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 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#[derive(Serialize, Deserialize, Debug)]
42pub enum Format {
43 Incomplete {
44 debug: String,
45 },
46 TypeName(String),
48
49 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 Option(Box<Format>),
72 Never,
74 Seq(Box<Format>),
76 Map {
78 key: Box<Format>,
79 value: Box<Format>,
80 },
81
82 Tuple(Vec<Format>),
84 TupleArray {
87 content: Box<Format>,
88 size: usize,
89 },
90}
91
92impl Format {
93 pub fn is_primitive(&self) -> bool {
94 match self {
95 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#[derive(Serialize, Deserialize, Debug)]
220pub enum ContainerFormat {
221 UnitStruct,
223 NewTypeStruct(Box<Format>),
225 TupleStruct(Vec<Format>),
227 Struct(Vec<Named<Format>>),
229 Enum(BTreeMap<u32, Named<VariantFormat>>),
232}
233
234#[derive(Serialize, Deserialize, Debug)]
235pub enum VariantFormat {
237 Unit,
239 NewType(Box<Format>),
241 Tuple(Vec<Format>),
243 Struct(Vec<Named<Format>>),
245}
246
247#[derive(Serialize, Deserialize, Debug)]
248pub 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 External,
301 Untagged,
303 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}