i_codegen_code/
lib.rs

1pub mod types;
2pub mod utils;
3
4#[cfg(feature = "generate")]
5pub use linkme;
6
7#[cfg(feature = "experimental")]
8use serde_reflection;
9
10#[cfg(feature = "generate")]
11pub struct Context {
12    tags: std::collections::BTreeSet<String>,
13    #[cfg(feature = "experimental")]
14    tracer: Option<(Vec<(String, types::TypeRoot)>, serde_reflection::Tracer)>,
15    untraced: Vec<types::TypeRoot>,
16    errors: Vec<String>,
17}
18
19#[cfg(feature = "generate")]
20impl Context {
21    // pub fn trace_type_root<'de, T: serde::Deserialize<'de>>(
22    pub fn add_type_root(
23        &mut self,
24        names_json: &str,
25        file_name: &str,
26        line: u32,
27        tags: &[&str],
28    ) -> () {
29        if !self.should_include(tags) {
30            return;
31        }
32        let type_root = self.create_type_root(names_json, file_name, line);
33        self.untraced.push(type_root);
34    }
35
36    fn should_include(&self, tags: &[&str]) -> bool {
37        if tags.is_empty() {
38            if !self.tags.is_empty() {
39                return false;
40            }
41        } else {
42            let mut found = false;
43            for tag in tags {
44                if self.tags.contains(*tag) {
45                    found = true;
46                    continue;
47                }
48            }
49            if !found {
50                return false;
51            }
52        }
53        return true;
54    }
55
56    fn create_type_root(
57        &mut self,
58        names_json: &str,
59        file_name: &str,
60        line: u32,
61    ) -> types::TypeRoot {
62        let mut type_root = serde_json::from_str::<types::TypeRoot>(names_json)
63            .expect("Incompatible versions of generate & code");
64
65        type_root.file = file_name.to_string();
66        type_root.line = line;
67        type_root
68    }
69
70    #[cfg(features = "experimental")]
71    pub fn trace_type_root<T>(
72        &mut self,
73        names_json: &str,
74        file_name: &str,
75        line: u32,
76        tags: &[&str],
77    ) -> () {
78        if !self.should_include(tags) {
79            return;
80        }
81        let type_root = self.create_type_root(names_json, file_name, line);
82
83        match &type_root.inner.value {
84            types::ContainerFormat::Enum(_) => {
85                for types::Spanned {
86                    value: (key, _value),
87                    ..
88                } in type_root.inner.serde_attrs.iter()
89                {
90                    if &key.value == "tag" || &key.value == "content" {
91                        // cannot be traced...
92                        eprintln!("We can't trace enums with tag and content!");
93                        return;
94                    }
95                }
96            }
97            _ => {}
98        }
99
100        if let Some((ref mut tracer, ref mut merge)) = self.tracer {
101            type TODO = ();
102            todo!("Trace simple enabled for serialize only?");
103            match tracer.trace_simple_type::<TODO>() {
104                Ok((serde_reflection::Format::TypeName(name), _samples)) => {
105                    merge.push((name, type_root));
106                }
107                Ok((other_format, _samples)) => {
108                    todo!("handle other format {other_format:?}\nFor type root:{type_root:#?}")
109                }
110                Err(err) => {
111                    self.errors.push(format!("{err:#?}"));
112                }
113            }
114        } else {
115            self.untraced.push(type_root);
116        }
117    }
118}
119
120#[cfg(feature = "generate")]
121#[linkme::distributed_slice]
122pub static CODEGEN_ITEMS: [fn(&mut Context)] = [..];
123
124#[cfg(feature = "generate")]
125#[track_caller]
126pub fn get_types_by_tags(tags: &[String]) -> Vec<types::TypeRoot> {
127    let mut context = Context {
128        tags: tags.into_iter().cloned().map(String::from).collect(),
129        errors: Vec::new(),
130        #[cfg(feature = "experimental")]
131        tracer: None,
132        // tracer: Some((Tracer::new(TracerConfig::default()), Vec::new())),
133        untraced: Vec::new(),
134    };
135    {
136        let mut context = &mut context;
137        for gen in CODEGEN_ITEMS {
138            gen(&mut context);
139            if !context.errors.is_empty() {
140                for err in &context.errors {
141                    eprintln!("{err}");
142                }
143            }
144            context.errors.clear();
145        }
146    }
147
148    #[allow(unused_mut)]
149    let Context {
150        errors,
151        untraced: mut type_roots,
152        #[cfg(feature = "experimental")]
153        tracer,
154        tags,
155    } = context;
156
157    if !errors.is_empty() {
158        eprintln!("Context trace errors for tags {tags:?}:");
159        for err in errors {
160            eprintln!(" * {err:?}");
161        }
162    }
163
164    #[cfg(feature = "experimental")]
165    if let Some((tracer, merge)) = tracer {
166        let registry = tracer.registry().expect("constructing registry");
167        eprintln!("{registry:#?}");
168        type_roots.extend(types.into_iter().map(|(name, mut type_root)| {
169            use types::{ContainerFormat, VariantFormat};
170            use serde_reflection as sr;
171            let format = registry.get(&name).expect("type exists in registry (if not, maybe alias unsupported)");
172            match (&mut type_root.inner.value, format) {
173                (ContainerFormat::Struct(ref mut named_formats), sr::ContainerFormat::Struct(ref reflected_named_formats)) => {
174                    for named_format in named_formats.iter_mut() {
175                        let serialize_name = named_format.serialize_name().to_string();
176                        named_format.value.replace_incomplete(
177                            reflected_named_formats.iter().find_map(|i| {
178                                if &i.name == &serialize_name {
179                                    Some(format_to_format(&i.value))
180                                } else {
181                                    None
182                                }
183                            }).expect("found matching struct item")
184                        );
185                    }
186                },
187                (ContainerFormat::Enum(ref mut enu), sr::ContainerFormat::Enum(ref reflected_enu)) => {
188                    for (idx, ref mut enu_variant) in enu.iter_mut() {
189                        let reflected_variant = reflected_enu.get(idx).expect("found matching enum new type variant");    
190                        match (&mut enu_variant.value, &reflected_variant.value) {
191                            (VariantFormat::Unit, sr::VariantFormat::Unit) => {
192                                // nothing to replace
193                            },
194                            (VariantFormat::NewType(ref mut format), sr::VariantFormat::NewType(reflected)) => {
195                                format.replace_incomplete(format_to_format(&reflected));
196                            },
197                            (VariantFormat::Tuple(ref mut formats), sr::VariantFormat::Tuple(reflected_formats)) => {
198                                for (format, reflected) in formats.iter_mut().zip(reflected_formats.iter()) {
199                                    format.replace_incomplete(format_to_format(&reflected));
200                                }
201                            },
202                            (VariantFormat::Struct(ref mut named_formats), sr::VariantFormat::Struct(reflected_named_formats)) => {
203                                for named_format in named_formats.iter_mut() {
204                                    let serialize_name = named_format.serialize_name().to_string();
205                                    named_format.value.replace_incomplete({
206                                        reflected_named_formats.iter().find_map(|i| {
207                                            if &i.name == &serialize_name {
208                                                Some(format_to_format(&i.value))
209                                            } else {
210                                                None
211                                            }
212                                        }).expect("found matching struct item")
213                                    });
214                                }
215                            },
216                            (other, reflected_other) => {
217                                panic!("Unknown enum combination {other:#?} VERSUS {reflected_other:?}");
218                            }
219                        };
220                    }
221                },
222                (ContainerFormat::UnitStruct, sr::ContainerFormat::UnitStruct) => {
223                    // nothing to fill in
224                },
225                (ContainerFormat::NewTypeStruct(format), sr::ContainerFormat::NewTypeStruct(reflected_format)) => {
226                    format.replace_incomplete(format_to_format(&reflected_format));
227                },
228                (ContainerFormat::TupleStruct(formats), sr::ContainerFormat::TupleStruct(reflected_formats)) => {
229                    for (ref mut format, reflected_format) in formats.iter_mut().zip(reflected_formats.iter()) {
230                        format.replace_incomplete(format_to_format(&reflected_format));
231                    }
232                },
233                (named_type, reflected_type) => {
234                    panic!("Mismatch between containers (do we need to handle flatten or similar correctly?) {named_type:#?} VERSUS {reflected_type:#?}")
235                }
236            }
237
238            type_root
239        }));
240    }
241
242    type_roots
243}
244
245#[cfg(feature = "experimental")]
246fn format_to_format(input: &serde_reflection::Format) -> types::Format {
247    use serde_reflection::Format as SFormat;
248    use types::Format as IFormat;
249    match input {
250        SFormat::Variable(_) => unreachable!(),
251        SFormat::TypeName(name) => IFormat::TypeName(name.clone()),
252        SFormat::Unit => IFormat::Unit,
253        SFormat::Bool => IFormat::Bool,
254        SFormat::I8 => IFormat::I8,
255        SFormat::I16 => IFormat::I16,
256        SFormat::I32 => IFormat::I32,
257        SFormat::I64 => IFormat::I64,
258        SFormat::I128 => IFormat::I128,
259        SFormat::U8 => IFormat::U8,
260        SFormat::U16 => IFormat::U16,
261        SFormat::U32 => IFormat::U32,
262        SFormat::U64 => IFormat::U64,
263        SFormat::U128 => IFormat::U128,
264        SFormat::F32 => IFormat::F32,
265        SFormat::F64 => IFormat::F64,
266        SFormat::Char => IFormat::Char,
267        SFormat::Str => IFormat::Str,
268        SFormat::Bytes => IFormat::Bytes,
269        SFormat::Option(inner) => IFormat::Option(format_to_format(&inner).into()),
270        SFormat::Seq(inner) => IFormat::Seq(format_to_format(&inner).into()),
271        SFormat::Map { key, value } => IFormat::Map {
272            key: format_to_format(&key).into(),
273            value: format_to_format(&value).into(),
274        },
275        SFormat::Tuple(inner) => IFormat::Tuple(inner.iter().map(format_to_format).collect()),
276        SFormat::TupleArray { content, size } => IFormat::TupleArray {
277            content: format_to_format(&content).into(),
278            size: *size,
279        },
280    }
281}