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 TypeDecl {
32 Struct(Struct),
33 Enum(Enum),
34 TupleStruct(TupleStruct)
35 }
36
37 enum Vis {
38 Pub(KPub),
39 PubCrate(Cons<KPub, ParenthesisGroupContaining<KCrate>>),
40 }
41
42 struct Attribute {
43 _pound: Pound,
44 body: BracketGroupContaining<AttributeInner>,
45 }
46
47 enum AttributeInner {
48 Facet(FacetAttr),
49 Doc(DocInner),
50 Repr(ReprInner),
51 Any(Vec<TokenTree>)
52 }
53
54 struct FacetAttr {
55 _facet: KFacet,
56 inner: ParenthesisGroupContaining<FacetInner>,
57 }
58
59 enum FacetInner {
60 Sensitive(KSensitive),
61 Other(Vec<TokenTree>)
62 }
63
64 struct DocInner {
65 _kw_doc: KDoc,
66 _eq: Eq,
67 value: LiteralString,
68 }
69
70 struct ReprInner {
71 _kw_repr: KRepr,
72 attr: ParenthesisGroupContaining<Ident>,
73 }
74
75 struct Struct {
76 attributes: Vec<Attribute>,
78 _vis: Option<Vis>,
79 _kw_struct: KStruct,
80 name: Ident,
81 body: Option<BraceGroupContaining<CommaDelimitedVec<StructField>>>,
82 }
83
84 struct Lifetime {
85 _apostrophe: Apostrophe,
86 name: Ident,
87 }
88
89 enum Expr {
90 Integer(LiteralInteger),
91 }
92
93 enum Type {
94 Path(PathType),
95 Tuple(ParenthesisGroupContaining<CommaDelimitedVec<Box<Type>>>),
96 Slice(BracketGroupContaining<Box<Type>>),
97 Bare(BareType),
98 }
99
100 struct PathType {
101 prefix: Ident,
102 _doublesemi: DoubleSemicolon,
103 rest: Box<Type>,
104 }
105
106 struct BareType {
107 name: Ident,
108 generic_params: Option<GenericParams>,
109 }
110
111 struct GenericParams {
112 _lt: Lt,
113 params: CommaDelimitedVec<Type>,
114 _gt: Gt,
115 }
116
117 enum ConstOrMut {
118 Const(KConst),
119 Mut(KMut),
120 }
121
122 struct StructField {
123 attributes: Vec<Attribute>,
124 _vis: Option<Vis>,
125 name: Ident,
126 _colon: Colon,
127 typ: Type,
128 }
129
130 struct TupleStruct {
131 attributes: Vec<Attribute>,
133 _vis: Option<Vis>,
134 _kw_struct: KStruct,
135 name: Ident,
136 body: ParenthesisGroupContaining<CommaDelimitedVec<TupleField>>,
137 }
138
139 struct TupleField {
140 attributes: Vec<Attribute>,
141 vis: Option<Vis>,
142 typ: Type,
143 }
144
145 struct Enum {
146 attributes: Vec<Attribute>,
148 _pub: Option<KPub>,
149 _kw_enum: KEnum,
150 name: Ident,
151 body: BraceGroupContaining<CommaDelimitedVec<EnumVariantLike>>,
152 }
153
154 enum EnumVariantLike {
155 Tuple(TupleVariant),
156 Struct(StructVariant),
157 Unit(UnitVariant),
158 }
159
160 struct UnitVariant {
161 attributes: Vec<Attribute>,
162 name: Ident,
163 }
164
165 struct TupleVariant {
166 attributes: Vec<Attribute>,
168 name: Ident,
169 _paren: ParenthesisGroupContaining<CommaDelimitedVec<TupleField>>,
170 }
171
172 struct StructVariant {
173 attributes: Vec<Attribute>,
175 name: Ident,
176 fields: BraceGroupContaining<CommaDelimitedVec<StructField>>,
177 }
178}
179
180#[proc_macro_derive(Facet, attributes(facet))]
185pub fn facet_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
186 let input = TokenStream::from(input);
187 let mut i = input.to_token_iter();
188
189 match i.parse::<TypeDecl>() {
191 Ok(TypeDecl::Struct(parsed)) => process_struct::process_struct(parsed),
192 Ok(TypeDecl::TupleStruct(parsed)) => process_tuple_struct::process_tuple_struct(parsed),
193 Ok(TypeDecl::Enum(parsed)) => process_enum::process_enum(parsed),
194 Err(err) => {
195 panic!(
196 "Could not parse input as struct, tuple struct, or enum: {}\nError: {:?}",
197 input, err
198 );
199 }
200 }
201}
202
203impl core::fmt::Display for Type {
204 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
205 match self {
206 Type::Path(path) => {
207 write!(f, "{}::{}", path.prefix, path.rest)
208 }
209 Type::Tuple(tuple) => {
210 write!(f, "(")?;
211 for (i, typ) in tuple.content.0.iter().enumerate() {
212 if i > 0 {
213 write!(f, ", ")?;
214 }
215 write!(f, "{}", typ.value)?;
216 }
217 write!(f, ")")
218 }
219 Type::Slice(slice) => {
220 write!(f, "[{}]", slice.content)
221 }
222 Type::Bare(ident) => {
223 write!(f, "{}", ident.name)?;
224 if let Some(generic_params) = &ident.generic_params {
225 write!(f, "<")?;
226 for (i, param) in generic_params.params.0.iter().enumerate() {
227 if i > 0 {
228 write!(f, ", ")?;
229 }
230 write!(f, "{}", param.value)?;
231 }
232 write!(f, ">")?;
233 }
234 Ok(())
235 }
236 }
237 }
238}
239
240impl core::fmt::Display for ConstOrMut {
241 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 match self {
243 ConstOrMut::Const(_) => write!(f, "const"),
244 ConstOrMut::Mut(_) => write!(f, "mut"),
245 }
246 }
247}
248
249impl core::fmt::Display for Lifetime {
250 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251 write!(f, "'{}", self.name)
252 }
253}
254
255impl core::fmt::Display for Expr {
256 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
257 match self {
258 Expr::Integer(int) => write!(f, "{}", int.value()),
259 }
260 }
261}
262
263pub(crate) fn to_upper_snake_case(input: &str) -> String {
265 input
266 .chars()
267 .enumerate()
268 .fold(String::new(), |mut acc, (i, c)| {
269 if c.is_uppercase() {
270 if i > 0 {
271 acc.push('_');
272 }
273 acc.push(c.to_ascii_uppercase());
274 } else {
275 acc.push(c.to_ascii_uppercase());
276 }
277 acc
278 })
279}
280
281pub(crate) fn generate_static_decl(type_name: &str) -> String {
283 format!(
284 "#[used]\nstatic {}_SHAPE: &'static facet::Shape = <{} as facet::Facet>::SHAPE;",
285 to_upper_snake_case(type_name),
286 type_name
287 )
288}