1use std::{str::FromStr, fmt::Display};
2
3use proc_macro2::Span;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7pub enum ErrorMsg {
8 #[error("Failed to Parse Attribute: expected list of key/value pairs EX) ATTR_NAME(x = 1) and/or booleans EX) ATTR_NAME(is_x)")]
9 FailedToParseAttr,
10
11 #[error("Invalid Item: expected struct")]
12 InvalidItem,
13
14 #[error("Missing Attribute: attribute '{0}' is required")]
15 MissingAttribute(&'static str),
16
17 #[error("Missing Argument: '{0}' is required")]
18 MissingArg(&'static str),
19 #[error("Invalid Type: expected {expected}")]
20 InvalidType{expected: &'static str},
21 #[error("Duplicate Argument")]
22 DuplicateArg,
23 #[error("Invalid Argument")]
24 InvalidArg,
25}
26use ErrorMsg::*;
27
28
29#[derive(Debug)]
30pub struct Error {
31 pub msg: ErrorMsg,
32 pub location: Span,
33}
34impl Error {
35 pub fn new(location: Span, msg: ErrorMsg) -> Self {
36 Self {
37 location,
38 msg
39 }
40 }
41}
42
43pub trait Concat: Sized {
45 const NO_DUPLICATES: bool = true;
49
50 fn concat(&mut self, other: Self) { *self = other }
52}
53impl<T: Concat> Concat for ArgResult<T> {
54 fn concat(&mut self, other: Self) {
55 let mut other = other;
56 if other.is_found() {
57 self.location = other.location;
58 if self.is_found() && T::NO_DUPLICATES {
59 self.add_error(DuplicateArg);
60 }
61 }
62 if other.found_with_errors() {
63 self.errors.append(&mut other.errors)
64 }
65 if other.found_with_value() {
66 match self.value {
67 Some(ref mut value) => {
68 match other.value {
69 Some(other_value) => {
70 value.concat(other_value);
71 },
72 None => {}
73 }
74
75 }
76 None => self.value = other.value
77 }
78 }
79 }
80}
81
82
83
84
85#[derive(Debug)]
87pub struct ArgResult<T> {
88 pub value: Option<T>,
89 pub errors: Vec<Error>,
90 pub location: Span,
91}
92impl<T> ArgResult<T> {
93 pub fn new(location: Span) -> Self {
94 Self {
95 value: None,
96 errors: vec![],
97 location,
98 }
99 }
100 pub fn add_error(&mut self, msg: ErrorMsg) {
102 self.errors.push(Error::new(self.location, msg));
103 }
104
105 pub fn add_value(&mut self, value: T) {
107 self.value = Some(value);
108 }
109
110 pub fn add_result(&mut self, value: Result<T, ErrorMsg>) {
112 match value {
113 Ok(value) => self.add_value(value),
114 Err(error) => self.add_error(error)
115 }
116 }
117
118 pub fn is_found(&self) -> bool { self.errors.len() > 0 || self.value.is_some() }
119 pub fn found_with_errors(&self) -> bool { self.errors.len() > 0 }
120 pub fn found_with_value(&self) -> bool { self.value.is_some() }
121}
122
123
124pub trait SynVersion: Sized {
126 type Attribute: GetSpan;
128
129 fn deserialize_attr_args(attr: &Self::Attribute) -> Option<Vec<Self::ArgMeta>>;
131 fn deserialize_list_args(meta: &Self::ArgMeta) -> Option<Vec<Self::ArgMeta>>;
133
134 type ArgMeta: GetSpan;
136
137 fn deserialize_key(meta: &Self::ArgMeta) -> Option<String>;
139
140 fn deserialize_attr_key(meta: &Self::Attribute) -> Option<String>;
142
143 fn deserialize_integer<T>(meta: &Self::ArgMeta) -> Option<T> where T: FromStr, T::Err: Display;
145
146 fn deserialize_float<T>(meta: &Self::ArgMeta) -> Option<T> where T: FromStr, T::Err: Display;
148
149 fn deserialize_string(meta: &Self::ArgMeta) -> Option<String>;
151
152 fn deserialize_bool(meta: &Self::ArgMeta) -> Option<bool>;
154
155 fn deserialize_array(meta: &Self::ArgMeta) -> Option<Vec<Self::ArgMeta>>;
157
158 type Error;
160
161 fn convert_error(error: Error) -> Self::Error;
163}
164
165pub trait GetSpan {
167 fn get_span(&self) -> Span;
168}
169
170
171pub trait TryFromMeta<V: SynVersion>: Sized {
174 type InitialType: Concat;
177
178 type Metadata;
180 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType>;
184 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>>;
188}
189
190pub fn required_validation<A, B: From<A>>(state: ArgResult<A>, arg_name: &'static str) -> Result<B, Vec<Error>> {
192 let mut state = state;
193 match state.found_with_errors() {
194 true => Err(state.errors),
195 false if state.value.is_none() => {
196 state.add_error(MissingArg(arg_name));
197 Err(state.errors)
198 }
199 false => Ok(state.value.unwrap().into())
200 }
201}
202
203impl Concat for String {}
204impl<V: SynVersion> TryFromMeta<V> for String {
205 type InitialType = Self;
206
207 type Metadata = V::ArgMeta;
208 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self> {
209 let mut result = ArgResult::new(meta.get_span());
210
211 let maybe_string = V::deserialize_string(&meta);
212
213 match maybe_string {
214 Some(string) => result.add_value(string),
215 None => result.add_error(InvalidType { expected: "string" })
216 }
217
218 result
219 }
220
221 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
222 required_validation(state, arg_name)
223 }
224}
225
226
227impl Concat for bool {}
228impl<V: SynVersion> TryFromMeta<V> for bool {
229 type InitialType = Self;
230
231 type Metadata = V::ArgMeta;
232 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType> {
233 let mut result = ArgResult::new(meta.get_span());
234
235 let maybe_bool = V::deserialize_bool(&meta);
236
237 match maybe_bool {
238 Some(value) => result.add_value(value),
239 None => result.add_error(InvalidType { expected: "boolean" })
240 }
241
242 result
243 }
244
245 fn validate(state: ArgResult<Self::InitialType>, _arg_name: &'static str) -> Result<Self, Vec<Error>> {
246 match state.found_with_errors() {
247 true => Err(state.errors),
248 false if state.value.is_none() => Ok(false),
249 false => Ok(state.value.unwrap())
250 }
251 }
252}
253
254impl<T: Concat> Concat for Vec<T> {
255 const NO_DUPLICATES: bool = false;
256 fn concat(&mut self, other: Self) {
257 let mut other = other;
258 self.append(&mut other);
259 }
260}
261impl<V: SynVersion, T: TryFromMeta<V, Metadata = V::ArgMeta>> TryFromMeta<V> for Vec<T> {
262 type InitialType = Vec<ArgResult<T::InitialType>>;
263 type Metadata = V::ArgMeta;
264
265 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType> {
266 let mut result = ArgResult::new(meta.get_span());
267 let array =
268 match V::deserialize_array(&meta) {
269 Some(array) => array,
270 None => {
271 result.add_error(InvalidType { expected: "array" });
272 return result;
273 }
274 };
275
276 let mut values = vec![];
277 for meta in array {
278 let element = T::try_from_meta(meta);
279 values.push(element);
280 }
281
282 result.add_value(values);
283
284 result
285 }
286
287 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
288 let mut state = state;
289
290 let values =
291 match state.found_with_errors() {
292 true => return Err(state.errors),
293 false if state.value.is_none() => {
294 state.add_error(MissingArg(arg_name));
295 return Err(state.errors);
296 },
297 false => state.value.unwrap()
298 };
299
300 let mut y = vec![];
301 for element in values {
302 let x =
303 match T::validate(element, arg_name) {
304 Ok(val) => val,
305 Err(ref mut errors) => {
306 state.errors.append(errors);
307 continue;
308 }
309 };
310
311 y.push(x);
312 }
313
314 match state.errors.len() {
315 0 => Ok(y),
316 _ => Err(state.errors)
317 }
318 }
319}
320
321
322impl<V: SynVersion, T: TryFromMeta<V>> TryFromMeta<V> for Option<T> {
323 type InitialType = T::InitialType;
324
325 type Metadata = T::Metadata;
326 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType> {
327 T::try_from_meta(meta)
328 }
329
330 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
331 match state.value {
332 Some(_) => Ok(Some(T::validate(state, arg_name)?)),
333 None if state.found_with_errors() => Err(state.errors),
334 None => Ok(None)
335 }
336 }
337}
338
339
340pub trait AttributeName {
341 const NAME: &'static str;
342}
343
344impl<T: AttributeName> AttributeName for Option<T> {
345 const NAME: &'static str = T::NAME;
346}
347
348impl<V: SynVersion, T: Attribute<V>> Attribute<V> for Option<T>
349where
350 Self: TryFromMeta<V, Metadata = V::Attribute>
351{}
352
353
354
355pub trait Attribute<V: SynVersion>: AttributeName + TryFromMeta<V, Metadata = V::Attribute> {
357 fn from_attrs(location: Span, attrs: Vec<V::Attribute>) -> Result<Self, Vec<V::Error>> {
359 let mut result = ArgResult::new(location);
360
361 for attr in attrs {
362 let maybe_key = V::deserialize_attr_key(&attr);
363 let found_attribute = matches!(maybe_key, Some(key) if key == Self::NAME);
364 if found_attribute == false { continue; }
365
366
367 let attr = Self::try_from_meta(attr);
368 result.concat(attr);
369 }
370
371 let maybe_attr = <Self as TryFromMeta<V>>::validate(result, Self::NAME);
372
373 maybe_attr.map_err(|e| e.into_iter().map(|e| V::convert_error(e)).collect())
374 }
375}
376
377
378pub trait CustomArgFromMeta<V: SynVersion>: Sized {
380 fn try_from_meta(meta: V::ArgMeta) -> Result<Self, ErrorMsg>;
381}
382
383#[derive(Debug)]
385pub struct CustomArg<T>(pub T);
386impl<V: SynVersion, T: CustomArgFromMeta<V>> TryFromMeta<V> for CustomArg<T> {
387 type InitialType = Self;
388 type Metadata = V::ArgMeta;
389
390 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType> {
391 let mut result = ArgResult::new(meta.get_span());
392 let x = <T as CustomArgFromMeta<V>>::try_from_meta(meta);
393
394 result.add_result(x);
395
396 let v = result.value.map(|v| Self(v));
397 ArgResult { value: v, errors: result.errors, location: result.location }
398
399
400 }
401
402 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
403 required_validation(state, arg_name)
404 }
405}
406impl<T> Concat for CustomArg<T> {}
407impl<T: Default> Default for CustomArg<T> {
408 fn default() -> Self { Self(T::default()) }
409}
410
411
412
413
414macro_rules! impl_integer {
415 ($($type_name: ident), *) => {
416 $(
417 impl Concat for $type_name {}
418 impl<V: SynVersion> TryFromMeta<V> for $type_name {
419 type InitialType = Self;
420 type Metadata = V::ArgMeta;
421 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType> {
422 let mut result = ArgResult::new(meta.get_span());
423
424 let maybe_int = V::deserialize_integer(&meta);
425
426 match maybe_int {
427 Some(value) => result.add_value(value),
428 None => result.add_error(InvalidType { expected: stringify!($type_name) })
429 }
430
431 result
432 }
433
434 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
435 required_validation(state, arg_name)
436 }
437 }
438
439 )*
440 };
441}
442macro_rules! impl_float {
443 ($($type_name: ident), *) => {
444 $(
445 impl Concat for $type_name {}
446 impl<V: SynVersion> TryFromMeta<V> for $type_name {
447 type InitialType = Self;
448 type Metadata = V::ArgMeta;
449 fn try_from_meta(meta: Self::Metadata) -> ArgResult<Self::InitialType> {
450 let mut result = ArgResult::new(meta.get_span());
451
452 let maybe_int = V::deserialize_integer(&meta);
453
454 match maybe_int {
455 Some(value) => result.add_value(value),
456 None => result.add_error(InvalidType { expected: stringify!($type_name) })
457 }
458
459 result
460 }
461
462 fn validate(state: ArgResult<Self::InitialType>, arg_name: &'static str) -> Result<Self, Vec<Error>> {
463 required_validation(state, arg_name)
464 }
465 }
466 )*
467 };
468}
469
470impl_integer!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
471impl_float!(f32, f64);