i_codegen_code/
types.rs

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