1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4mod process_enum;
5mod process_struct;
6mod process_tuple_struct;
7
8use unsynn::*;
9
10keyword! {
11 KPub = "pub";
12 KStruct = "struct";
13 KEnum = "enum";
14 KDoc = "doc";
15 KRepr = "repr";
16 KCrate = "crate";
17 KConst = "const";
18 KMut = "mut";
19 KFacet = "facet";
20 KSensitive = "sensitive";
21}
22
23operator! {
24 Eq = "=";
25 Semi = ";";
26 Apostrophe = "'";
27 DoubleSemicolon = "::";
28}
29
30unsynn! {
31 enum Vis {
32 Pub(KPub),
33 PubCrate(Cons<KPub, ParenthesisGroupContaining<KCrate>>),
34 }
35
36 struct Attribute {
37 _pound: Pound,
38 body: BracketGroupContaining<AttributeInner>,
39 }
40
41 enum AttributeInner {
42 Facet(FacetAttr),
43 Doc(DocInner),
44 Repr(ReprInner),
45 Any(Vec<TokenTree>)
46 }
47
48 struct FacetAttr {
49 _facet: KFacet,
50 inner: ParenthesisGroupContaining<FacetInner>,
51 }
52
53 enum FacetInner {
54 Sensitive(KSensitive),
55 Other(Vec<TokenTree>)
56 }
57
58 struct DocInner {
59 _kw_doc: KDoc,
60 _eq: Eq,
61 value: LiteralString,
62 }
63
64 struct ReprInner {
65 _kw_repr: KRepr,
66 attr: ParenthesisGroupContaining<Ident>,
67 }
68
69 struct Struct {
70 attributes: Vec<Attribute>,
72 _vis: Option<Vis>,
73 _kw_struct: KStruct,
74 name: Ident,
75 body: BraceGroupContaining<CommaDelimitedVec<StructField>>,
76 }
77
78 struct Lifetime {
79 _apostrophe: Apostrophe,
80 name: Ident,
81 }
82
83 enum Expr {
84 Integer(LiteralInteger),
85 }
86
87 enum Type {
88 Path(PathType),
89 Tuple(ParenthesisGroupContaining<CommaDelimitedVec<Box<Type>>>),
90 Slice(BracketGroupContaining<Box<Type>>),
91 Bare(BareType),
92 }
93
94 struct PathType {
95 prefix: Ident,
96 _doublesemi: DoubleSemicolon,
97 rest: Box<Type>,
98 }
99
100 struct BareType {
101 name: Ident,
102 generic_params: Option<GenericParams>,
103 }
104
105 struct GenericParams {
106 _lt: Lt,
107 params: CommaDelimitedVec<Type>,
108 _gt: Gt,
109 }
110
111 enum ConstOrMut {
112 Const(KConst),
113 Mut(KMut),
114 }
115
116 struct StructField {
117 attributes: Vec<Attribute>,
118 _vis: Option<Vis>,
119 name: Ident,
120 _colon: Colon,
121 typ: Type,
122 }
123
124 struct TupleStruct {
125 attributes: Vec<Attribute>,
127 _vis: Option<Vis>,
128 _kw_struct: KStruct,
129 name: Ident,
130 body: ParenthesisGroupContaining<CommaDelimitedVec<TupleField>>,
131 }
132
133 struct TupleField {
134 attributes: Vec<Attribute>,
135 vis: Option<Vis>,
136 typ: Type,
137 }
138
139 struct Enum {
140 attributes: Vec<Attribute>,
142 _pub: Option<KPub>,
143 _kw_enum: KEnum,
144 name: Ident,
145 body: BraceGroupContaining<CommaDelimitedVec<EnumVariantLike>>,
146 }
147
148 enum EnumVariantLike {
149 Unit(UnitVariant),
150 Tuple(TupleVariant),
151 Struct(StructVariant),
152 }
153
154 struct UnitVariant {
155 attributes: Vec<Attribute>,
156 name: Ident,
157 }
158
159 struct TupleVariant {
160 attributes: Vec<Attribute>,
162 name: Ident,
163 _paren: ParenthesisGroupContaining<CommaDelimitedVec<TupleField>>,
164 }
165
166 struct StructVariant {
167 _doc_attributes: Vec<Attribute>,
169 name: Ident,
170 _brace: BraceGroupContaining<CommaDelimitedVec<StructField>>,
171 }
172}
173
174#[proc_macro_derive(Facet, attributes(facet))]
179pub fn facet_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
180 let input = TokenStream::from(input);
181 let mut i = input.to_token_iter();
182
183 if let Ok(parsed) = i.parse::<Struct>() {
185 return process_struct::process_struct(parsed);
186 }
187 let struct_tokens_left = i.count();
188
189 i = input.to_token_iter(); if let Ok(parsed) = i.parse::<TupleStruct>() {
192 return process_tuple_struct::process_tuple_struct(parsed);
193 }
194 let tuple_struct_tokens_left = i.count();
195
196 i = input.to_token_iter(); if let Ok(parsed) = i.parse::<Enum>() {
199 return process_enum::process_enum(parsed);
200 }
201 let enum_tokens_left = i.count();
202
203 let mut msg = format!(
204 "Could not parse input as struct, tuple struct, or enum: {}",
205 input
206 );
207
208 let min_tokens_left = struct_tokens_left
210 .min(tuple_struct_tokens_left)
211 .min(enum_tokens_left);
212
213 if min_tokens_left == struct_tokens_left {
215 i = input.to_token_iter();
216 let err = i.parse::<Struct>().err();
217 msg = format!(
218 "{}\n====> Error parsing struct: {:?}\n====> Remaining tokens after struct parsing: {}",
219 msg,
220 err,
221 i.collect::<TokenStream>()
222 );
223 } else if min_tokens_left == tuple_struct_tokens_left {
224 i = input.to_token_iter();
225 let err = i.parse::<TupleStruct>().err();
226 msg = format!(
227 "{}\n====> Error parsing tuple struct: {:?}\n====> Remaining tokens after tuple struct parsing: {}",
228 msg,
229 err,
230 i.collect::<TokenStream>()
231 );
232 } else {
233 i = input.to_token_iter();
234 let err = i.parse::<Enum>().err();
235 msg = format!(
236 "{}\n====> Error parsing enum: {:?}\n====> Remaining tokens after enum parsing: {}",
237 msg,
238 err,
239 i.collect::<TokenStream>()
240 );
241 }
242
243 panic!("{msg}");
245}
246
247impl core::fmt::Display for Type {
248 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249 match self {
250 Type::Path(path) => {
251 write!(f, "{}::{}", path.prefix, path.rest)
252 }
253 Type::Tuple(tuple) => {
254 write!(f, "(")?;
255 for (i, typ) in tuple.content.0.iter().enumerate() {
256 if i > 0 {
257 write!(f, ", ")?;
258 }
259 write!(f, "{}", typ.value)?;
260 }
261 write!(f, ")")
262 }
263 Type::Slice(slice) => {
264 write!(f, "[{}]", slice.content)
265 }
266 Type::Bare(ident) => {
267 write!(f, "{}", ident.name)?;
268 if let Some(generic_params) = &ident.generic_params {
269 write!(f, "<")?;
270 for (i, param) in generic_params.params.0.iter().enumerate() {
271 if i > 0 {
272 write!(f, ", ")?;
273 }
274 write!(f, "{}", param.value)?;
275 }
276 write!(f, ">")?;
277 }
278 Ok(())
279 }
280 }
281 }
282}
283
284impl core::fmt::Display for ConstOrMut {
285 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
286 match self {
287 ConstOrMut::Const(_) => write!(f, "const"),
288 ConstOrMut::Mut(_) => write!(f, "mut"),
289 }
290 }
291}
292
293impl core::fmt::Display for Lifetime {
294 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
295 write!(f, "'{}", self.name)
296 }
297}
298
299impl core::fmt::Display for Expr {
300 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
301 match self {
302 Expr::Integer(int) => write!(f, "{}", int.value()),
303 }
304 }
305}