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                unreachable!("flag-type fields are always compact in Compact derive")
159            }
160            self.lines.push(quote! {
161                buf = new_buf;
162            });
163        }
164    }
165}