synthez_core/
ext.rs

1//! Extensions for [`syn`] types.
2
3use proc_macro2::Span;
4use sealed::sealed;
5use syn::{punctuated::Punctuated, token};
6
7/// Extension of a [`syn::Data`].
8#[sealed]
9pub trait Data {
10    /// Parses [`syn::Fields::Named`] from this consumed [`syn::Data::Struct`]
11    /// and returns owning iterator over them.
12    ///
13    /// # Errors
14    ///
15    /// - If this [`syn::Data`] is not a [`syn::Data::Struct`].
16    /// - If this [`syn::Data::Struct`] doesn't consist of
17    ///   [`syn::Fields::Named`].
18    fn named_fields(self) -> syn::Result<Punctuated<syn::Field, token::Comma>>;
19
20    /// Parses [`syn::Fields::Named`] from this borrowed [`syn::Data::Struct`]
21    /// and returns referencing iterator over them.
22    ///
23    /// # Errors
24    ///
25    /// - If this [`syn::Data`] is not a [`syn::Data::Struct`].
26    /// - If this [`syn::Data::Struct`] doesn't consist of
27    ///   [`syn::Fields::Named`].
28    fn named_fields_ref(
29        &self,
30    ) -> syn::Result<&Punctuated<syn::Field, token::Comma>>;
31
32    /// Parses [`syn::Fields::Unnamed`] from this consumed [`syn::Data::Struct`]
33    /// and returns owning iterator over them.
34    ///
35    /// # Errors
36    ///
37    /// - If this [`syn::Data`] is not a [`syn::Data::Struct`].
38    /// - If this [`syn::Data::Struct`] doesn't consist of
39    ///   [`syn::Fields::Unnamed`].
40    fn unnamed_fields(
41        self,
42    ) -> syn::Result<Punctuated<syn::Field, token::Comma>>;
43
44    /// Parses [`syn::Fields::Unnamed`] from this borrowed [`syn::Data::Struct`]
45    /// and returns referencing iterator over them.
46    ///
47    /// # Errors
48    ///
49    /// - If this [`syn::Data`] is not a [`syn::Data::Struct`].
50    /// - If this [`syn::Data::Struct`] doesn't consist of
51    ///   [`syn::Fields::Unnamed`].
52    fn unnamed_fields_ref(
53        &self,
54    ) -> syn::Result<&Punctuated<syn::Field, token::Comma>>;
55}
56
57#[sealed]
58impl Data for syn::Data {
59    fn named_fields(self) -> syn::Result<Punctuated<syn::Field, token::Comma>> {
60        match self {
61            Self::Struct(data) => match data.fields {
62                syn::Fields::Named(f) => Ok(f.named),
63                syn::Fields::Unit | syn::Fields::Unnamed(_) => {
64                    Err(syn::Error::new_spanned(
65                        &data.fields,
66                        "expected named struct fields only",
67                    ))
68                }
69            },
70            Self::Enum(data) => Err(syn::Error::new_spanned(
71                data.enum_token,
72                "expected struct only",
73            )),
74            Self::Union(data) => Err(syn::Error::new_spanned(
75                data.union_token,
76                "expected struct only",
77            )),
78        }
79    }
80
81    fn named_fields_ref(
82        &self,
83    ) -> syn::Result<&Punctuated<syn::Field, token::Comma>> {
84        match self {
85            Self::Struct(data) => match &data.fields {
86                syn::Fields::Named(f) => Ok(&f.named),
87                syn::Fields::Unit | syn::Fields::Unnamed(_) => {
88                    Err(syn::Error::new_spanned(
89                        &data.fields,
90                        "expected named struct fields only",
91                    ))
92                }
93            },
94            Self::Enum(data) => Err(syn::Error::new_spanned(
95                data.enum_token,
96                "expected struct only",
97            )),
98            Self::Union(data) => Err(syn::Error::new_spanned(
99                data.union_token,
100                "expected struct only",
101            )),
102        }
103    }
104
105    fn unnamed_fields(
106        self,
107    ) -> syn::Result<Punctuated<syn::Field, token::Comma>> {
108        match self {
109            Self::Struct(data) => match data.fields {
110                syn::Fields::Unnamed(f) => Ok(f.unnamed),
111                syn::Fields::Unit | syn::Fields::Named(_) => {
112                    Err(syn::Error::new_spanned(
113                        &data.fields,
114                        "expected unnamed struct fields only",
115                    ))
116                }
117            },
118            Self::Enum(data) => Err(syn::Error::new_spanned(
119                data.enum_token,
120                "expected struct only",
121            )),
122            Self::Union(data) => Err(syn::Error::new_spanned(
123                data.union_token,
124                "expected struct only",
125            )),
126        }
127    }
128
129    fn unnamed_fields_ref(
130        &self,
131    ) -> syn::Result<&Punctuated<syn::Field, token::Comma>> {
132        match self {
133            Self::Struct(data) => match &data.fields {
134                syn::Fields::Unnamed(f) => Ok(&f.unnamed),
135                syn::Fields::Unit | syn::Fields::Named(_) => {
136                    Err(syn::Error::new_spanned(
137                        &data.fields,
138                        "expected unnamed struct fields only",
139                    ))
140                }
141            },
142            Self::Enum(data) => Err(syn::Error::new_spanned(
143                data.enum_token,
144                "expected struct only",
145            )),
146            Self::Union(data) => Err(syn::Error::new_spanned(
147                data.union_token,
148                "expected struct only",
149            )),
150        }
151    }
152}
153
154/// Extension of a [`syn::Ident`](struct@syn::Ident).
155#[sealed]
156pub trait Ident {
157    /// Creates a new [`syn::Ident`] out of the given string value with a
158    /// [`Span::call_site`].
159    ///
160    /// [`syn::Ident`]: struct@syn::Ident
161    #[must_use]
162    fn new_on_call_site(ident: &str) -> syn::Ident;
163}
164
165#[sealed]
166impl Ident for syn::Ident {
167    #[inline]
168    fn new_on_call_site(string: &str) -> Self {
169        Self::new(string, Span::call_site())
170    }
171}