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)]
7pub enum DefaultValue {
9 Any(Option<Lit>),
11 Flag,
13 Str(Option<&'static str>),
15 String(Option<String>),
17 ByteStr(Option<&'static [u8]>),
19 ByteString(Option<Vec<u8>>),
21 Byte(Option<u8>),
23 Char(Option<char>),
25 I32(Option<i32>),
27 F32(Option<f32>),
29 Bool(Option<bool>),
31 Idents,
33}
34
35impl DefaultValue {
36 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 #[must_use]
127 pub fn ty(&self, optional: bool) -> Type {
128 Type {
129 ty: Types::from(self),
130 optional,
131 }
132 }
133
134 #[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}