Skip to content

Commit 2c06953

Browse files
committed
make html_ast
1 parent f2117bf commit 2c06953

File tree

9 files changed

+412
-390
lines changed

9 files changed

+412
-390
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ast_node/src/encoding/decode.rs

Lines changed: 144 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,43 @@
11
use syn::{spanned::Spanned, Data, DeriveInput};
22

3-
use super::{is_unknown, is_with};
3+
use super::{is_unknown, is_with, EnumType};
44

55
pub fn expand(DeriveInput { ident, data, .. }: DeriveInput) -> syn::ItemImpl {
66
match data {
77
Data::Struct(data) => {
88
let is_named = data.fields.iter().any(|field| field.ident.is_some());
9+
let names = data.fields.iter()
10+
.enumerate()
11+
.map(|(idx, field)| match field.ident.as_ref() {
12+
Some(name) => name.clone(),
13+
None => {
14+
let name = format!("unit{idx}");
15+
let name = syn::Ident::new(&name, field.span());
16+
name
17+
}
18+
})
19+
.collect::<Vec<_>>();
920

1021
let fields = data.fields.iter()
11-
.enumerate()
12-
.map(|(idx, field)| -> syn::Stmt {
22+
.zip(names.iter())
23+
.map(|(field, field_name)| -> syn::Stmt {
1324
let ty = &field.ty;
1425
let value: syn::Expr = match is_with(&field.attrs) {
1526
Some(with_type) => syn::parse_quote!(<#with_type<#ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0),
1627
None => syn::parse_quote!(<#ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?)
1728
};
1829

19-
match field.ident.as_ref() {
20-
Some(name) => syn::parse_quote!{
21-
let #name = #value;
22-
},
23-
None => {
24-
let name = format!("unit{idx}");
25-
let name = syn::Ident::new(&name, field.span());
26-
syn::parse_quote!{
27-
let #name = #value;
28-
}
29-
}
30+
syn::parse_quote!{
31+
let #field_name = #value;
3032
}
3133
});
32-
let build_struct = data
33-
.fields
34-
.iter()
35-
.enumerate()
36-
.map(|(idx, field)| -> syn::FieldValue {
37-
match field.ident.as_ref() {
38-
Some(name) => syn::parse_quote!(#name),
39-
None => {
40-
let name = format!("unit{idx}");
41-
let name = syn::Ident::new(&name, field.span());
42-
syn::parse_quote!(#name)
43-
}
44-
}
34+
let build_struct: syn::Expr = is_named
35+
.then(|| syn::parse_quote! {
36+
#ident { #(#names),* }
4537
})
46-
.collect::<syn::punctuated::Punctuated<_, syn::Token![,]>>();
47-
let build_struct: syn::Expr = if is_named {
48-
syn::parse_quote! {
49-
#ident { #build_struct }
50-
}
51-
} else {
52-
syn::parse_quote! {
53-
#ident ( #build_struct )
54-
}
55-
};
38+
.unwrap_or_else(|| syn::parse_quote! {
39+
#ident ( #(#names),* )
40+
});
5641

5742
let count = data.fields.len();
5843
let head: Option<syn::Expr> = (count != 1).then(|| {
@@ -76,97 +61,151 @@ pub fn expand(DeriveInput { ident, data, .. }: DeriveInput) -> syn::ItemImpl {
7661
}
7762
}
7863
Data::Enum(data) => {
64+
let enum_type = data.variants.iter()
65+
.filter(|v| !is_unknown(&v.attrs))
66+
.fold(None, |mut sum, next| {
67+
let ty = match &next.fields {
68+
syn::Fields::Named(_) => EnumType::Struct,
69+
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => EnumType::One,
70+
syn::Fields::Unit => EnumType::Unit,
71+
syn::Fields::Unnamed(_) => panic!("more than 1 unnamed member field are not allowed")
72+
};
73+
match (*sum.get_or_insert(ty), ty) {
74+
(EnumType::Struct, EnumType::Struct)
75+
| (EnumType::Struct, EnumType::Unit)
76+
| (EnumType::Unit, EnumType::Unit)
77+
| (EnumType::One, EnumType::One)
78+
=> (),
79+
(EnumType::Unit, EnumType::One)
80+
| (EnumType::One, EnumType::Unit)
81+
| (_, EnumType::Struct) => sum = Some(EnumType::Struct),
82+
_ => panic!("enum member types must be consistent: {:?} {:?}", sum, ty),
83+
}
84+
sum
85+
});
86+
let enum_type = enum_type.expect("enum cannot be empty");
7987
let mut iter = data.variants.iter().peekable();
80-
let mut is_unit = None;
81-
82-
assert!(!data.variants.is_empty(), "empty enums are not allowed");
83-
84-
let unknown_arm: Option<syn::Arm> = if let Some(unknown) =
85-
iter.next_if(|variant| is_unknown(&variant.attrs))
86-
{
87-
let name = &unknown.ident;
88-
assert!(
89-
unknown.discriminant.is_none(),
90-
"custom discriminant unsupport"
91-
);
92-
assert!(
93-
is_with(&unknown.attrs).is_none(),
94-
"unknown member is not allowed with type"
95-
);
96-
97-
Some(match &unknown.fields {
98-
syn::Fields::Unnamed(fields) => match fields.unnamed.len() {
99-
1 => {
100-
is_unit = Some(true);
101-
syn::parse_quote! {
102-
tag => #ident::#name(tag),
88+
89+
let unknown_arm: Option<syn::Arm> = iter.next_if(|variant| is_unknown(&variant.attrs))
90+
.map(|unknown| {
91+
let name = &unknown.ident;
92+
assert!(
93+
unknown.discriminant.is_none(),
94+
"custom discriminant unsupport"
95+
);
96+
assert!(
97+
is_with(&unknown.attrs).is_none(),
98+
"unknown member is not allowed with type"
99+
);
100+
101+
match &unknown.fields {
102+
syn::Fields::Unnamed(fields) => match fields.unnamed.len() {
103+
1 => {
104+
assert_eq!(enum_type, EnumType::Unit);
105+
syn::parse_quote! {
106+
tag => #ident::#name(tag),
107+
}
103108
}
104-
}
105-
2 => {
106-
is_unit = Some(false);
107-
let val_ty = &fields.unnamed[1].ty;
108-
109-
syn::parse_quote! {
110-
tag => {
111-
let val = <#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;
112-
#ident::#name(tag, val)
113-
},
109+
2 => {
110+
assert_eq!(enum_type, EnumType::One);
111+
let val_ty = &fields.unnamed[1].ty;
112+
syn::parse_quote! {
113+
tag => {
114+
let tag: u32 = tag.try_into().map_err(|_| cbor4ii::core::error::DecodeError::CastOverflow {
115+
name: &"tag",
116+
})?;
117+
let val = <#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;
118+
#ident::#name(tag, val)
119+
},
120+
}
114121
}
115-
}
116-
_ => panic!("unknown member must be a tag and a value"),
117-
},
118-
_ => panic!("named enum unsupported"),
119-
})
120-
} else {
121-
None
122-
};
122+
_ => panic!("unknown member must be a tag and a value"),
123+
},
124+
_ => panic!("named enum unsupported"),
125+
}
126+
});
127+
128+
if matches!(enum_type, EnumType::Struct) {
129+
assert!(unknown_arm.is_none(), "struct enum does not allow unknown variants");
130+
}
123131

124132
let fields = iter
125133
.enumerate()
126134
.map(|(idx, field)| -> syn::Arm {
127135
let idx = idx + 1; // skip zero
128136
let idx: u32 = idx.try_into().expect("enum tags must not exceed 32 bits");
137+
let idx = idx as u64;
129138
let name = &field.ident;
130139

131140
assert!(field.discriminant.is_none(), "custom discriminant is not allowed");
132141
assert!(!is_unknown(&field.attrs), "unknown member must be first");
133142

134-
match &field.fields {
135-
syn::Fields::Unnamed(fields) => {
136-
if fields.unnamed.len() != 1 {
137-
panic!("enum member only allows one field");
138-
}
139-
140-
if *is_unit.get_or_insert(false) {
141-
panic!("the number of fields in member must be consistent");
143+
match enum_type {
144+
EnumType::Unit => {
145+
assert!(is_with(&field.attrs).is_none(), "unit member is not allowed with type");
146+
syn::parse_quote!{
147+
#idx => #ident::#name,
142148
}
143-
let val_ty = &fields.unnamed[0].ty;
149+
},
150+
EnumType::One => {
151+
let val_ty = &field.fields.iter().next().unwrap().ty;
144152
let value: syn::Expr = match is_with(&field.attrs) {
145-
Some(with_type) => syn::parse_quote!(<#with_type<#val_ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0),
153+
Some(with_type)
154+
=> syn::parse_quote!(<#with_type<#val_ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0),
146155
None => syn::parse_quote!(<#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?)
147156
};
148157

149158
syn::parse_quote!{
150-
#idx => {
151-
let val = #value;
152-
#ident::#name(val)
153-
},
159+
#idx => #ident::#name(#value),
154160
}
155161
},
156-
syn::Fields::Unit => {
157-
if !*is_unit.get_or_insert(true) {
158-
panic!("the number of fields in member must be consistent");
159-
}
160-
assert!(is_with(&field.attrs).is_none(), "unit member is not allowed with type");
161-
162+
EnumType::Struct => {
163+
let is_named = field.fields.iter().all(|field| field.ident.is_some());
164+
let names = field.fields.iter()
165+
.enumerate()
166+
.map(|(idx, field)| match field.ident.as_ref() {
167+
Some(name) => name.clone(),
168+
None => {
169+
let name = format!("unit{idx}");
170+
let name = syn::Ident::new(&name, field.span());
171+
name
172+
}
173+
})
174+
.collect::<Vec<_>>();
175+
let num = field.fields.len();
176+
177+
let stmt = field.fields.iter()
178+
.zip(names.iter())
179+
.map(|(field, field_name)| -> syn::Stmt {
180+
let val_ty = &field.ty;
181+
match is_with(&field.attrs) {
182+
Some(with_type) => syn::parse_quote!{
183+
let #field_name = <#with_type<#val_ty> as cbor4ii::core::dec::Decode<'_>>::decode(reader)?.0;
184+
},
185+
None => syn::parse_quote!{
186+
let #field_name = <#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;
187+
}
188+
}
189+
});
190+
let build_struct: syn::Expr = is_named
191+
.then(|| syn::parse_quote! {
192+
#ident::#name { #(#names),* }
193+
})
194+
.unwrap_or_else(|| syn::parse_quote! {
195+
#ident::#name ( #(#names),* )
196+
});
197+
162198
syn::parse_quote!{
163-
#idx => #ident::#name,
164-
}
165-
},
166-
syn::Fields::Named(_) => panic!("named enum unsupported")
199+
#idx => {
200+
let len = cbor4ii::core::types::Array::len(reader)?;
201+
debug_assert_eq!(len, Some(#num));
202+
#(#stmt)*
203+
#build_struct
204+
},
205+
}
206+
}
167207
}
168-
})
169-
.collect::<Vec<_>>();
208+
});
170209

171210
let unknown_arm = match unknown_arm {
172211
Some(arm) => arm,
@@ -183,26 +222,13 @@ pub fn expand(DeriveInput { ident, data, .. }: DeriveInput) -> syn::ItemImpl {
183222
}
184223
};
185224

186-
let head: syn::Expr = {
187-
let count: usize = match is_unit {
188-
Some(true) => 1,
189-
Some(false) => 2,
190-
None => panic!(),
191-
};
192-
syn::parse_quote! {{
193-
let n = <cbor4ii::core::types::Array<()>>::len(reader)?;
194-
debug_assert_eq!(n, Some(#count));
195-
}}
196-
};
197-
198225
syn::parse_quote! {
199226
impl<'de> cbor4ii::core::dec::Decode<'de> for #ident {
200227
#[inline]
201228
fn decode<R: cbor4ii::core::dec::Read<'de>>(reader: &mut R)
202229
-> Result<Self, cbor4ii::core::error::DecodeError<R::Error>>
203230
{
204-
#head;
205-
let tag = <u32 as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;
231+
let tag = <cbor4ii::core::types::Tag<()>>::tag(reader)?;
206232
let value = match tag {
207233
#(#fields)*
208234
#unknown_arm

0 commit comments

Comments
 (0)