amplify_syn/
data.rs

1// Rust language amplification derive library providing multiple generic trait
2// implementations, type wrappers, derive macros and other language enhancements
3//
4// Written in 2019-2021 by
5//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
6//
7// To the extent possible under law, the author(s) have dedicated all
8// copyright and related and neighboring rights to this software to
9// the public domain worldwide. This software is distributed without
10// any warranty.
11//
12// You should have received a copy of the MIT License
13// along with this software.
14// If not, see <https://opensource.org/licenses/MIT>.
15
16// TODO: Write docs for `data` module
17#![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}