1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use crate::util::kw;
6 use proc_macro2::TokenStream;
7 use quote::{quote, ToTokens};
8 use syn::{
9     bracketed, parenthesized,
10     parse::{Nothing, Parse, ParseStream},
11     token::{Bracket, Paren},
12     Lit,
13 };
14 
15 /// Default value
16 #[derive(Clone)]
17 pub enum DefaultValue {
18     Literal(Lit),
19     None(kw::None),
20     Some {
21         some: kw::Some,
22         paren: Paren,
23         inner: Box<DefaultValue>,
24     },
25     EmptySeq(Bracket),
26 }
27 
28 impl ToTokens for DefaultValue {
to_tokens(&self, tokens: &mut TokenStream)29     fn to_tokens(&self, tokens: &mut TokenStream) {
30         match self {
31             DefaultValue::Literal(lit) => lit.to_tokens(tokens),
32             DefaultValue::None(kw) => kw.to_tokens(tokens),
33             DefaultValue::Some { inner, .. } => tokens.extend(quote! { Some(#inner) }),
34             DefaultValue::EmptySeq(_) => tokens.extend(quote! { [] }),
35         }
36     }
37 }
38 
39 impl Parse for DefaultValue {
parse(input: ParseStream<'_>) -> syn::Result<Self>40     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
41         let lookahead = input.lookahead1();
42         if lookahead.peek(kw::None) {
43             let none_kw: kw::None = input.parse()?;
44             Ok(Self::None(none_kw))
45         } else if lookahead.peek(kw::Some) {
46             let some: kw::Some = input.parse()?;
47             let content;
48             let paren = parenthesized!(content in input);
49             Ok(Self::Some {
50                 some,
51                 paren,
52                 inner: content.parse()?,
53             })
54         } else if lookahead.peek(Bracket) {
55             let content;
56             let bracket = bracketed!(content in input);
57             content.parse::<Nothing>()?;
58             Ok(Self::EmptySeq(bracket))
59         } else {
60             Ok(Self::Literal(input.parse()?))
61         }
62     }
63 }
64 
65 impl DefaultValue {
metadata_calls(&self) -> syn::Result<TokenStream>66     fn metadata_calls(&self) -> syn::Result<TokenStream> {
67         match self {
68             DefaultValue::Literal(Lit::Int(i)) if !i.suffix().is_empty() => Err(
69                 syn::Error::new_spanned(i, "integer literals with suffix not supported here"),
70             ),
71             DefaultValue::Literal(Lit::Float(f)) if !f.suffix().is_empty() => Err(
72                 syn::Error::new_spanned(f, "float literals with suffix not supported here"),
73             ),
74 
75             DefaultValue::Literal(Lit::Str(s)) => Ok(quote! {
76                 .concat_value(::uniffi::metadata::codes::LIT_STR)
77                 .concat_str(#s)
78             }),
79             DefaultValue::Literal(Lit::Int(i)) => {
80                 let digits = i.base10_digits();
81                 Ok(quote! {
82                     .concat_value(::uniffi::metadata::codes::LIT_INT)
83                     .concat_str(#digits)
84                 })
85             }
86             DefaultValue::Literal(Lit::Float(f)) => {
87                 let digits = f.base10_digits();
88                 Ok(quote! {
89                     .concat_value(::uniffi::metadata::codes::LIT_FLOAT)
90                     .concat_str(#digits)
91                 })
92             }
93             DefaultValue::Literal(Lit::Bool(b)) => Ok(quote! {
94                 .concat_value(::uniffi::metadata::codes::LIT_BOOL)
95                 .concat_bool(#b)
96             }),
97 
98             DefaultValue::Literal(_) => Err(syn::Error::new_spanned(
99                 self,
100                 "this type of literal is not currently supported as a default",
101             )),
102 
103             DefaultValue::EmptySeq(_) => Ok(quote! {
104                 .concat_value(::uniffi::metadata::codes::LIT_EMPTY_SEQ)
105             }),
106 
107             DefaultValue::None(_) => Ok(quote! {
108                 .concat_value(::uniffi::metadata::codes::LIT_NONE)
109             }),
110 
111             DefaultValue::Some { inner, .. } => {
112                 let inner_calls = inner.metadata_calls()?;
113                 Ok(quote! {
114                     .concat_value(::uniffi::metadata::codes::LIT_SOME)
115                     #inner_calls
116                 })
117             }
118         }
119     }
120 }
121 
default_value_metadata_calls(default: &Option<DefaultValue>) -> syn::Result<TokenStream>122 pub fn default_value_metadata_calls(default: &Option<DefaultValue>) -> syn::Result<TokenStream> {
123     Ok(match default {
124         Some(default) => {
125             let metadata_calls = default.metadata_calls()?;
126             quote! {
127                 .concat_bool(true)
128                 #metadata_calls
129             }
130         }
131         None => quote! { .concat_bool(false) },
132     })
133 }
134