i_codegen_types/
lib.rs

1use std::{borrow::Cow, collections::BTreeMap, fmt::Debug};
2
3use serde::{self, Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, Debug)]
6pub struct TypeRoot {
7    #[serde(rename = "f")]
8    pub file: String,
9    #[serde(rename = "l")]
10    pub line: u32,
11    #[serde(rename = "i")]
12    pub inner: Named<ContainerFormat>,
13    #[serde(rename = "e")]
14    pub extras: Vec<Named<ContainerFormat>>,
15}
16
17#[derive(Serialize, Deserialize)]
18pub struct Spanned<T> {
19    #[serde(rename = "$")]
20    pub value: T,
21    #[serde(rename = "_")]
22    #[serde(skip_serializing_if = "is_null_bytes", default)]
23    /// Location in file, byte offset
24    pub bytes: (usize, usize),
25}
26
27fn is_null_bytes(value: &(usize, usize)) -> bool {
28    value.0 == 0 && value.1 == 0
29}
30
31impl<T: Debug> Debug for Spanned<T> {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        f.write_fmt(format_args!("#{:?} ", self.bytes))?;
34        self.value.fmt(f)
35    }
36}
37
38/// Serde-based serialization format for anonymous "value" types.
39/// This is just the path respecting serde names into the container
40/// It gets replaced by the knowledge
41#[derive(Serialize, Deserialize, Debug)]
42pub enum Format {
43    Incomplete {
44        debug: String,
45    },
46    /// The name of a container.
47    TypeName(String),
48
49    // The formats of primitive types
50    Unit,
51    Bool,
52    I8,
53    I16,
54    I32,
55    I64,
56    I128,
57    ISIZE,
58    U8,
59    U16,
60    U32,
61    U64,
62    U128,
63    USIZE,
64    F32,
65    F64,
66    Char,
67    Str,
68    Bytes,
69
70    /// The format of `Option<T>`.
71    Option(Box<Format>),
72    /// Never actually instantiated
73    Never,
74    /// A sequence, e.g. the format of `Vec<Foo>`.
75    Seq(Box<Format>),
76    /// A map, e.g. the format of `BTreeMap<K, V>`.
77    Map {
78        key: Box<Format>,
79        value: Box<Format>,
80    },
81
82    /// A tuple, e.g. the format of `(Foo, Bar)`.
83    Tuple(Vec<Format>),
84    /// Alias for `(Foo, ... Foo)`.
85    /// E.g. the format of `[Foo; N]`.
86    TupleArray {
87        content: Box<Format>,
88        size: usize,
89    },
90}
91
92impl Format {
93    pub fn is_primitive(&self) -> bool {
94        match self {
95            // The formats of primitive types
96            Format::Unit
97            | Format::Bool
98            | Format::I8
99            | Format::I16
100            | Format::I32
101            | Format::I64
102            | Format::I128
103            | Format::ISIZE
104            | Format::U8
105            | Format::U16
106            | Format::U32
107            | Format::U64
108            | Format::U128
109            | Format::USIZE
110            | Format::F32
111            | Format::F64
112            | Format::Char
113            | Format::Str
114            | Format::Bytes => true,
115            _ => false,
116        }
117    }
118    pub fn is_typename(&self) -> Option<&str> {
119        match self {
120            Format::TypeName(name) => Some(name),
121            _ => None,
122        }
123    }
124    pub fn as_ident(&self) -> Cow<'static, str> {
125        Cow::Borrowed(match self {
126            Format::Incomplete { debug } => todo!("Unknown ident incomplete: {debug}"),
127            Format::TypeName(name) => return Cow::Owned(name.clone()),
128            Format::Unit => "Nil",
129            Format::Bool => "Bool",
130            Format::I8 => "I8",
131            Format::I16 => "I16",
132            Format::I32 => "I32",
133            Format::I64 => "I64",
134            Format::I128 => "I128",
135            Format::ISIZE => "ISIZE",
136            Format::U8 => "U8",
137            Format::U16 => "U16",
138            Format::U32 => "U32",
139            Format::U64 => "U64",
140            Format::U128 => "U128",
141            Format::USIZE => "USIZE",
142            Format::F32 => "F32",
143            Format::F64 => "F64",
144            Format::Char => "Char",
145            Format::Str => "Str",
146            Format::Bytes => "Bytes",
147            Format::Option(of) => return Cow::Owned(format!("{}_Option", of.as_ident())),
148            Format::Never => "Never",
149            Format::Seq(of) => return Cow::Owned(format!("{}_List", of.as_ident())),
150            Format::Map { key, value } => {
151                return Cow::Owned(format!("{}_{}_Map", key.as_ident(), value.as_ident()))
152            }
153            Format::Tuple(of) => {
154                return Cow::Owned(format!(
155                    "{}Tuple",
156                    of.iter()
157                        .flat_map(|v| [v.as_ident(), Cow::Borrowed("_")])
158                        .collect::<String>()
159                ))
160            }
161            Format::TupleArray { content, size } => {
162                return Cow::Owned(format!("{}_{}_TupleOf", content.as_ident(), size))
163            }
164        })
165    }
166    pub fn replace_incomplete(&mut self, replacement: Format) {
167        if let Format::Incomplete { .. } = self {
168            *self = replacement;
169            return;
170        }
171        if self.is_primitive() || self.is_typename().is_some() {
172            return;
173        }
174        match (self, replacement) {
175            (Format::Option(ref mut original), Format::Option(replacement)) => {
176                original.replace_incomplete(*replacement);
177            }
178            (Format::Seq(ref mut original), Format::Seq(replacement)) => {
179                original.replace_incomplete(*replacement);
180            }
181            (
182                Format::Map {
183                    ref mut key,
184                    ref mut value,
185                },
186                Format::Map {
187                    key: replace_key,
188                    value: replace_value,
189                },
190            ) => {
191                key.replace_incomplete(*replace_key);
192                value.replace_incomplete(*replace_value);
193            }
194            (Format::Tuple(ref mut original), Format::Tuple(replacement_vec)) => {
195                for (original_item, replacement) in original.iter_mut().zip(replacement_vec) {
196                    original_item.replace_incomplete(replacement);
197                }
198            }
199            (
200                Format::TupleArray {
201                    ref mut content, ..
202                },
203                Format::TupleArray {
204                    content: replacement_content,
205                    ..
206                },
207            ) => {
208                content.replace_incomplete(*replacement_content);
209            }
210            (original, replacement) => {
211                panic!("Failed to merge original and replacement:\n{original:#?}\nREPLACEMENT\n{replacement:#?}")
212            }
213        }
214    }
215}
216
217/// Serde-based serialization format for named "container" types.
218/// In Rust, those are enums and structs.
219#[derive(Serialize, Deserialize, Debug)]
220pub enum ContainerFormat {
221    /// An empty struct, e.g. `struct A`.
222    UnitStruct,
223    /// A struct with a single unnamed parameter, e.g. `struct A(u16)`
224    NewTypeStruct(Box<Format>),
225    /// A struct with several unnamed parameters, e.g. `struct A(u16, u32)`
226    TupleStruct(Vec<Format>),
227    /// A struct with named parameters, e.g. `struct A { a: Foo }`.
228    Struct(Vec<Named<Format>>),
229    /// An enum, that is, an enumeration of variants.
230    /// Each variant has a unique name and index within the enum.
231    Enum(BTreeMap<u32, Named<VariantFormat>>),
232}
233
234#[derive(Serialize, Deserialize, Debug)]
235/// Description of a variant in an enum.
236pub enum VariantFormat {
237    /// A variant without parameters, e.g. `A` in `enum X { A }`
238    Unit,
239    /// A variant with a single unnamed parameter, e.g. `A` in `enum X { A(u16) }`
240    NewType(Box<Format>),
241    /// A struct with several unnamed parameters, e.g. `A` in `enum X { A(u16, u32) }`
242    Tuple(Vec<Format>),
243    /// A struct with named parameters, e.g. `A` in `enum X { A { a: Foo } }`
244    Struct(Vec<Named<Format>>),
245}
246
247#[derive(Serialize, Deserialize, Debug)]
248/// A named value.
249/// Used for named parameters or variants.
250pub struct Named<T> {
251    #[serde(rename = "id")]
252    pub rust_ident: Spanned<String>,
253    #[serde(skip_serializing_if = "Option::is_none", default)]
254    #[serde(rename = "docs")]
255    pub rust_docs: Option<String>,
256    #[serde(skip_serializing_if = "Vec::is_empty", default)]
257    #[serde(rename = "sa")]
258    pub serde_attrs: Vec<Spanned<(Spanned<String>, Spanned<String>)>>,
259    #[serde(skip_serializing_if = "Vec::is_empty", default)]
260    #[serde(rename = "sf")]
261    pub serde_flags: Vec<Spanned<String>>,
262    #[serde(skip_serializing_if = "Vec::is_empty", default)]
263    #[serde(rename = "ca")]
264    pub codegen_attrs: Vec<Spanned<(Spanned<String>, Spanned<String>)>>,
265    #[serde(skip_serializing_if = "Vec::is_empty", default)]
266    #[serde(rename = "cf")]
267    pub codegen_flags: Vec<Spanned<String>>,
268    #[serde(rename = "$")]
269    pub value: T,
270}
271
272impl<T> Named<T> {
273    pub fn builtin(ident: &str, docs: &str, bytes: Option<(usize, usize)>, value: T) -> Self {
274        Named {
275            rust_ident: Spanned {
276                value: ident.to_string(),
277                bytes: bytes.unwrap_or_default(),
278            },
279            rust_docs: {
280                let docs = docs.trim();
281                if docs.is_empty() {
282                    None
283                } else {
284                    Some(docs.to_string())
285                }
286            },
287            serde_attrs: Vec::new(),
288            serde_flags: Vec::new(),
289            codegen_attrs: Vec::new(),
290            codegen_flags: Vec::new(),
291            value,
292        }
293    }
294}
295
296#[derive(Serialize, Deserialize, Debug)]
297pub enum EnumRepresentation {
298    /// The default
299    /// e.g `{ User: { id: 1200, name: "Smithy" } }`
300    External,
301    /// e.g `{ id: 1200, name: "Smithy" }`
302    Untagged,
303    /// e.g `{ type: "User", id: 1200, name: "Smithy" }`
304    /// e.g `{ type: "User", content: { id: 1200, name: "Smithy" } }`
305    Tagged {
306        tag: Spanned<String>,
307        content: Option<Spanned<String>>,
308    },
309}
310
311impl<T> Named<T> {
312    pub fn serialize_name(&self) -> &str {
313        self.serde_attrs
314            .iter()
315            .filter_map(|attr| {
316                if attr.value.0.value == "rename" {
317                    Some(&attr.value.1.value)
318                } else {
319                    None
320                }
321            })
322            .last()
323            .unwrap_or(&self.rust_ident.value)
324    }
325}