nix_compat_derive/internal/
mod.rs

1use syn::punctuated::Punctuated;
2use syn::spanned::Spanned;
3use syn::Token;
4
5pub mod attrs;
6mod ctx;
7pub mod inputs;
8mod symbol;
9
10pub use ctx::Context;
11
12pub struct Field<'a> {
13    pub member: syn::Member,
14    pub ty: &'a syn::Type,
15    pub attrs: attrs::Field,
16    pub original: &'a syn::Field,
17}
18
19impl<'a> Field<'a> {
20    pub fn from_ast(ctx: &Context, idx: usize, field: &'a syn::Field) -> Field<'a> {
21        let attrs = attrs::Field::from_ast(ctx, &field.attrs);
22        let member = match &field.ident {
23            Some(id) => syn::Member::Named(id.clone()),
24            None => syn::Member::Unnamed(idx.into()),
25        };
26        Field {
27            member,
28            attrs,
29            ty: &field.ty,
30            original: field,
31        }
32    }
33
34    pub fn var_ident(&self) -> syn::Ident {
35        match &self.member {
36            syn::Member::Named(name) => name.clone(),
37            syn::Member::Unnamed(idx) => {
38                syn::Ident::new(&format!("field{}", idx.index), self.original.span())
39            }
40        }
41    }
42}
43
44pub struct Variant<'a> {
45    pub ident: &'a syn::Ident,
46    pub attrs: attrs::Variant,
47    pub style: Style,
48    pub fields: Vec<Field<'a>>,
49    //pub original: &'a syn::Variant,
50}
51
52impl<'a> Variant<'a> {
53    pub fn from_ast(ctx: &Context, variant: &'a syn::Variant) -> Self {
54        let attrs = attrs::Variant::from_ast(ctx, &variant.attrs);
55        let (style, fields) = match &variant.fields {
56            syn::Fields::Named(fields) => (Style::Struct, fields_ast(ctx, &fields.named)),
57            syn::Fields::Unnamed(fields) => (Style::Tuple, fields_ast(ctx, &fields.unnamed)),
58            syn::Fields::Unit => (Style::Unit, Vec::new()),
59        };
60        Variant {
61            ident: &variant.ident,
62            attrs,
63            style,
64            fields,
65            //original: variant,
66        }
67    }
68}
69
70#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
71pub enum Style {
72    Struct,
73    Tuple,
74    Unit,
75}
76
77pub enum Data<'a> {
78    Enum(Vec<Variant<'a>>),
79    Struct(Style, Vec<Field<'a>>),
80}
81
82pub struct Container<'a> {
83    pub ident: &'a syn::Ident,
84    pub attrs: attrs::Container,
85    pub data: Data<'a>,
86    pub crate_path: syn::Path,
87    pub original: &'a syn::DeriveInput,
88}
89
90impl<'a> Container<'a> {
91    pub fn from_ast(
92        ctx: &Context,
93        crate_path: syn::Path,
94        input: &'a mut syn::DeriveInput,
95    ) -> Option<Container<'a>> {
96        let attrs = attrs::Container::from_ast(ctx, &input.attrs);
97        let data = match &input.data {
98            syn::Data::Struct(s) => match &s.fields {
99                syn::Fields::Named(fields) => {
100                    Data::Struct(Style::Struct, fields_ast(ctx, &fields.named))
101                }
102                syn::Fields::Unnamed(fields) => {
103                    Data::Struct(Style::Tuple, fields_ast(ctx, &fields.unnamed))
104                }
105                syn::Fields::Unit => Data::Struct(Style::Unit, Vec::new()),
106            },
107            syn::Data::Enum(e) => {
108                let variants = e
109                    .variants
110                    .iter()
111                    .map(|variant| Variant::from_ast(ctx, variant))
112                    .collect();
113                Data::Enum(variants)
114            }
115            syn::Data::Union(u) => {
116                ctx.error_spanned(u.union_token, "Union not supported by nix-compat");
117                return None;
118            }
119        };
120        Some(Container {
121            ident: &input.ident,
122            attrs,
123            data,
124            crate_path,
125            original: input,
126        })
127    }
128
129    pub fn crate_path(&self) -> &syn::Path {
130        if let Some(crate_path) = self.attrs.crate_path.as_ref() {
131            crate_path
132        } else {
133            &self.crate_path
134        }
135    }
136
137    pub fn ident_type(&self) -> syn::Type {
138        let path: syn::Path = self.ident.clone().into();
139        let tp = syn::TypePath { qself: None, path };
140        tp.into()
141    }
142}
143
144pub struct Remote<'a> {
145    pub attrs: attrs::Container,
146    pub ty: &'a syn::Type,
147    pub crate_path: syn::Path,
148}
149
150impl<'a> Remote<'a> {
151    pub fn from_ast(
152        ctx: &Context,
153        crate_path: syn::Path,
154        input: &'a inputs::RemoteInput,
155    ) -> Option<Remote<'a>> {
156        let attrs = attrs::Container::from_ast(ctx, &input.attrs);
157        Some(Remote {
158            ty: &input.ident,
159            attrs,
160            crate_path,
161        })
162    }
163
164    pub fn crate_path(&self) -> &syn::Path {
165        if let Some(crate_path) = self.attrs.crate_path.as_ref() {
166            crate_path
167        } else {
168            &self.crate_path
169        }
170    }
171}
172
173fn fields_ast<'a>(ctx: &Context, fields: &'a Punctuated<syn::Field, Token![,]>) -> Vec<Field<'a>> {
174    fields
175        .iter()
176        .enumerate()
177        .map(|(idx, field)| Field::from_ast(ctx, idx, field))
178        .collect()
179}