macro_input_core/
value.rs

1use crate::{Type, Types};
2use proc_macro2::{Span, TokenStream};
3use quote::{quote, ToTokens};
4use syn::{parse_quote, Error, Lit, LitByteStr, Result};
5
6#[derive(Clone)]
7/// a default value for a [`Def`](crate::Def)
8pub enum DefaultValue {
9    /// any literal
10    Any(Option<Lit>),
11    /// a flag that doesn't have a value eg `#[my_input(enabled)]`
12    Flag,
13    /// a string
14    Str(Option<&'static str>),
15    /// a string
16    String(Option<String>),
17    /// a bytestring
18    ByteStr(Option<&'static [u8]>),
19    /// a bytestring
20    ByteString(Option<Vec<u8>>),
21    /// a u8
22    Byte(Option<u8>),
23    /// a char
24    Char(Option<char>),
25    /// a i32
26    I32(Option<i32>),
27    /// a f32
28    F32(Option<f32>),
29    /// a bool
30    Bool(Option<bool>),
31    /// a list of idents (default not supported)
32    Idents,
33}
34
35impl DefaultValue {
36    /// construct a `DefaultValue` from a type and a literal
37    /// # Errors
38    /// may return an error if the literal is not compatible with the type
39    pub fn from_lit(ty: Type, lit: Option<Lit>) -> Result<DefaultValue> {
40        match ty.ty {
41            Types::Any => Ok(DefaultValue::Any(lit)),
42            Types::Flag => Ok(DefaultValue::Flag),
43            Types::Str => lit
44                .map(|lit| {
45                    if let Lit::Str(v) = lit {
46                        Ok(v.value())
47                    } else {
48                        Err(Error::new(lit.span(), "expected string"))
49                    }
50                })
51                .transpose()
52                .map(DefaultValue::String),
53            Types::ByteStr => lit
54                .map(|lit| {
55                    if let Lit::ByteStr(v) = lit {
56                        Ok(v.value())
57                    } else {
58                        Err(Error::new(lit.span(), "expected bytes"))
59                    }
60                })
61                .transpose()
62                .map(DefaultValue::ByteString),
63            Types::Byte => lit
64                .map(|lit| {
65                    if let Lit::Byte(v) = lit {
66                        Ok(v.value())
67                    } else {
68                        Err(Error::new(lit.span(), "expected byte"))
69                    }
70                })
71                .transpose()
72                .map(DefaultValue::Byte),
73            Types::Char => lit
74                .map(|lit| {
75                    if let Lit::Char(v) = lit {
76                        Ok(v.value())
77                    } else {
78                        Err(Error::new(lit.span(), "expected char"))
79                    }
80                })
81                .transpose()
82                .map(DefaultValue::Char),
83            Types::I32 => lit
84                .map(|lit| {
85                    if let Lit::Int(v) = lit {
86                        v.base10_parse()
87                    } else {
88                        Err(Error::new(lit.span(), "expected i32"))
89                    }
90                })
91                .transpose()
92                .map(DefaultValue::I32),
93            Types::F32 => lit
94                .map(|lit| {
95                    if let Lit::Int(v) = lit {
96                        v.base10_parse()
97                    } else {
98                        Err(Error::new(lit.span(), "expected f32"))
99                    }
100                })
101                .transpose()
102                .map(DefaultValue::F32),
103            Types::Bool => lit
104                .map(|lit| {
105                    if let Lit::Bool(v) = lit {
106                        Ok(v.value)
107                    } else {
108                        Err(Error::new(lit.span(), "expected bool"))
109                    }
110                })
111                .transpose()
112                .map(DefaultValue::Bool),
113            Types::Idents => lit.map_or_else(
114                || Ok(DefaultValue::Idents),
115                |lit| {
116                    Err(Error::new(
117                        lit.span(),
118                        "default values are not supported for idents",
119                    ))
120                },
121            ),
122        }
123    }
124
125    /// get the type of the value
126    #[must_use]
127    pub fn ty(&self, optional: bool) -> Type {
128        Type {
129            ty: Types::from(self),
130            optional,
131        }
132    }
133
134    /// checks whether the value is a default value
135    #[must_use]
136    pub fn has_default_data(&self) -> bool {
137        match self {
138            DefaultValue::Any(val) => val.is_some(),
139            DefaultValue::Flag | DefaultValue::Idents => false,
140            DefaultValue::Str(val) => val.is_some(),
141            DefaultValue::String(val) => val.is_some(),
142            DefaultValue::ByteStr(val) => val.is_some(),
143            DefaultValue::ByteString(val) => val.is_some(),
144            DefaultValue::Byte(val) => val.is_some(),
145            DefaultValue::Char(val) => val.is_some(),
146            DefaultValue::I32(val) => val.is_some(),
147            DefaultValue::F32(val) => val.is_some(),
148            DefaultValue::Bool(val) => val.is_some(),
149        }
150    }
151
152    pub(crate) fn as_lit(&self) -> Option<Lit> {
153        match self {
154            DefaultValue::Flag | DefaultValue::Idents => None,
155            DefaultValue::Any(val) => val.clone(),
156            DefaultValue::Str(val) => val.map(|v| parse_quote!(#v)),
157            DefaultValue::String(val) => val.as_ref().map(|v| parse_quote!(#v)),
158            DefaultValue::ByteStr(val) => val.map(|v| {
159                let lbs = LitByteStr::new(&v, Span::call_site());
160                parse_quote!(#lbs)
161            }),
162            DefaultValue::ByteString(val) => val.as_ref().map(|v| {
163                let lbs = LitByteStr::new(&v, Span::call_site());
164                parse_quote!(#lbs)
165            }),
166            DefaultValue::Byte(val) => val.map(|v| parse_quote!(#v)),
167            DefaultValue::Char(val) => val.map(|v| parse_quote!(#v)),
168            DefaultValue::I32(val) => val.map(|v| parse_quote!(#v)),
169            DefaultValue::F32(val) => val.map(|v| parse_quote!(#v)),
170            DefaultValue::Bool(val) => val.map(|v| parse_quote!(#v)),
171        }
172    }
173}
174
175impl From<DefaultValue> for Option<Lit> {
176    fn from(val: DefaultValue) -> Self {
177        match val {
178            DefaultValue::Flag | DefaultValue::Idents => None,
179            DefaultValue::Any(val) => val,
180            DefaultValue::Str(val) => val.map(|v| parse_quote!(#v)),
181            DefaultValue::String(val) => val.map(|v| parse_quote!(#v)),
182            DefaultValue::ByteStr(val) => val.map(|v| {
183                let lbs = LitByteStr::new(&v, Span::call_site());
184                parse_quote!(#lbs)
185            }),
186            DefaultValue::ByteString(val) => val.map(|v| {
187                let lbs = LitByteStr::new(&v, Span::call_site());
188                parse_quote!(#lbs)
189            }),
190            DefaultValue::Byte(val) => val.map(|v| parse_quote!(#v)),
191            DefaultValue::Char(val) => val.map(|v| parse_quote!(#v)),
192            DefaultValue::I32(val) => val.map(|v| parse_quote!(#v)),
193            DefaultValue::F32(val) => val.map(|v| parse_quote!(#v)),
194            DefaultValue::Bool(val) => val.map(|v| parse_quote!(#v)),
195        }
196    }
197}
198
199impl From<&DefaultValue> for Types {
200    fn from(value: &DefaultValue) -> Self {
201        match value {
202            DefaultValue::Any(_) => Types::Any,
203            DefaultValue::Flag => Types::Flag,
204            DefaultValue::Str(_) | DefaultValue::String(_) => Types::Str,
205            DefaultValue::ByteStr(_) | DefaultValue::ByteString(_) => Types::ByteStr,
206            DefaultValue::Byte(_) => Types::Byte,
207            DefaultValue::Char(_) => Types::Char,
208            DefaultValue::I32(_) => Types::I32,
209            DefaultValue::F32(_) => Types::F32,
210            DefaultValue::Bool(_) => Types::Bool,
211            DefaultValue::Idents => Types::Idents,
212        }
213    }
214}
215
216impl ToTokens for DefaultValue {
217    fn to_tokens(&self, tokens: &mut TokenStream) {
218        fn map_literal<V: ToTokens>(v: &Option<V>) -> TokenStream {
219            if let Some(data) = v {
220                quote!(::core::option::Option::Some(#data))
221            } else {
222                quote!(::core::option::Option::None)
223            }
224        }
225
226        let tts = match self {
227            DefaultValue::Any(v) => {
228                let data = map_literal(v);
229                quote!(::macro_input::DefaultValue::Any(#data))
230            }
231            DefaultValue::Flag => quote!(::macro_input::DefaultValue::Flag),
232            DefaultValue::Str(v) => {
233                let data = map_literal(v);
234                quote!(::macro_input::DefaultValue::Str(#data))
235            }
236            DefaultValue::String(v) => {
237                let data = map_literal(v);
238                quote!(::macro_input::DefaultValue::Str(#data))
239            }
240            DefaultValue::ByteStr(v) => {
241                let data = map_literal(&v.as_ref().map(|v| LitByteStr::new(v, Span::call_site())));
242                quote!(::macro_input::DefaultValue::ByteStr(#data))
243            }
244            DefaultValue::ByteString(v) => {
245                let data = map_literal(&v.as_ref().map(|v| LitByteStr::new(v, Span::call_site())));
246                quote!(::macro_input::DefaultValue::ByteStr(#data))
247            }
248            DefaultValue::Byte(v) => {
249                let data = map_literal(v);
250                quote!(::macro_input::DefaultValue::Byte(#data))
251            }
252            DefaultValue::Char(v) => {
253                let data = map_literal(v);
254                quote!(::macro_input::DefaultValue::Char(#data))
255            }
256            DefaultValue::I32(v) => {
257                let data = map_literal(v);
258                quote!(::macro_input::DefaultValue::I32(#data))
259            }
260            DefaultValue::F32(v) => {
261                let data = map_literal(v);
262                quote!(::macro_input::DefaultValue::F32(#data))
263            }
264            DefaultValue::Bool(v) => {
265                let data = map_literal(v);
266                quote!(::macro_input::DefaultValue::Bool(#data))
267            }
268            DefaultValue::Idents => {
269                quote!(::macro_input::DefaultValue::Idents)
270            }
271        };
272        tokens.extend(tts);
273    }
274}