1#![allow(missing_docs)]
18
19use std::ops::{Deref, DerefMut};
20use std::slice;
21
22use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
23use quote::ToTokens;
24use syn::{DeriveInput, Generics, Path};
25
26use crate::{ident, ParametrizedAttr};
27
28#[derive(Clone)]
29pub struct DataType {
30 pub generics: Generics,
31 pub name: Ident,
32 pub attr: ParametrizedAttr,
33 pub inner: DataInner,
34}
35
36#[derive(Clone)]
37pub enum DataInner {
38 Uninhabited,
39 Struct(Fields),
40 Enum(Items<Variant>),
41 Union(Items<NamedField>),
42}
43
44#[derive(Clone)]
45pub enum Fields {
46 Unit,
47 Named(Items<NamedField>),
48 Unnamed(Items<Field>),
49}
50
51#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
52pub enum FieldKind {
53 Named,
54 Unnamed,
55}
56
57#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
58pub enum EnumKind {
59 Primitive,
60 Associated,
61}
62
63impl Fields {
64 pub fn is_unit(&self) -> bool { matches!(self, Fields::Unit) }
65
66 pub fn kind(&self) -> FieldKind {
67 match self {
68 Fields::Unit => FieldKind::Unnamed,
69 Fields::Named(_) => FieldKind::Named,
70 Fields::Unnamed(_) => FieldKind::Unnamed,
71 }
72 }
73}
74
75pub trait Element: Sized {
76 type Input: Sized;
77 fn with(input: Self::Input, attr_name: &Ident) -> syn::Result<Self>;
78}
79
80#[derive(Clone)]
81pub struct Items<E: Element>(Vec<E>);
82
83impl<E: Element> Deref for Items<E> {
84 type Target = Vec<E>;
85 fn deref(&self) -> &Self::Target { &self.0 }
86}
87
88impl<E: Element> DerefMut for Items<E> {
89 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
90}
91
92impl<'a, E: Element> IntoIterator for &'a Items<E> {
93 type Item = &'a E;
94 type IntoIter = slice::Iter<'a, E>;
95
96 fn into_iter(self) -> Self::IntoIter { self.0.iter() }
97}
98
99impl Items<Variant> {
100 pub fn enum_kind(&self) -> EnumKind {
101 if self.iter().all(|var| var.fields.is_unit()) {
102 EnumKind::Primitive
103 } else {
104 EnumKind::Associated
105 }
106 }
107}
108
109#[derive(Clone)]
110pub struct NamedField {
111 pub name: Ident,
112 pub field: Field,
113}
114
115#[derive(Clone)]
116pub struct Field {
117 pub vis: Vis,
118 pub attr: ParametrizedAttr,
119 pub ty: syn::Type,
120}
121
122#[derive(Clone)]
123pub struct Variant {
124 pub attr: ParametrizedAttr,
125 pub name: Ident,
126 pub fields: Fields,
127}
128
129#[derive(Clone)]
130pub enum Vis {
131 Public,
132 Scoped(Scope),
133 Inherited,
134}
135
136#[derive(Clone)]
137pub enum Scope {
138 Crate,
139 Super,
140 Path(Path),
141}
142
143impl DataType {
144 pub fn with(input: DeriveInput, attr_name: Ident) -> syn::Result<Self> {
145 let attr = ParametrizedAttr::with(attr_name.to_string(), input.attrs.as_ref())?;
146 Ok(DataType {
147 generics: input.generics,
148 name: input.ident,
149 attr,
150 inner: DataInner::with(input.data, &attr_name)?,
151 })
152 }
153}
154
155impl DataInner {
156 pub fn with(data: syn::Data, attr_name: &Ident) -> syn::Result<Self> {
157 match data {
158 syn::Data::Struct(inner) => {
159 Fields::with(inner.fields, attr_name).map(DataInner::Struct)
160 }
161 syn::Data::Enum(inner) if inner.variants.is_empty() => Ok(DataInner::Uninhabited),
162 syn::Data::Enum(inner) => {
163 Items::with(inner.variants.into_iter(), attr_name).map(DataInner::Enum)
164 }
165 syn::Data::Union(inner) => {
166 Items::with(inner.fields.named.into_iter(), attr_name).map(DataInner::Union)
167 }
168 }
169 }
170}
171
172impl Fields {
173 pub fn with(fields: syn::Fields, attr_name: &Ident) -> syn::Result<Self> {
174 match fields {
175 syn::Fields::Named(fields) => {
176 Items::with(fields.named.into_iter(), attr_name).map(Fields::Named)
177 }
178 syn::Fields::Unnamed(fields) => {
179 Items::with(fields.unnamed.into_iter(), attr_name).map(Fields::Unnamed)
180 }
181 syn::Fields::Unit => Ok(Fields::Unit),
182 }
183 }
184}
185
186impl<E: Element> Items<E> {
187 pub fn with(
188 items: impl ExactSizeIterator<Item = E::Input>,
189 attr_name: &Ident,
190 ) -> syn::Result<Self> {
191 let mut list = Vec::with_capacity(items.len());
192 for el in items {
193 list.push(E::with(el, attr_name)?)
194 }
195 Ok(Items(list))
196 }
197}
198
199impl Element for NamedField {
200 type Input = syn::Field;
201
202 fn with(input: Self::Input, attr_name: &Ident) -> syn::Result<Self> {
203 Ok(NamedField {
204 name: input.ident.clone().expect("named field without a name"),
205 field: Field::with(input, attr_name)?,
206 })
207 }
208}
209impl Element for Field {
210 type Input = syn::Field;
211
212 fn with(input: Self::Input, attr_name: &Ident) -> syn::Result<Self> {
213 let attr = ParametrizedAttr::with(attr_name.to_string(), input.attrs.as_ref())?;
214 Ok(Field {
215 vis: input.vis.into(),
216 attr,
217 ty: input.ty,
218 })
219 }
220}
221
222impl Element for Variant {
223 type Input = syn::Variant;
224
225 fn with(input: Self::Input, attr_name: &Ident) -> syn::Result<Self> {
226 let attr = ParametrizedAttr::with(attr_name.to_string(), input.attrs.as_ref())?;
227 Ok(Variant {
228 attr,
229 name: input.ident,
230 fields: Fields::with(input.fields, attr_name)?,
231 })
232 }
233}
234
235impl From<syn::Visibility> for Vis {
236 fn from(vis: syn::Visibility) -> Self {
237 match vis {
238 syn::Visibility::Public(_) => Vis::Public,
239 syn::Visibility::Crate(_) => Vis::Scoped(Scope::Crate),
240 syn::Visibility::Restricted(scope) => Vis::Scoped(scope.into()),
241 syn::Visibility::Inherited => Vis::Inherited,
242 }
243 }
244}
245
246impl From<syn::VisRestricted> for Scope {
247 fn from(scope: syn::VisRestricted) -> Self {
248 if scope.in_token.is_none() {
249 debug_assert_eq!(scope.path.get_ident().unwrap(), &ident!(super));
250 Scope::Super
251 } else {
252 Scope::Path(*scope.path)
253 }
254 }
255}
256
257impl DataType {
258 pub fn derive<D: DeriveInner>(
259 &self,
260 trait_crate: &Path,
261 trait_name: &Ident,
262 attr: &D,
263 ) -> syn::Result<TokenStream2> {
264 let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
265
266 let ident_name = &self.name;
267
268 let inner = match &self.inner {
269 DataInner::Struct(Fields::Unit) => attr.derive_unit_inner(),
270 DataInner::Struct(Fields::Unnamed(fields)) => attr.derive_tuple_inner(fields),
271 DataInner::Struct(Fields::Named(fields)) => attr.derive_struct_inner(fields),
272 DataInner::Enum(variants) => attr.derive_enum_inner(variants),
273 DataInner::Union(_) => Err(syn::Error::new(
274 Span::call_site(),
275 format!(
276 "deriving `{}` is not supported in unions",
277 trait_name.to_token_stream().to_string()
278 ),
279 )),
280 DataInner::Uninhabited => Err(syn::Error::new(
281 Span::call_site(),
282 format!(
283 "deriving `{}` is not supported for uninhabited enums",
284 trait_name.to_token_stream().to_string()
285 ),
286 )),
287 }?;
288
289 let tokens = quote! {
290 #[automatically_derived]
291 impl #impl_generics #trait_crate::#trait_name for #ident_name #ty_generics #where_clause {
292 #inner
293 }
294 };
295
296 Ok(tokens)
297 }
298}
299
300pub trait DeriveInner {
301 fn derive_unit_inner(&self) -> syn::Result<TokenStream2>;
302 fn derive_struct_inner(&self, fields: &Items<NamedField>) -> syn::Result<TokenStream2>;
303 fn derive_tuple_inner(&self, fields: &Items<Field>) -> syn::Result<TokenStream2>;
304 fn derive_enum_inner(&self, fields: &Items<Variant>) -> syn::Result<TokenStream2>;
305}