-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparser.rs
111 lines (102 loc) · 3.16 KB
/
parser.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use darling::{
ast::{Data, Fields, Style},
util::Ignored,
FromDeriveInput, FromVariant,
};
use crate::from_impl::FromImpl;
/// A parsing context which houses information read from the input until it
/// can be used to construct the appropriate token stream.
///
/// The `Container` is the workhorse of the macro; it is responsible for traversing
/// the input to populate itself, and then generating a set of `FromImpl` objects
/// which are responsible for the eventual rendering of the conversion implementations.
#[derive(FromDeriveInput)]
#[darling(from_ident, attributes(from_variants), supports(enum_any))]
pub struct Container {
pub into: bool,
pub ident: syn::Ident,
generics: syn::Generics,
data: Data<Variant, Ignored>,
}
impl Container {
/// Generates a list of `From` implementations.
pub fn as_impls(&self) -> Vec<FromImpl<'_>> {
if let Some(variants) = self.data.as_ref().take_enum() {
variants
.into_iter()
.filter(|v| v.is_enabled())
.map(|item| FromImpl {
generics: &self.generics,
variant_ident: &item.ident,
variant_ty: item.ty().expect("Shape validation already took place"),
target_ident: &self.ident,
into: item.into.unwrap_or(self.into),
})
.collect()
} else {
panic!("FromVariants is not supported on structs");
}
}
}
impl From<syn::Ident> for Container {
fn from(ident: syn::Ident) -> Self {
Container {
ident,
into: false,
generics: Default::default(),
data: Data::Enum(vec![]),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, FromVariant)]
#[darling(from_ident, attributes(from_variants), and_then = "Self::validate")]
pub struct Variant {
ident: syn::Ident,
skip: Option<bool>,
into: Option<bool>,
fields: Fields<syn::Type>,
}
impl Variant {
fn validate(self) -> darling::Result<Self> {
if self.is_enabled() && !self.fields.is_newtype() {
let shape = if self.fields.is_tuple() {
"tuple"
} else if self.fields.is_struct() {
"struct"
} else if self.fields.is_unit() {
"unit"
} else {
"unknown"
};
Err(darling::Error::unsupported_shape(shape).with_span(&self.fields))
} else {
Ok(self)
}
}
/// Check if this variant will emit a converter.
pub fn is_enabled(&self) -> bool {
!(self.fields.is_unit() || self.skip.unwrap_or(false))
}
pub fn ty(&self) -> Option<&syn::Type> {
if let Fields {
style: Style::Tuple,
ref fields,
..
} = self.fields
{
fields.get(0)
} else {
None
}
}
}
impl From<syn::Ident> for Variant {
fn from(ident: syn::Ident) -> Self {
Variant {
ident,
skip: Default::default(),
into: Default::default(),
fields: Fields::new(Style::Unit, Vec::new()),
}
}
}