reth_codecs_derive/compact/
structs.rs1use super::*;
2
3#[derive(Debug)]
4pub struct StructHandler<'a> {
5 fields_iterator: std::iter::Peekable<std::slice::Iter<'a, FieldTypes>>,
6 lines: Vec<TokenStream2>,
7 pub is_wrapper: bool,
8}
9
10impl<'a> StructHandler<'a> {
11 pub fn new(fields: &'a FieldList) -> Self {
12 StructHandler {
13 lines: vec![],
14 fields_iterator: fields.iter().peekable(),
15 is_wrapper: false,
16 }
17 }
18
19 pub fn next_field(&mut self) -> Option<&'a FieldTypes> {
20 self.fields_iterator.next()
21 }
22
23 pub fn generate_to(mut self) -> Vec<TokenStream2> {
24 while let Some(field) = self.next_field() {
25 match field {
26 FieldTypes::EnumVariant(_) | FieldTypes::EnumUnnamedField(_) => unreachable!(),
27 FieldTypes::StructField(field_descriptor) => self.to(field_descriptor),
28 }
29 }
30 self.lines
31 }
32
33 pub fn generate_from(&mut self, known_types: &[&str]) -> Vec<TokenStream2> {
34 while let Some(field) = self.next_field() {
35 match field {
36 FieldTypes::EnumVariant(_) | FieldTypes::EnumUnnamedField(_) => unreachable!(),
37 FieldTypes::StructField(field_descriptor) => {
38 self.from(field_descriptor, known_types)
39 }
40 }
41 }
42 self.lines.clone()
43 }
44
45 fn to(&mut self, field_descriptor: &StructFieldDescriptor) {
47 let StructFieldDescriptor { name, ftype, is_compact, use_alt_impl, is_reference: _ } =
48 field_descriptor;
49
50 let to_compact_ident = if *use_alt_impl {
51 format_ident!("specialized_to_compact")
52 } else {
53 format_ident!("to_compact")
54 };
55
56 if name.is_empty() {
58 self.is_wrapper = true;
59
60 self.lines.push(quote! {
61 let _len = self.0.#to_compact_ident(&mut buffer);
62 });
63
64 if is_flag_type(ftype) {
65 self.lines.push(quote! {
66 flags.set_placeholder_len(_len as u8);
67 })
68 }
69
70 return
71 }
72
73 let name = format_ident!("{name}");
74 let set_len_method = format_ident!("set_{name}_len");
75 let len = format_ident!("{name}_len");
76
77 if *is_compact && !is_flag_type(ftype) {
79 let itype = format_ident!("{ftype}");
80 let set_bool_method = format_ident!("set_{name}");
81 self.lines.push(quote! {
82 if self.#name != #itype::zero() {
83 flags.#set_bool_method(true);
84 self.#name.#to_compact_ident(&mut buffer);
85 };
86 });
87 } else {
88 self.lines.push(quote! {
89 let #len = self.#name.#to_compact_ident(&mut buffer);
90 });
91 }
92 if is_flag_type(ftype) {
93 self.lines.push(quote! {
94 flags.#set_len_method(#len as u8);
95 })
96 }
97 }
98
99 fn from(&mut self, field_descriptor: &StructFieldDescriptor, known_types: &[&str]) {
101 let StructFieldDescriptor { name, ftype, is_compact, use_alt_impl, .. } = field_descriptor;
102
103 let (name, len) = if name.is_empty() {
104 self.is_wrapper = true;
105
106 (format_ident!("placeholder"), format_ident!("placeholder_len"))
108 } else {
109 (format_ident!("{name}"), format_ident!("{name}_len"))
110 };
111
112 let from_compact_ident = if *use_alt_impl {
113 format_ident!("specialized_from_compact")
114 } else {
115 format_ident!("from_compact")
116 };
117
118 assert!(
134 known_types.contains(&ftype.as_str()) ||
135 is_flag_type(ftype) ||
136 self.fields_iterator.peek().is_none(),
137 "`{ftype}` field should be placed as the last one since it's not known.
138 If it's an alias type (which are not supported by proc_macro), be sure to add it to either `known_types` or `get_bit_size` lists in the derive crate."
139 );
140
141 if ftype == "Bytes" {
142 self.lines.push(quote! {
143 let mut #name = Bytes::new();
144 (#name, buf) = Bytes::from_compact(buf, buf.len() as usize);
145 })
146 } else {
147 let ident_type = format_ident!("{ftype}");
148 if !is_flag_type(ftype) {
149 self.lines.push(quote! {
151 let (#name, new_buf) = #ident_type::#from_compact_ident(buf, buf.len());
152 })
153 } else if *is_compact {
154 self.lines.push(quote! {
155 let (#name, new_buf) = #ident_type::#from_compact_ident(buf, flags.#len() as usize);
156 });
157 } else {
158 todo!()
159 }
160 self.lines.push(quote! {
161 buf = new_buf;
162 });
163 }
164 }
165}