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()),
        }
    }
}