nix_compat_derive/internal/
mod.rs1use 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 }
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 }
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}