1pub mod rustfmt;
2
3use arora_module_core::{
4 header::generate_header_file, ImportAsset, ModuleAsset, ModuleDeclarationError,
5};
6use arora_registry::{
7 local::LocalRegistry, EnumerationFrozen, ModuleFrozen, ReadableRegistry, RegistryError,
8 StructureFrozen, TypeDefinitionFrozen,
9};
10use arora_types::record::ty::PrimitiveKind;
11use arora_types::record::{
12 module::frozen::{ExportKind, Parameter},
13 ty::{FrozenScalar, FrozenTy, Primitive},
14 FrozenReference,
15};
16use arora_types::record::{RecordType, Selector};
17use arora_types::ty::{
18 BOOLEAN_ID, F32_ID, F64_ID, I16_ID, I32_ID, I64_ID, I8_ID, STRING_ID, U16_ID, U32_ID, U64_ID,
19 U8_ID, UNIT_ID,
20};
21use arora_vfs::{Directory, Entry as VfsEntry, File, VfsError};
22use async_recursion::async_recursion;
23use convert_case::{Case, Casing};
24use derive_more::Display;
25use proc_macro2::Ident;
26use quote::{__private::TokenStream, format_ident, quote, ToTokens};
27use semver::VersionReq;
28use std::{
29 collections::{hash_map::Entry, HashMap, HashSet},
30 fmt::Display,
31 path,
32};
33use uuid::Uuid;
34
35pub async fn generate_sources(
39 assets: Vec<ModuleAsset>,
40 registry: &mut dyn ReadableRegistry,
41) -> Result<Directory, GenerationError> {
42 let mut result = generate_common_sources()?;
43 let mut imports_by_module: HashMap<Uuid, Vec<ImportAsset>> = HashMap::new();
44 let mut current_module = Option::<(Uuid, ModuleFrozen, String)>::None;
45 for asset in assets {
46 match asset {
47 ModuleAsset::Type(id, _, ty) => match ty {
48 TypeDefinitionFrozen::Primitive(_kind) => {}
49 TypeDefinitionFrozen::Enumeration(enumeration) => {
50 let parent_path = registry
51 .resolve_id(&enumeration.parent)
52 .await
53 .map_err(GenerationError::RegistryError)?;
54 let enum_sources = generate_enumeration_source(&id, &enumeration, &parent_path)
55 .map_err(GenerationError::VfsError)?;
56 result = result.merge_with(&enum_sources);
57 }
58 TypeDefinitionFrozen::Structure(structure) => {
59 let parent_path = registry
60 .resolve_id(&structure.parent)
61 .await
62 .map_err(GenerationError::RegistryError)?;
63 let struct_sources =
64 generate_structure_source(&id, &structure, registry, &parent_path).await?;
65 result = result.merge_with(&struct_sources);
66 }
67 },
68 ModuleAsset::Import(import) => {
69 match imports_by_module.entry(import.module_id.to_owned()) {
70 Entry::Occupied(mut entry) => entry.get_mut().push(import),
71 Entry::Vacant(entry) => {
72 entry.insert(vec![import]);
73 }
74 }
75 }
76 ModuleAsset::Module(ref module_id, _, ref module, ref executor) => {
77 let module_sources = generate_module_source(module, registry).await?;
78 result = result.merge_with(&module_sources);
79 assert!(current_module.is_none()); current_module =
81 Some((module_id.to_owned(), module.to_owned(), executor.to_owned()));
82 }
83 }
84 }
85
86 let mut all_imports = Vec::new();
87 for (module_id, ref mut imports) in imports_by_module {
88 let module_path = registry
90 .resolve_id(&module_id)
91 .await
92 .map_err(GenerationError::RegistryError)?;
93 let imports_sources =
94 generate_imports_from_module_source(&module_id, &module_path, imports, registry)
95 .await?;
96 result = result.merge_with(&imports_sources);
97 all_imports.append(imports);
98 }
99
100 let current_module = current_module.unwrap();
102 result = result.merge_with(
103 &generate_header_file(
104 ¤t_module.0,
105 ¤t_module.1,
106 &all_imports,
107 ¤t_module.2,
108 )
109 .map_err(GenerationError::ModuleDeclarationError)?,
110 );
111
112 let engine_functions_declarations = quote! {
117 #[cfg(target_arch = "wasm32")]
118 #[link(wasm_import_module = "env")]
119 extern "C" {
120 pub fn arora_dispatch(module_id: usize, method_id: usize, arg: usize) -> usize;
121 pub fn arora_dispatch_indirect(callable_id: u64) -> usize;
122 }
123
124 #[cfg(not(target_arch = "wasm32"))]
125 pub unsafe extern "C" fn arora_dispatch(
126 _module_id: usize,
127 _method_id: usize,
128 _arg: usize,
129 ) -> usize {
130 panic!(
131 "arora_dispatch called on the host; this module is meant to run as a wasm guest under the arora engine"
132 );
133 }
134
135 #[cfg(not(target_arch = "wasm32"))]
136 pub unsafe extern "C" fn arora_dispatch_indirect(_callable_id: u64) -> usize {
137 panic!(
138 "arora_dispatch_indirect called on the host; this module is meant to run as a wasm guest under the arora engine"
139 );
140 }
141 };
142 result = result.merge_with(
143 &token_stream_to_file("arora.rs", &engine_functions_declarations)
144 .map_err(GenerationError::VfsError)?,
145 );
146
147 generate_mods_in_directories(&mut result)?;
149
150 Ok(result)
151}
152
153pub fn generate_mods_in_directories(dir: &mut Directory) -> Result<bool, GenerationError> {
156 let mut mods = Vec::new();
157 for (path, entry) in dir.list_mut() {
158 if let VfsEntry::Directory(ref mut dir) = entry {
159 if generate_mods_in_directories(dir)? {
160 mods.push(path);
161 }
162 } else {
163 if path.ends_with(".rs") {
164 mods.push(path[..path.len() - 3].to_string());
165 }
166 }
167 }
168 if !mods.is_empty() {
169 let mods = mods
170 .into_iter()
171 .map(|mod_name| format_ident!("{}", mod_name.to_case(Case::Snake)));
172 let tokens = quote! {
173 #(pub mod #mods;)*
174 };
175 dir.insert("mod.rs", File::new(tokens.to_string()))
176 .map_err(GenerationError::VfsError)?;
177 Ok(true)
178 } else {
179 Ok(false)
180 }
181}
182
183pub fn generate_records(
187 assets: &[ModuleAsset],
188 registry: &LocalRegistry,
189) -> Result<Directory, GenerationError> {
190 use arora_registry::local::ROOT_ID;
191
192 let mut vfs = Directory::new();
193 vfs.ensure_directories(&path::PathBuf::from("folder"))
194 .map_err(GenerationError::VfsError)?;
195 vfs.ensure_directories(&path::PathBuf::from("enumeration"))
196 .map_err(GenerationError::VfsError)?;
197 vfs.ensure_directories(&path::PathBuf::from("structure"))
198 .map_err(GenerationError::VfsError)?;
199
200 let mut json_records: Vec<serde_json::Value> = vec![
201 serde_json::json!({"id": UNIT_ID.to_string(), "name": "unit"}),
202 serde_json::json!({"id": BOOLEAN_ID.to_string(), "name": "bool"}),
203 serde_json::json!({"id": U8_ID.to_string(), "name": "u8"}),
204 serde_json::json!({"id": U16_ID.to_string(), "name": "u16"}),
205 serde_json::json!({"id": U32_ID.to_string(), "name": "u32"}),
206 serde_json::json!({"id": U64_ID.to_string(), "name": "u64"}),
207 serde_json::json!({"id": I8_ID.to_string(), "name": "i8"}),
208 serde_json::json!({"id": I16_ID.to_string(), "name": "i16"}),
209 serde_json::json!({"id": I32_ID.to_string(), "name": "i32"}),
210 serde_json::json!({"id": I64_ID.to_string(), "name": "i64"}),
211 serde_json::json!({"id": F32_ID.to_string(), "name": "f32"}),
212 serde_json::json!({"id": F64_ID.to_string(), "name": "f64"}),
213 serde_json::json!({"id": STRING_ID.to_string(), "name": "str"}),
214 ];
215 let primitive_count = json_records.len();
219
220 let mut seen_folders: HashSet<Uuid> = HashSet::new();
221
222 for asset in assets {
223 let (id, version, ty) = match asset {
224 ModuleAsset::Type(id, version, ty) => (id, version, ty),
225 _ => continue,
226 };
227
228 match ty {
229 TypeDefinitionFrozen::Primitive(_) => {}
230 TypeDefinitionFrozen::Enumeration(e) => {
231 let yaml = serde_yaml::to_string(e)
232 .map_err(|err| GenerationError::Generic(err.to_string()))?;
233 let file_name = format!("{}@{}.yaml", id, version);
234 vfs.insert_at_path(
235 path::PathBuf::from("enumeration").join(&file_name),
236 File::new(yaml.as_bytes()),
237 )
238 .map_err(GenerationError::VfsError)?;
239
240 let mut entry = serde_json::json!({"id": id.to_string(), "name": e.name});
241 if e.parent != ROOT_ID {
242 entry["parent"] = serde_json::json!(e.parent.to_string());
243 }
244 json_records.push(entry);
245 add_folder_chain(
246 &e.parent,
247 registry,
248 &mut vfs,
249 &mut json_records,
250 &mut seen_folders,
251 )?;
252 }
253 TypeDefinitionFrozen::Structure(s) => {
254 let yaml = serde_yaml::to_string(s)
255 .map_err(|err| GenerationError::Generic(err.to_string()))?;
256 let file_name = format!("{}@{}.yaml", id, version);
257 vfs.insert_at_path(
258 path::PathBuf::from("structure").join(&file_name),
259 File::new(yaml.as_bytes()),
260 )
261 .map_err(GenerationError::VfsError)?;
262
263 let mut entry = serde_json::json!({"id": id.to_string(), "name": s.name});
264 if s.parent != ROOT_ID {
265 entry["parent"] = serde_json::json!(s.parent.to_string());
266 }
267 json_records.push(entry);
268 add_folder_chain(
269 &s.parent,
270 registry,
271 &mut vfs,
272 &mut json_records,
273 &mut seen_folders,
274 )?;
275 }
276 }
277 }
278
279 json_records[primitive_count..].sort_by(|a, b| a["id"].as_str().cmp(&b["id"].as_str()));
282
283 let records_json = serde_json::to_string(&json_records)
284 .map_err(|err| GenerationError::Generic(err.to_string()))?;
285 vfs.insert("records.json", File::new(records_json.as_bytes()))
286 .map_err(GenerationError::VfsError)?;
287
288 Ok(vfs)
289}
290
291fn add_folder_chain(
292 folder_id: &Uuid,
293 registry: &LocalRegistry,
294 vfs: &mut Directory,
295 json_records: &mut Vec<serde_json::Value>,
296 seen: &mut HashSet<Uuid>,
297) -> Result<(), GenerationError> {
298 use arora_registry::local::ROOT_ID;
299
300 if *folder_id == ROOT_ID || seen.contains(folder_id) {
301 return Ok(());
302 }
303
304 let Some((name, parent_opt)) = registry.record_name_and_parent(folder_id) else {
305 return Ok(());
306 };
307
308 seen.insert(*folder_id);
309
310 let yaml = match parent_opt {
311 Some(p) => format!("name: {}\nparent: {}\n", name, p),
312 None => format!("name: {}\n", name),
313 };
314 let file_name = format!("{}.yaml", folder_id);
315 vfs.insert_at_path(
316 path::PathBuf::from("folder").join(&file_name),
317 File::new(yaml.as_bytes()),
318 )
319 .map_err(GenerationError::VfsError)?;
320
321 let mut entry = serde_json::json!({"id": folder_id.to_string(), "name": name});
322 if let Some(p) = parent_opt {
323 if p != ROOT_ID {
324 entry["parent"] = serde_json::json!(p.to_string());
325 }
326 add_folder_chain(&p, registry, vfs, json_records, seen)?;
327 }
328 json_records.push(entry);
329
330 Ok(())
331}
332
333pub fn generate_common_sources() -> Result<Directory, GenerationError> {
334 let source = quote! {
335 use derive_more::Display;
336
337 #[derive(Display, Debug)]
338 pub struct DeserializationError {
339 #[display("deserialization error: {}", message)]
340 pub message: String,
341 }
342
343 impl std::error::Error for DeserializationError {}
344 };
345 token_stream_to_file("error.rs", &source).map_err(GenerationError::VfsError)
346}
347
348pub fn generate_enumeration_source(
353 id: &Uuid,
354 enumeration: &EnumerationFrozen,
355 parent_path: &str,
356) -> Result<Directory, VfsError> {
357 let uses = quote! {
358 use crate::arora_generated::error::DeserializationError;
359 use arora_buffers::*;
360 use arora_types::value::{ConversionError, Enumeration, Value};
361 use uuid::Uuid;
362 };
363
364 let name = &enumeration.name;
366 let enum_name = name.to_case(Case::UpperCamel);
367 let enum_ident = type_ident(&enum_name);
368 let variants = enumeration.variants.iter();
369 let enum_contents = variants.clone().map(|(_, variant)| {
370 let variant_ident = format_ident!("{}", variant.name.to_case(Case::UpperCamel));
371 quote! { #variant_ident, }
372 });
373 let enum_declaration = quote! {
374 #[derive(Debug, PartialEq, Clone)]
375 pub enum #enum_ident {
376 #(#enum_contents)*
377 }
378 };
379
380 let enum_id = id.to_string();
382 let enum_id_bytes = RawUuidValue(id);
383 let enum_upper_name = format_ident!("{}", enum_name.to_case(Case::UpperSnake));
384 let enum_const_id_ident = format_ident!("{}_ENUM_RAW_ID", enum_upper_name);
385 let enum_const_id_doc = format!("{}: {}", enum_name, enum_id);
386 let enum_id_declaration = quote! {
387 #[doc = #enum_const_id_doc]
388 pub const #enum_const_id_ident: [u8; 16] = #enum_id_bytes;
389 };
390
391 let variant_id_declarations = variants.clone().map(|(id, variant)| {
392 let id_string = id.to_string();
393 let id_bytes = RawUuidValue(id);
394 let variant_const_id_ident = enum_variant_const_id_ident(&enum_name, &variant.name);
395 let variant_doc = format!(
396 "{}: {}",
397 enum_variant_ident(&enum_name, &variant.name),
398 id_string
399 );
400 quote! {
401 #[doc = #variant_doc]
402 pub const #variant_const_id_ident: [u8; 16] = #id_bytes;
403 }
404 });
405
406 let serialization_match_branches: Vec<TokenStream> = variants
408 .clone()
409 .map(|(_, variant)| {
410 let variant_ident = enum_variant_ident(&enum_name, &variant.name);
411 let id_ident = enum_variant_const_id_ident(&enum_name, &variant.name);
412 quote! {
413 #variant_ident => #id_ident.as_slice(),
414 }
415 })
416 .collect();
417
418 let into_impl = generate_into_impl(&enum_ident);
419 let serialization = quote! {
420 #into_impl
421
422 pub fn serialize_to_writer(value: &#enum_ident, writer: &mut BufferWriter) {
423 let enumeration_id = #enum_const_id_ident.as_slice();
424 let variant_id = match value {
425 #(#serialization_match_branches)*
426 };
427 writer.add_enumeration_value(enumeration_id, variant_id);
428 writer.add_unit();
429 }
430
431 pub fn serialize_to_writer_raw(value: &#enum_ident, writer: &mut BufferWriter) {
437 let variant_id = match value {
438 #(#serialization_match_branches)*
439 };
440 writer.add_enumeration_value_raw(variant_id);
441 writer.add_unit();
442 }
443 };
444
445 let deserialization_cases = variants.clone().map(|(_, variant)| {
447 let variant_const_id_ident = enum_variant_const_id_ident(&enum_name, &variant.name);
448 let variant_ident = enum_variant_ident(&enum_name, &variant.name);
449 quote! {
450 #variant_const_id_ident => Ok(#variant_ident),
451 }
452 });
453
454 let deserialization = quote! {
455 impl TryFrom<&[u8]> for #enum_ident {
456 type Error = DeserializationError;
457
458 fn try_from(buffer: &[u8]) -> Result<Self, Self::Error> {
459 let mut reader = BufferReader::new(buffer);
460 return deserialize_from_reader(&mut reader, true)
461 }
462 }
463
464 pub fn deserialize_from_reader(reader: &mut BufferReader, check_type: bool) -> Result<#enum_ident, DeserializationError> {
465 if check_type {
466 let type_raw_id_opt = reader.next_type();
467 if type_raw_id_opt.is_none() {
468 return Err(DeserializationError{ message: "missing next type information".to_string() })
469 }
470 if type_raw_id_opt.unwrap() != TYPE_ENUMERATION {
471 return Err(DeserializationError{ message: "next type is not an enumeration".to_string() })
472 }
473 if #enum_const_id_ident != reader.get_structure_field() {
477 return Err(DeserializationError{ message: "missing variant information".to_string() })
478 }
479 }
480
481 let variant_raw_id = reader.get_enumeration_value_raw();
482 reader.next_type();
487 match variant_raw_id.try_into().expect("enum id is of unexpected length") {
488 #(#deserialization_cases)*
489 _ => Err(DeserializationError{ message: "unexpected variant".to_string() })
490 }
491 }
492 };
493
494 let to_value_cases = variants.clone().map(|(_, variant)| {
496 let variant_ident = enum_variant_ident(&enum_name, &variant.name);
497 let id_ident = enum_variant_const_id_ident(&enum_name, &variant.name);
498 quote! {
499 #variant_ident => Value::Enumeration(Enumeration {
500 id: Uuid::from_bytes(#enum_const_id_ident),
501 variant_id: Uuid::from_bytes(#id_ident),
502 value: Box::new(Value::Unit),
503 }),
504 }
505 });
506
507 let to_value = quote! {
508 impl Into<Value> for #enum_ident {
509 fn into(self) -> Value {
510 match self {
511 #(#to_value_cases)*
512 }
513 }
514 }
515 };
516
517 let from_value_cases = variants.map(|(_, variant)| {
519 let variant_const_id_ident = enum_variant_const_id_ident(&enum_name, &variant.name);
520 let variant_ident = enum_variant_ident(&enum_name, &variant.name);
521 quote! {
522 #variant_const_id_ident => Ok(#variant_ident),
523 }
524 });
525
526 let from_value = quote! {
527 impl TryFrom<Value> for #enum_ident {
528 type Error = ConversionError;
529 fn try_from(value: Value) -> Result<Self, Self::Error> {
530 if let Value::Enumeration(as_enum) = value {
531 if *as_enum.id.as_bytes() == #enum_const_id_ident {
532 match *as_enum.variant_id.as_bytes() {
533 #(#from_value_cases)*
534 _ => Err(Self::Error { message: "unexpected variant".to_string() }),
535 }
536 } else {
537 Err(Self::Error {
538 message: "unexpected enum type ID".to_string(),
539 })
540 }
541 } else {
542 Err(Self::Error {
543 message: "unexpected kind".to_string(),
544 })
545 }
546 }
547 }
548 };
549
550 let type_source = quote! {
552 #uses
553 #enum_declaration
554 #serialization
555 #deserialization
556 #to_value
557 #from_value
558 #enum_id_declaration
559 #(#variant_id_declarations)*
560 };
561
562 let base_file_name = enumeration.name.to_case(Case::Snake);
563 let file_path = if parent_path.is_empty() {
564 format!("{}.rs", base_file_name)
565 } else {
566 format!("{}/{}.rs", parent_path.replace('.', "/"), base_file_name)
567 };
568 token_stream_to_file(file_path, &type_source)
569}
570
571pub async fn generate_structure_source(
576 id: &Uuid,
577 structure: &StructureFrozen,
578 registry: &mut dyn ReadableRegistry,
579 parent_path: &str,
580) -> Result<Directory, GenerationError> {
581 let name = &structure.name;
583 let struct_ident = type_ident(name);
584 let is_self_ref = |field: &arora_types::record::structure::frozen::StructureField| matches!(&field.ty, FrozenTy::FrozenScalar(scalar) if scalar.reference.id == *id);
589 let mut field_declarations = Vec::new();
590 for (_, field) in &structure.fields {
591 let field_ident = variable_ident(&field.name);
592 let mut field_type_ident =
593 type_ident_from_frozen(&field.ty, registry, PrefixWithMod::Yes).await?;
594 if is_self_ref(field) {
595 field_type_ident = quote! { Box<#field_type_ident> };
596 }
597 field_declarations.push(quote! { pub #field_ident: #field_type_ident });
598 }
599 let struct_declaration = quote! {
600 #[derive(Debug, PartialEq, Clone)]
601 pub struct #struct_ident {
602 #(#field_declarations),*
603 }
604 };
605
606 let id_str = id.to_string();
608 let id_bytes = RawUuidValue(id);
609 let upper_name = format_ident!("{}", name.to_case(Case::UpperSnake));
610 let const_id_ident = format_ident!("{}_STRUCT_RAW_ID", upper_name);
611 let const_id_doc = format!("{}: {}", name, id_str);
612 let id_declaration = quote! {
613 #[doc = #const_id_doc]
614 pub const #const_id_ident: [u8; 16] = #id_bytes;
615 };
616
617 let field_id_declarations = structure.fields.iter().map(|(field_id, field)| {
618 let field_id_bytes = RawUuidValue(field_id);
619 let field_const_id_ident = struct_field_const_id_ident(name, &field.name);
620 let field_doc = format!("{}: {}", struct_field_ident(name, &field.name), field_id,);
621 quote! {
622 #[doc = #field_doc]
623 pub const #field_const_id_ident: [u8; 16] = #field_id_bytes;
624 }
625 });
626
627 let mut fields_serialization = Vec::new();
629 for (_, field) in &structure.fields {
630 let field_const_id_ident = struct_field_const_id_ident(name, &field.name);
631 let field_ident = variable_ident(&field.name);
632 let value_expression = quote! { value.#field_ident };
633 let serialize =
634 generate_serialize_from_frozen(&field.ty, value_expression, registry).await?;
635 fields_serialization.push(quote! {
639 writer.add_structure_field(&#field_const_id_ident);
640 #serialize;
641 });
642 }
643 let field_count = fields_serialization.len() as u32;
644
645 let into_impl = generate_into_impl(&struct_ident);
646 let serialization = quote! {
647 #into_impl
648
649 pub fn serialize_to_writer(value: &#struct_ident, writer: &mut BufferWriter) {
650 let structure_id = #const_id_ident.as_slice();
651 writer.begin_structure(structure_id, #field_count);
652 #(#fields_serialization)*
653 }
654
655 pub fn serialize_to_writer_raw(value: &#struct_ident, writer: &mut BufferWriter) {
663 writer.begin_structure_raw(#field_count);
664 #(#fields_serialization)*
665 }
666 };
667
668 let mut field_variable_declarations = Vec::new();
672 for (_, field) in &structure.fields {
673 let variable_ident = struct_field_intermediate_variable_ident(name, &field.name);
674 let mut type_ident =
675 type_ident_from_frozen(&field.ty, registry, PrefixWithMod::Yes).await?;
676 if is_self_ref(field) {
677 type_ident = quote! { Box<#type_ident> };
678 }
679 field_variable_declarations
680 .push(quote! { let mut #variable_ident: Option<#type_ident> = None; });
681 }
682
683 let mut deserialization_cases = Vec::new();
684 for (_, field) in &structure.fields {
685 let field_const_id_ident = struct_field_const_id_ident(name, &field.name);
686 let field_variable_ident = struct_field_intermediate_variable_ident(name, &field.name);
687 let deserialize =
688 generate_deserialize_from_frozen(&field.ty, registry, CheckType::Yes).await?;
689 let deserialize = if is_self_ref(field) {
690 quote! { Box::new(#deserialize) }
691 } else {
692 deserialize
693 };
694 deserialization_cases.push(quote! {
695 if field_raw_id == #field_const_id_ident {
696 #field_variable_ident = Some(#deserialize);
697 }
698 });
699 }
700
701 let struct_field_assignment = structure.fields.iter().map(|(_, field)| {
702 let field_ident = variable_ident(&field.name);
703 let variable_ident = struct_field_intermediate_variable_ident(name, &field.name);
704 quote! { #field_ident: #variable_ident.unwrap() }
705 });
706
707 let try_from_impl = generate_try_from_impl(&struct_ident);
708 let expected_field_count = structure.fields.len();
709 let deserialization = quote! {
710 #try_from_impl
711
712 pub fn deserialize_from_reader(reader: &mut BufferReader, check_type: bool) -> Result<#struct_ident, DeserializationError> {
713 let field_count = if check_type {
714 let type_raw_id_opt = reader.next_type();
715 if type_raw_id_opt.is_none() {
716 return Err(DeserializationError{ message: "missing next type information".to_string() })
717 }
718 if type_raw_id_opt.unwrap() != TYPE_STRUCTURE {
719 return Err(DeserializationError{ message: "next type is not a structure".to_string() })
720 }
721 let (structure_raw_id, field_count) = reader.get_structure();
722 if #const_id_ident != structure_raw_id {
723 return Err(DeserializationError{ message: "structure id does not match".to_string() })
724 }
725 field_count
726 } else {
727 reader.get_structure_raw()
728 };
729 if #expected_field_count != field_count as usize {
730 return Err(DeserializationError{
731 message: format!("expected {} fields, found {}", #expected_field_count, field_count)
732 })
733 }
734
735 #(#field_variable_declarations)*
736 for _ in 0..field_count {
737 let field_raw_id = reader.get_structure_field();
738 #(#deserialization_cases) else* else {
739 return Err(DeserializationError {
740 message: format!("unexpected struct field {}", Uuid::from_slice(field_raw_id).unwrap().to_string())
741 })
742 }
743 }
744
745 Ok(#struct_ident {
746 #(#struct_field_assignment,)*
747 })
748 }
749 };
750
751 let mut to_value_fields = Vec::new();
755 for (_, field) in &structure.fields {
756 let field_ident = variable_ident(&field.name);
757 let field_const_id_ident = struct_field_const_id_ident(name, &field.name);
758 let field_access = if is_self_ref(field) {
760 quote! { *self.#field_ident }
761 } else {
762 quote! { self.#field_ident }
763 };
764 let field_value = generate_value_from_frozen(&field.ty, field_access, registry).await?;
765 to_value_fields.push(quote! {
766 StructureField {
767 id: Uuid::from_bytes(#field_const_id_ident),
768 value: Box::new(#field_value),
769 }
770 });
771 }
772 let to_value = quote! {
773 impl Into<Value> for #struct_ident {
774 fn into(self) -> Value {
775 Value::Structure(Structure {
776 id: Uuid::from_bytes(#const_id_ident),
777 fields: vec![#(#to_value_fields),*],
778 })
779 }
780 }
781 };
782
783 let mut from_value_field_vars = Vec::new();
784 let mut from_value_cases = Vec::new();
785 let mut from_value_assignments = Vec::new();
786 for (_, field) in &structure.fields {
787 let field_ident = variable_ident(&field.name);
788 let field_const_id_ident = struct_field_const_id_ident(name, &field.name);
789 let field_var = struct_field_intermediate_variable_ident(name, &field.name);
790 let mut field_type_ident =
791 type_ident_from_frozen(&field.ty, registry, PrefixWithMod::Yes).await?;
792 let extract = generate_field_from_value_frozen(
793 &field.ty,
794 quote! { *field.value },
795 &field.name,
796 registry,
797 )
798 .await?;
799 let extract = if is_self_ref(field) {
800 field_type_ident = quote! { Box<#field_type_ident> };
801 quote! { Box::new(#extract) }
802 } else {
803 extract
804 };
805 from_value_field_vars
806 .push(quote! { let mut #field_var: Option<#field_type_ident> = None; });
807 from_value_cases.push(quote! { #field_const_id_ident => { #field_var = Some(#extract); } });
808 let missing_message = format!("missing field {}", field.name);
809 from_value_assignments.push(quote! {
810 #field_ident: #field_var.ok_or_else(|| ConversionError { message: #missing_message.to_string() })?
811 });
812 }
813 let from_value = quote! {
814 impl TryFrom<Value> for #struct_ident {
815 type Error = ConversionError;
816 fn try_from(value: Value) -> Result<Self, Self::Error> {
817 if let Value::Structure(as_struct) = value {
818 if *as_struct.id.as_bytes() != #const_id_ident {
819 return Err(ConversionError { message: "unexpected structure type ID".to_string() });
820 }
821 #(#from_value_field_vars)*
822 for field in as_struct.fields {
823 match *field.id.as_bytes() {
824 #(#from_value_cases)*
825 _ => return Err(ConversionError { message: "unexpected struct field".to_string() }),
826 }
827 }
828 Ok(#struct_ident {
829 #(#from_value_assignments,)*
830 })
831 } else {
832 Err(ConversionError { message: "unexpected kind".to_string() })
833 }
834 }
835 }
836 };
837
838 let references_generated_modules = structure.fields.values().any(|field| match &field.ty {
843 FrozenTy::Primitive(_) => false,
844 FrozenTy::FrozenScalar(scalar) => !is_dynamic_value_id(&scalar.reference.id),
845 FrozenTy::FrozenArray(array) => !is_dynamic_value_id(&array.reference.id),
846 });
847 let generated_modules_use = if references_generated_modules {
848 quote! { use crate::arora_generated; }
849 } else {
850 quote! {}
851 };
852
853 let mut needs_structure_without_id = false;
858 let mut needs_enumeration_value_types = false;
859 for field in structure.fields.values() {
860 if let FrozenTy::FrozenArray(array) = &field.ty {
861 if is_dynamic_value_id(&array.reference.id) {
862 continue;
863 }
864 match registry
865 .type_of(&Selector::Id(array.reference.id.to_owned()))
866 .await
867 .map_err(GenerationError::RegistryError)?
868 {
869 RecordType::Structure => needs_structure_without_id = true,
870 RecordType::Enumeration => needs_enumeration_value_types = true,
871 _ => {}
872 }
873 }
874 }
875 let mut value_imports: Vec<TokenStream> = vec![
876 quote! { ConversionError },
877 quote! { Structure },
878 quote! { StructureField },
879 quote! { Value },
880 ];
881 if needs_structure_without_id {
882 value_imports.push(quote! { StructureWithoutId });
883 }
884 if needs_enumeration_value_types {
885 value_imports.push(quote! { Enumeration });
886 value_imports.push(quote! { EnumerationWithoutId });
887 }
888
889 let type_source = quote! {
890 use arora_buffers::*;
891 use uuid::Uuid;
892 use arora_types::value::{ #(#value_imports),* };
893 use crate::arora_generated::error::DeserializationError;
894 #generated_modules_use
895 #struct_declaration
896 #serialization
897 #deserialization
898 #to_value
899 #from_value
900 #id_declaration
901 #(#field_id_declarations)*
902 };
903
904 let base_file_name = structure.name.to_case(Case::Snake);
905 let file_path = if parent_path.is_empty() {
906 format!("{}.rs", base_file_name)
907 } else {
908 format!("{}/{}.rs", parent_path.replace('.', "/"), base_file_name)
909 };
910 token_stream_to_file(file_path, &type_source).map_err(GenerationError::VfsError)
911}
912
913async fn generate_imports_from_module_source(
917 module_id: &Uuid,
918 module_path: &str,
919 imports: &Vec<ImportAsset>,
920 registry: &mut dyn ReadableRegistry,
921) -> Result<Directory, GenerationError> {
922 let uses = {
924 let mut dependencies = HashSet::<&FrozenReference>::new();
925 for import in imports {
926 import.import.dependencies(&mut dependencies);
927 }
928 let mut uses = Vec::new();
929 for dep in dependencies {
930 let dep_selector = Selector::Id(dep.id);
931 let type_def = match registry
932 .get_type(
933 &dep_selector,
934 &VersionReq::parse(dep.version.to_string().as_str()).unwrap(),
935 )
936 .await
937 {
938 Ok(TypeDefinitionFrozen::Primitive(_)) => continue,
939 Ok(type_definition) => type_definition,
940 Err(RegistryError::NotAType { selector: _ }) => continue,
941 Err(err) => return Err(GenerationError::RegistryError(err)),
942 };
943 let type_ident =
944 type_ident_from_definition(&type_def, &dep.id, registry, PrefixWithMod::Yes)
945 .await?;
946 uses.push(type_ident);
947 }
948 uses
949 };
950
951 let splitted_module_path: Vec<&str> = module_path.split(".").collect();
952 let module_name = splitted_module_path.last().unwrap();
953
954 let module_const_id_ident =
956 format_ident!("{}_MODULE_ID", module_name.to_case(Case::UpperSnake),);
957 let module_id_declaration = generate_const_id_declaration(
958 &module_name.to_string(),
959 &module_const_id_ident,
960 module_id,
961 Public::No,
962 );
963
964 let mut functions_declarations = Vec::<TokenStream>::new();
966 for import in imports {
967 let ExportKind::Function(function_symbol) = &import.import.kind;
968 let function_name = &import.import.name;
969 let function_ident = format_ident!("{}", function_name);
970 let mut parameters_declarations = Vec::new();
971 for param in function_symbol.parameters.values() {
972 let maybe_mut = if param.mutable {
973 quote! { mut }
974 } else {
975 quote! {}
976 };
977 let param_name_ident = format_ident!("{}", param.name);
978 let param_type_ident =
979 type_ident_from_frozen(¶m.ty, registry, PrefixWithMod::Yes).await?;
980 parameters_declarations.push(quote! {
981 #maybe_mut #param_name_ident: #param_type_ident
982 });
983 }
984 let ret_type_ident =
985 type_ident_from_frozen(&function_symbol.return_ty, registry, PrefixWithMod::Yes)
986 .await?;
987
988 let function_const_id_ident = function_const_id_ident(function_name);
991 let function_id_declaration = generate_const_id_declaration(
992 function_name,
993 &function_const_id_ident,
994 &import.id,
995 Public::No,
996 );
997 let param_ids_declarations = {
998 let mut param_ids_declarations = Vec::new();
999 for (id, param) in &function_symbol.parameters {
1000 param_ids_declarations.push(generate_const_id_declaration(
1001 &format!("{}.{}", function_name, param.name),
1002 &function_param_const_id_ident(function_name, ¶m.name),
1003 id,
1004 Public::No,
1005 ));
1006 }
1007 param_ids_declarations
1008 };
1009
1010 let ids_declaration = quote! {
1011 #function_id_declaration
1012 #(#param_ids_declarations)*
1013 };
1014
1015 let add_args = {
1019 let mut add_args = Vec::new();
1020 for param in function_symbol.parameters.values() {
1021 let function_param_const_id_ident =
1022 function_param_const_id_ident(function_name, ¶m.name);
1023 let param_name_ident = format_ident!("{}", param.name);
1024 let serialize_arg = generate_serialize_from_frozen(
1025 ¶m.ty,
1026 param_name_ident.into_token_stream(),
1027 registry,
1028 )
1029 .await?;
1030 add_args.push(quote! {
1031 writer.add_structure_field(#function_param_const_id_ident.as_slice());
1032 #serialize_arg;
1033 });
1034 }
1035 add_args
1036 };
1037 let nof_args = add_args.len() as u32;
1038 let prepare_call_structure = quote! {
1039 let mut writer = BufferWriter::new();
1040 let writer = &mut writer;
1041 writer.begin_structure(#function_const_id_ident.as_slice(), #nof_args);
1042 #(#add_args)*
1043 let arg = writer.finalize();
1044 };
1045
1046 let perform_call = quote! {
1048 let result_buffer_addr = unsafe {
1049 arora_dispatch(
1050 #module_const_id_ident.as_ptr() as usize,
1051 #function_const_id_ident.as_ptr() as usize,
1052 arg.as_ptr() as usize,
1053 )
1054 };
1055 };
1056
1057 let prepare_parsing = quote! {
1059 let result_buffer_ptr = result_buffer_addr as *const u8;
1060 let input_size_bytes: &[u8; 4] =
1061 unsafe { std::slice::from_raw_parts(result_buffer_ptr, BUFFER_SIZE_SIZE) }
1062 .try_into()
1063 .expect("input is too small");
1064 let input_size = u32::from_le_bytes(*input_size_bytes) as usize;
1065 let input =
1066 unsafe { std::slice::from_raw_parts(result_buffer_ptr, BUFFER_SIZE_SIZE + input_size) };
1067 let mut reader = BufferReader::new(&input);
1068 let reader = &mut reader;
1069 };
1070
1071 let check_result_struct = quote! {
1073 let type_raw_id_opt = reader.next_type();
1074 assert!(!type_raw_id_opt.is_none());
1075 assert_eq!(type_raw_id_opt.unwrap(), TYPE_STRUCTURE);
1076 let (result_struct_id, result_field_count) = reader.get_structure();
1077 assert_eq!(result_struct_id, #function_const_id_ident);
1078 };
1079
1080 let deserialize_ret =
1085 generate_deserialize_from_frozen(&function_symbol.return_ty, registry, CheckType::Yes)
1086 .await?;
1087
1088 let process_params = if nof_args > 1 {
1089 let declare_mutable_params = {
1090 let mut declare_mutable_params = Vec::new();
1091 for param in function_symbol.parameters.values() {
1092 if param.mutable {
1093 let param_name_ident = format_ident!("{}", param.name);
1094 declare_mutable_params.push(quote! {
1095 let mut #param_name_ident = None;
1096 })
1097 }
1098 }
1099 declare_mutable_params
1100 };
1101
1102 let deserialize_params = {
1103 let mut deserialize_params = Vec::new();
1104 for param in function_symbol.parameters.values() {
1105 if param.mutable {
1106 let param_name_ident = format_ident!("{}", param.name);
1107 let function_param_const_id_ident =
1108 function_param_const_id_ident(function_name, ¶m.name);
1109 let deserialize_param =
1110 generate_deserialize_from_frozen(¶m.ty, registry, CheckType::Yes)
1111 .await?;
1112 deserialize_params.push(quote! {
1113 x if *x == #function_param_const_id_ident => *#param_name_ident = #deserialize_param,
1114 });
1115 }
1116 }
1117 deserialize_params
1118 };
1119
1120 quote! {
1121 #(#declare_mutable_params)*
1122 for _i in 1u32..#nof_args {
1123 let next_field_id = reader.get_structure_field();
1124 match next_field_id {
1125 #(#deserialize_params)*
1126 x => panic!("found unexpected mutated argument id: {:#?}", x),
1127 }
1128 }
1129 }
1130 } else {
1131 quote! {}
1132 };
1133
1134 let process_result = quote! {
1135 assert_eq!(result_field_count, #nof_args);
1136 let first_field_id = reader.get_structure_field();
1137 assert_eq!(first_field_id, #function_const_id_ident);
1138 let ret = #deserialize_ret;
1139 #process_params
1140 ret
1141 };
1142
1143 functions_declarations.push(quote! {
1145 pub fn #function_ident (#(#parameters_declarations),*) -> #ret_type_ident {
1146 #ids_declaration
1147 #prepare_call_structure
1148 #perform_call
1149 #prepare_parsing
1150 #check_result_struct
1151 #process_result
1152 }
1153 });
1154 }
1155
1156 let source = quote! {
1158 #(#uses)*
1159 use arora_buffers::*;
1160 use crate::arora_generated::arora::arora_dispatch;
1161 #module_id_declaration
1162 #(#functions_declarations)*
1163 };
1164
1165 let file_path = splitted_module_path
1166 .iter()
1167 .map(|name| name.to_case(Case::Snake))
1168 .fold(String::new(), |acc, name| {
1169 if acc.is_empty() {
1170 name
1171 } else {
1172 format!("{}/{}", acc, name)
1173 }
1174 })
1175 + ".rs";
1176 token_stream_to_file(file_path, &source).map_err(GenerationError::VfsError)
1177}
1178
1179async fn generate_module_source(
1181 module: &ModuleFrozen,
1182 registry: &mut dyn ReadableRegistry,
1183) -> Result<Directory, GenerationError> {
1184 let exports = &module.exports;
1186 let use_functions = exports
1187 .values()
1188 .map(|export| format_ident!("{}", export.name));
1189
1190 let function_ids = exports.iter().flat_map(|(function_id, export)| {
1192 let ExportKind::Function(function_symbol) = &export.kind;
1193 let mut id_declarations = Vec::with_capacity(function_symbol.parameters.len() + 1);
1194 id_declarations.push(generate_const_id_declaration(
1195 &export.name,
1196 &function_const_id_ident(&export.name),
1197 function_id,
1198 Public::Yes,
1199 ));
1200 for (param_id, param) in &function_symbol.parameters {
1201 id_declarations.push(generate_const_id_declaration(
1202 &format!("{}.{}", export.name, param.name),
1203 &function_param_const_id_ident(&export.name, ¶m.name),
1204 param_id,
1205 Public::Yes,
1206 ));
1207 }
1208 id_declarations
1209 });
1210
1211 let function_declarations = {
1213 let mut function_declarations = Vec::new();
1214 for (export_id, export) in exports {
1215 let function_ident = format_ident!("{}", export.name);
1216 let ExportKind::Function(function_symbol) = &export.kind;
1217 let const_id_ident = function_const_id_ident(&export.name);
1218
1219 let call_check = quote! {
1220 let mut reader = BufferReader::new(&input);
1221 let reader = &mut reader;
1222 let type_raw_id_opt = reader.next_type();
1223 if type_raw_id_opt.is_none() {
1224 return Err("input is empty".to_string());
1225 }
1226 if type_raw_id_opt.unwrap() != TYPE_STRUCTURE {
1227 return Err(format!("expected structure input, got type {:?}", type_raw_id_opt));
1228 }
1229 let (structure_raw_id, field_count) = reader.get_structure();
1230 if structure_raw_id != &#const_id_ident {
1231 return Err("function id mismatch in input".to_string());
1232 }
1233 };
1234
1235 let param_declarations = {
1236 let mut param_declarations = Vec::new();
1237 for (param_id, param) in &function_symbol.parameters {
1238 let param_var_ident = param_ident(param_id, param);
1239 let param_type_ident =
1240 type_ident_from_frozen(¶m.ty, registry, PrefixWithMod::Yes).await?;
1241 param_declarations.push(
1242 quote! { let mut #param_var_ident: Option<#param_type_ident> = None; },
1243 );
1244 }
1245 param_declarations
1246 };
1247
1248 let deserialization_cases = {
1249 let mut deserialization_cases = Vec::new();
1250 for (param_id, param) in &function_symbol.parameters {
1251 let param_const_id_ident =
1252 function_param_const_id_ident(&export.name, ¶m.name);
1253 let param_var_ident = param_ident(param_id, param);
1254 let deserialize =
1255 generate_deserialize_from_frozen(¶m.ty, registry, CheckType::YesResult)
1256 .await?;
1257 deserialization_cases.push(quote! {
1258 if field_raw_id == #param_const_id_ident {
1259 #param_var_ident = Some(#deserialize);
1260 }
1261 });
1262 }
1263 deserialization_cases
1264 };
1265
1266 let deserialize_params = if function_symbol.parameters.is_empty() {
1267 quote! {
1268 if field_count != 0 {
1269 return Err(format!("expected 0 parameters but got {}", field_count));
1270 }
1271 }
1272 } else {
1273 quote! {
1274 #(#param_declarations)*
1275 for _ in 0..field_count {
1276 let field_raw_id = reader.get_structure_field();
1277 #(#deserialization_cases else)* {
1278 return Err(format!("unexpected parameter {:?}", field_raw_id));
1279 }
1280 }
1281 }
1282 };
1283
1284 let param_args = function_symbol.parameter_ordering.iter().map(|param_id| {
1285 let param = function_symbol.parameters.get(param_id).unwrap();
1286 let param_var_ident = param_ident(param_id, param);
1287 if param.mutable {
1288 quote! { &mut #param_var_ident }
1289 } else {
1290 quote! { #param_var_ident }
1291 }
1292 });
1293
1294 let call_and_write_result = {
1295 let result_ident = match &function_symbol.return_ty {
1296 FrozenTy::Primitive(Primitive { kind }) if *kind == PrimitiveKind::Unit => {
1297 quote! { _ }
1298 }
1299 _ => quote! { result },
1300 };
1301 let serialize_result = generate_serialize_from_frozen(
1302 &function_symbol.return_ty,
1303 result_ident.clone(),
1304 registry,
1305 )
1306 .await?;
1307 quote! {
1308 let #result_ident = #function_ident (#(#param_args),*);
1309 #serialize_result;
1310 }
1311 };
1312
1313 let write_mutated_params: Vec<TokenStream> = {
1314 let mut write_mutated_params = Vec::new();
1315 for (param_id, param) in &function_symbol.parameters {
1316 if param.mutable {
1317 let param_var_ident = param_ident(param_id, param);
1318 let param_const_id_ident =
1319 function_param_const_id_ident(&export.name, ¶m.name);
1320 let serialize_param = generate_serialize_from_frozen(
1321 ¶m.ty,
1322 quote! {#param_var_ident.unwrap()},
1323 registry,
1324 )
1325 .await?;
1326 write_mutated_params.push(quote! {
1327 writer.add_structure_field(&#param_const_id_ident);
1328 #serialize_param;
1329 });
1330 }
1331 }
1332 write_mutated_params
1333 };
1334 let nof_mutated_params = write_mutated_params.len();
1335
1336 let uuid_suffix = export_id.to_string().replace("-", "_");
1337 let arora_function_ident = format_ident!("arora_function_{}", uuid_suffix);
1338 let doc = export.name.to_string();
1339 function_declarations.push(quote! {
1340 #[doc = #doc]
1341 #[no_mangle]
1342 pub extern "C" fn #arora_function_ident (input_addr: usize) -> usize {
1343 let input_ptr = input_addr as *const u8;
1344 const INPUT_SIZE_SIZE: usize = std::mem::size_of::<u32>();
1345 let input_size_bytes: &[u8; 4] = unsafe {
1346 std::slice::from_raw_parts(input_ptr, INPUT_SIZE_SIZE)
1347 }.try_into().expect("input is too small");
1348 let input_size = u32::from_le_bytes(*input_size_bytes) as usize;
1349 let input = unsafe {
1350 std::slice::from_raw_parts(input_ptr, INPUT_SIZE_SIZE + input_size)
1351 };
1352 let _result: ::std::result::Result<::std::boxed::Box<[u8]>, ::std::string::String> = (|| {
1353 #call_check
1354 #deserialize_params
1355 let mut writer = BufferWriter::new();
1356 let writer = &mut writer;
1357 writer.begin_structure(&#const_id_ident, (#nof_mutated_params + 1) as u32);
1358 writer.add_structure_field(&#const_id_ident);
1359 #call_and_write_result
1360 #(#write_mutated_params)*
1361 ::std::result::Result::Ok(writer.finalize())
1362 })();
1363 match _result {
1364 ::std::result::Result::Ok(buf) => ::std::boxed::Box::leak(buf).as_ptr() as usize,
1365 ::std::result::Result::Err(msg) => {
1366 let mut writer = BufferWriter::new();
1367 writer.add_error(&msg);
1368 ::std::boxed::Box::leak(writer.finalize()).as_ptr() as usize
1369 }
1370 }
1371 }
1372 });
1373 }
1374 function_declarations
1375 };
1376
1377 let source = quote! {
1379 use arora_buffers::*;
1380 use crate::{arora_generated, #(#use_functions),*};
1381 #(#function_declarations)*
1382 #(#function_ids)*
1383 };
1384 token_stream_to_file("export.rs", &source).map_err(GenerationError::VfsError)
1385}
1386
1387pub fn generate_into_impl(type_ident: &Ident) -> TokenStream {
1388 quote! {
1389 impl Into<Box<[u8]>> for #type_ident {
1390 fn into(self) -> Box<[u8]> {
1391 let mut writer = BufferWriter::new();
1392 serialize_to_writer(&self, &mut writer);
1393 writer.finalize()
1394 }
1395 }
1396 }
1397}
1398
1399pub fn generate_try_from_impl(type_ident: &Ident) -> TokenStream {
1400 quote! {
1401 impl TryFrom<&[u8]> for #type_ident {
1402 type Error = DeserializationError;
1403
1404 fn try_from(buffer: &[u8]) -> Result<Self, Self::Error> {
1405 let mut reader = BufferReader::new(buffer);
1406 return deserialize_from_reader(&mut reader, true)
1407 }
1408 }
1409 }
1410}
1411
1412async fn generate_value_from_frozen(
1416 ty: &FrozenTy,
1417 value_expression: TokenStream,
1418 registry: &mut dyn ReadableRegistry,
1419) -> Result<TokenStream, GenerationError> {
1420 Ok(match ty {
1421 FrozenTy::Primitive(primitive) => match primitive.kind {
1422 PrimitiveKind::Unit => quote! { Value::Unit },
1423 PrimitiveKind::Boolean => quote! { Value::Boolean(#value_expression) },
1424 PrimitiveKind::U8 => quote! { Value::U8(#value_expression) },
1425 PrimitiveKind::U16 => quote! { Value::U16(#value_expression) },
1426 PrimitiveKind::U32 => quote! { Value::U32(#value_expression) },
1427 PrimitiveKind::U64 => quote! { Value::U64(#value_expression) },
1428 PrimitiveKind::I8 => quote! { Value::I8(#value_expression) },
1429 PrimitiveKind::I16 => quote! { Value::I16(#value_expression) },
1430 PrimitiveKind::I32 => quote! { Value::I32(#value_expression) },
1431 PrimitiveKind::I64 => quote! { Value::I64(#value_expression) },
1432 PrimitiveKind::F32 => quote! { Value::F32(#value_expression) },
1433 PrimitiveKind::F64 => quote! { Value::F64(#value_expression) },
1434 PrimitiveKind::String => quote! { Value::String(#value_expression) },
1435 PrimitiveKind::ArrayBoolean => quote! { Value::ArrayBoolean(#value_expression) },
1436 PrimitiveKind::ArrayU8 => quote! { Value::ArrayU8(#value_expression) },
1437 PrimitiveKind::ArrayU16 => quote! { Value::ArrayU16(#value_expression) },
1438 PrimitiveKind::ArrayU32 => quote! { Value::ArrayU32(#value_expression) },
1439 PrimitiveKind::ArrayU64 => quote! { Value::ArrayU64(#value_expression) },
1440 PrimitiveKind::ArrayI8 => quote! { Value::ArrayI8(#value_expression) },
1441 PrimitiveKind::ArrayI16 => quote! { Value::ArrayI16(#value_expression) },
1442 PrimitiveKind::ArrayI32 => quote! { Value::ArrayI32(#value_expression) },
1443 PrimitiveKind::ArrayI64 => quote! { Value::ArrayI64(#value_expression) },
1444 PrimitiveKind::ArrayF32 => quote! { Value::ArrayF32(#value_expression) },
1445 PrimitiveKind::ArrayF64 => quote! { Value::ArrayF64(#value_expression) },
1446 PrimitiveKind::ArrayString => quote! { Value::ArrayString(#value_expression) },
1447 },
1448 FrozenTy::FrozenScalar(scalar) if is_dynamic_value_id(&scalar.reference.id) => {
1450 quote! { #value_expression }
1451 }
1452 FrozenTy::FrozenScalar(_) => quote! { Into::<Value>::into(#value_expression) },
1454 FrozenTy::FrozenArray(array) if is_dynamic_value_id(&array.reference.id) => {
1456 quote! { Value::ArrayValue(#value_expression.into_iter().collect()) }
1457 }
1458 FrozenTy::FrozenArray(array) => {
1463 let raw_id = RawUuidValue(&array.reference.id);
1464 match registry
1465 .type_of(&Selector::Id(array.reference.id.to_owned()))
1466 .await
1467 .map_err(GenerationError::RegistryError)?
1468 {
1469 RecordType::Structure => quote! {
1470 Value::ArrayStructure {
1471 id: Uuid::from_bytes(#raw_id),
1472 elements: #value_expression
1473 .into_iter()
1474 .map(|__element| match Into::<Value>::into(__element) {
1475 Value::Structure(__s) => StructureWithoutId { fields: __s.fields },
1476 _ => unreachable!("generated structure did not convert to Value::Structure"),
1477 })
1478 .collect(),
1479 }
1480 },
1481 RecordType::Enumeration => quote! {
1482 Value::ArrayEnumeration {
1483 id: Uuid::from_bytes(#raw_id),
1484 elements: #value_expression
1485 .into_iter()
1486 .map(|__element| match Into::<Value>::into(__element) {
1487 Value::Enumeration(__e) => EnumerationWithoutId {
1488 variant_id: __e.variant_id,
1489 value: __e.value,
1490 },
1491 _ => unreachable!("generated enumeration did not convert to Value::Enumeration"),
1492 })
1493 .collect(),
1494 }
1495 },
1496 _ => unreachable!("unexpected array element record type"),
1497 }
1498 }
1499 })
1500}
1501
1502#[async_recursion(?Send)]
1506async fn generate_field_from_value_frozen(
1507 ty: &FrozenTy,
1508 value_expression: TokenStream,
1509 field_name: &str,
1510 registry: &mut dyn ReadableRegistry,
1511) -> Result<TokenStream, GenerationError> {
1512 match ty {
1513 FrozenTy::Primitive(primitive) => {
1514 let mismatch = format!("field {}: unexpected value kind", field_name);
1515 let arm = match primitive.kind {
1516 PrimitiveKind::Unit => quote! { Value::Unit => () },
1517 PrimitiveKind::Boolean => quote! { Value::Boolean(__v) => __v },
1518 PrimitiveKind::U8 => quote! { Value::U8(__v) => __v },
1519 PrimitiveKind::U16 => quote! { Value::U16(__v) => __v },
1520 PrimitiveKind::U32 => quote! { Value::U32(__v) => __v },
1521 PrimitiveKind::U64 => quote! { Value::U64(__v) => __v },
1522 PrimitiveKind::I8 => quote! { Value::I8(__v) => __v },
1523 PrimitiveKind::I16 => quote! { Value::I16(__v) => __v },
1524 PrimitiveKind::I32 => quote! { Value::I32(__v) => __v },
1525 PrimitiveKind::I64 => quote! { Value::I64(__v) => __v },
1526 PrimitiveKind::F32 => quote! { Value::F32(__v) => __v },
1527 PrimitiveKind::F64 => quote! { Value::F64(__v) => __v },
1528 PrimitiveKind::String => quote! { Value::String(__v) => __v },
1529 PrimitiveKind::ArrayBoolean => quote! { Value::ArrayBoolean(__v) => __v },
1530 PrimitiveKind::ArrayU8 => quote! { Value::ArrayU8(__v) => __v },
1531 PrimitiveKind::ArrayU16 => quote! { Value::ArrayU16(__v) => __v },
1532 PrimitiveKind::ArrayU32 => quote! { Value::ArrayU32(__v) => __v },
1533 PrimitiveKind::ArrayU64 => quote! { Value::ArrayU64(__v) => __v },
1534 PrimitiveKind::ArrayI8 => quote! { Value::ArrayI8(__v) => __v },
1535 PrimitiveKind::ArrayI16 => quote! { Value::ArrayI16(__v) => __v },
1536 PrimitiveKind::ArrayI32 => quote! { Value::ArrayI32(__v) => __v },
1537 PrimitiveKind::ArrayI64 => quote! { Value::ArrayI64(__v) => __v },
1538 PrimitiveKind::ArrayF32 => quote! { Value::ArrayF32(__v) => __v },
1539 PrimitiveKind::ArrayF64 => quote! { Value::ArrayF64(__v) => __v },
1540 PrimitiveKind::ArrayString => quote! { Value::ArrayString(__v) => __v },
1541 };
1542 Ok(quote! {
1543 match #value_expression {
1544 #arm,
1545 _ => return Err(ConversionError { message: #mismatch.to_string() }),
1546 }
1547 })
1548 }
1549 FrozenTy::FrozenScalar(scalar) if is_dynamic_value_id(&scalar.reference.id) => {
1550 Ok(quote! { #value_expression })
1552 }
1553 FrozenTy::FrozenScalar(_) => {
1554 let type_ident = type_ident_from_frozen(ty, registry, PrefixWithMod::Yes).await?;
1555 Ok(quote! { <#type_ident as TryFrom<Value>>::try_from(#value_expression)? })
1556 }
1557 FrozenTy::FrozenArray(array) if is_dynamic_value_id(&array.reference.id) => {
1559 let mismatch = format!("field {}: expected array value", field_name);
1560 Ok(quote! {
1561 match #value_expression {
1562 Value::ArrayValue(__items) => __items,
1563 _ => return Err(ConversionError { message: #mismatch.to_string() }),
1564 }
1565 })
1566 }
1567 FrozenTy::FrozenArray(array) => {
1573 let type_ident =
1574 type_ident_from_id(&array.reference.id, registry, PrefixWithMod::Yes).await?;
1575 match registry
1576 .type_of(&Selector::Id(array.reference.id.to_owned()))
1577 .await
1578 .map_err(GenerationError::RegistryError)?
1579 {
1580 RecordType::Structure => {
1581 let mismatch = format!("field {}: expected array of structures", field_name);
1582 Ok(quote! {
1583 match #value_expression {
1584 Value::ArrayStructure { id: __id, elements: __items } => {
1585 let mut __out = Vec::with_capacity(__items.len());
1586 for __swi in __items {
1587 __out.push(<#type_ident as TryFrom<Value>>::try_from(
1588 Value::Structure(Structure { id: __id, fields: __swi.fields })
1589 )?);
1590 }
1591 __out
1592 }
1593 _ => return Err(ConversionError { message: #mismatch.to_string() }),
1594 }
1595 })
1596 }
1597 RecordType::Enumeration => {
1598 let mismatch = format!("field {}: expected array of enumerations", field_name);
1599 Ok(quote! {
1600 match #value_expression {
1601 Value::ArrayEnumeration { id: __id, elements: __items } => {
1602 let mut __out = Vec::with_capacity(__items.len());
1603 for __ewi in __items {
1604 __out.push(<#type_ident as TryFrom<Value>>::try_from(
1605 Value::Enumeration(Enumeration {
1606 id: __id,
1607 variant_id: __ewi.variant_id,
1608 value: __ewi.value,
1609 })
1610 )?);
1611 }
1612 __out
1613 }
1614 _ => return Err(ConversionError { message: #mismatch.to_string() }),
1615 }
1616 })
1617 }
1618 _ => unreachable!("unexpected array element record type"),
1619 }
1620 }
1621 }
1622}
1623
1624async fn generate_serialize_from_frozen(
1625 ty: &FrozenTy,
1626 value_expression: TokenStream,
1627 registry: &mut dyn ReadableRegistry,
1628) -> Result<TokenStream, GenerationError> {
1629 match ty {
1630 FrozenTy::Primitive(primitive) => {
1631 let generate_serialize_primitive_array =
1632 |primitive_type_id: &Uuid, write_function: TokenStream| {
1633 let id_bytes = RawUuidValue(primitive_type_id);
1634 quote! {
1635 writer.add_array_primitive(#id_bytes, #value_expression.len() as u32);
1636 #write_function (#value_expression);
1637 }
1638 };
1639 Ok(match primitive.kind {
1640 PrimitiveKind::Unit => quote! { writer.add_unit() },
1641 PrimitiveKind::Boolean => quote! { writer.add_boolean(#value_expression) },
1642 PrimitiveKind::U8 => quote! { writer.add_u8(#value_expression) },
1643 PrimitiveKind::U16 => quote! { writer.add_u16(#value_expression) },
1644 PrimitiveKind::U32 => quote! { writer.add_u32(#value_expression) },
1645 PrimitiveKind::U64 => quote! { writer.add_u64(#value_expression) },
1646 PrimitiveKind::I8 => quote! { writer.add_i8(#value_expression) },
1647 PrimitiveKind::I16 => quote! { writer.add_i16(#value_expression) },
1648 PrimitiveKind::I32 => quote! { writer.add_i32(#value_expression) },
1649 PrimitiveKind::I64 => quote! { writer.add_i64(#value_expression) },
1650 PrimitiveKind::F32 => quote! { writer.add_f32(#value_expression) },
1651 PrimitiveKind::F64 => quote! { writer.add_f64(#value_expression) },
1652 PrimitiveKind::String => quote! { writer.add_string(#value_expression.as_str()) },
1653 PrimitiveKind::ArrayBoolean => generate_serialize_primitive_array(
1654 &BOOLEAN_ID,
1655 quote! { writer.add_boolean_bulk },
1656 ),
1657 PrimitiveKind::ArrayU8 => {
1658 generate_serialize_primitive_array(&U8_ID, quote! { writer.add_u8_bulk })
1659 }
1660 PrimitiveKind::ArrayU16 => {
1661 generate_serialize_primitive_array(&U16_ID, quote! { writer.add_u16_bulk })
1662 }
1663 PrimitiveKind::ArrayU32 => {
1664 generate_serialize_primitive_array(&U32_ID, quote! { writer.add_u32_bulk })
1665 }
1666 PrimitiveKind::ArrayU64 => {
1667 generate_serialize_primitive_array(&U64_ID, quote! { writer.add_u64_bulk })
1668 }
1669 PrimitiveKind::ArrayI8 => {
1670 generate_serialize_primitive_array(&I8_ID, quote! { writer.add_i8_bulk })
1671 }
1672 PrimitiveKind::ArrayI16 => {
1673 generate_serialize_primitive_array(&I16_ID, quote! { writer.add_i16_bulk })
1674 }
1675 PrimitiveKind::ArrayI32 => {
1676 generate_serialize_primitive_array(&I32_ID, quote! { writer.add_i32_bulk })
1677 }
1678 PrimitiveKind::ArrayI64 => {
1679 generate_serialize_primitive_array(&I64_ID, quote! { writer.add_i64_bulk })
1680 }
1681 PrimitiveKind::ArrayF32 => {
1682 generate_serialize_primitive_array(&F32_ID, quote! { writer.add_f32_bulk })
1683 }
1684 PrimitiveKind::ArrayF64 => {
1685 generate_serialize_primitive_array(&F64_ID, quote! { writer.add_f64_bulk })
1686 }
1687 PrimitiveKind::ArrayString => {
1688 let id_bytes = RawUuidValue(&STRING_ID);
1689 quote! {
1690 writer.add_array_primitive(#id_bytes, #value_expression.len() as u32);
1691 for s in #value_expression {
1692 writer.add_string(s.as_str());
1693 }
1694 }
1695 }
1696 })
1697 }
1698 FrozenTy::FrozenScalar(scalar) => {
1699 if is_dynamic_value_id(&scalar.reference.id) {
1702 return Ok(quote! {
1703 arora_buffers::serde_uuid::serialize_to_writer(&#value_expression, writer)
1704 });
1705 }
1706 let mod_prefix = generated_mod_ident_from_id(&scalar.reference.id, registry)
1707 .await
1708 .map_err(GenerationError::RegistryError)?;
1709 Ok(quote! { #mod_prefix serialize_to_writer(&#value_expression, writer) })
1712 }
1713 FrozenTy::FrozenArray(array) => {
1714 let type_def = registry
1715 .get_type(
1716 &Selector::Id(array.reference.id),
1717 &VersionReq::parse(array.reference.version.0.to_string().as_str()).unwrap(),
1718 )
1719 .await
1720 .map_err(GenerationError::RegistryError)?;
1721 let id_bytes = RawUuidValue(&array.reference.id);
1722 let add_array_args = quote! { &#id_bytes, #value_expression.len() as u32 };
1725 let prepare_array = match type_def {
1726 TypeDefinitionFrozen::Primitive(_) => {
1727 unreachable!("got an array of primitive type instead of a primitive array type")
1728 }
1729 TypeDefinitionFrozen::Enumeration(_) => {
1730 quote! { writer.add_array_enumeration(#add_array_args); }
1731 }
1732 TypeDefinitionFrozen::Structure(_) => {
1733 quote! { writer.add_array_structure(#add_array_args); }
1734 }
1735 };
1736 let mod_prefix = generated_mod_ident_from_id(&array.reference.id, registry)
1737 .await
1738 .map_err(GenerationError::RegistryError)?;
1739 Ok(quote! {
1751 #prepare_array
1752 for element in &#value_expression {
1753 #mod_prefix serialize_to_writer_raw(element, writer);
1754 }
1755 })
1756 }
1757 }
1758}
1759
1760#[async_recursion(?Send)]
1761async fn generate_deserialize_from_frozen(
1762 ty: &FrozenTy,
1763 registry: &mut dyn ReadableRegistry,
1764 check_type: CheckType,
1765) -> Result<TokenStream, GenerationError> {
1766 match ty {
1767 FrozenTy::Primitive(primitive) => {
1768 let type_kind_ident = type_kind_ident_from_primitive(&primitive.kind);
1769
1770 let generate_deserialize = |deserialize: TokenStream| {
1771 let type_check = match check_type {
1772 CheckType::Yes => quote! {
1773 {
1774 let _next_type = reader.next_type();
1775 assert_eq!(_next_type, Some(#type_kind_ident), "type mismatch");
1776 }
1777 },
1778 CheckType::YesResult => quote! {
1779 {
1780 let _next_type = reader.next_type();
1781 if _next_type != Some(#type_kind_ident) {
1782 return Err(format!("type mismatch: expected {:?} but got {:?}", #type_kind_ident, _next_type));
1783 }
1784 }
1785 },
1786 CheckType::No => quote! {},
1787 };
1788 quote! {{
1789 #type_check
1790 #deserialize
1791 }
1792 }
1793 };
1794
1795 let generate_deserialize_base_type = |type_ident: TokenStream| {
1796 let getter = format_ident!("get_{}", type_ident.to_string());
1797 generate_deserialize(quote! { reader.#getter() })
1798 };
1799
1800 let generate_deserialize_array = |deserialize_array: TokenStream| {
1801 let array_type_check = match check_type {
1802 CheckType::Yes => quote! {
1803 {
1804 let _at = reader.next_type();
1805 assert_eq!(_at, Some(TYPE_ARRAY));
1806 }
1807 let (ty, count) = reader.get_array();
1808 assert_eq!(ty, #type_kind_ident);
1809 },
1810 _ => quote! {
1811 {
1812 let _at = reader.next_type();
1813 if _at != Some(TYPE_ARRAY) {
1814 return Err(format!("expected array, got {:?}", _at));
1815 }
1816 }
1817 let (ty, count) = reader.get_array();
1818 if ty != #type_kind_ident {
1819 return Err(format!("expected array element type {:?}, got {:?}", #type_kind_ident, ty));
1820 }
1821 },
1822 };
1823 quote! {{
1824 #array_type_check
1825 #deserialize_array
1826 }
1827 }
1828 };
1829 Ok(match primitive.kind {
1830 PrimitiveKind::Unit => {
1831 quote! { Result::<(), DeserializationError>::Ok(reader.get_unit()) }
1832 }
1833 PrimitiveKind::Boolean => generate_deserialize(quote! { reader.get_boolean() }),
1834 PrimitiveKind::U8 => generate_deserialize_base_type(quote! {u8}),
1835 PrimitiveKind::U16 => generate_deserialize_base_type(quote! {u16}),
1836 PrimitiveKind::U32 => generate_deserialize_base_type(quote! {u32}),
1837 PrimitiveKind::U64 => generate_deserialize_base_type(quote! {u64}),
1838 PrimitiveKind::I8 => generate_deserialize_base_type(quote! {i8}),
1839 PrimitiveKind::I16 => generate_deserialize_base_type(quote! {i16}),
1840 PrimitiveKind::I32 => generate_deserialize_base_type(quote! {i32}),
1841 PrimitiveKind::I64 => generate_deserialize_base_type(quote! {i64}),
1842 PrimitiveKind::F32 => generate_deserialize_base_type(quote! {f32}),
1843 PrimitiveKind::F64 => generate_deserialize_base_type(quote! {f64}),
1844 PrimitiveKind::String => generate_deserialize(quote! {
1845 reader.get_string().to_string()
1846 }),
1847 PrimitiveKind::ArrayBoolean => generate_deserialize_array(quote! {
1848 reader.get_boolean_bulk(count)
1849 }),
1850 PrimitiveKind::ArrayU8 => generate_deserialize_array(quote! {
1851 reader.get_u8_bulk(count)
1852 }),
1853 PrimitiveKind::ArrayU16 => generate_deserialize_array(quote! {
1854 reader.get_u16_bulk(count)
1855 }),
1856 PrimitiveKind::ArrayU32 => generate_deserialize_array(quote! {
1857 reader.get_u32_bulk(count)
1858 }),
1859 PrimitiveKind::ArrayU64 => generate_deserialize_array(quote! {
1860 reader.get_u64_bulk(count)
1861 }),
1862 PrimitiveKind::ArrayI8 => generate_deserialize_array(quote! {
1863 reader.get_i8_bulk(count)
1864 }),
1865 PrimitiveKind::ArrayI16 => generate_deserialize_array(quote! {
1866 reader.get_i16_bulk(count)
1867 }),
1868 PrimitiveKind::ArrayI32 => generate_deserialize_array(quote! {
1869 reader.get_i32_bulk(count)
1870 }),
1871 PrimitiveKind::ArrayI64 => generate_deserialize_array(quote! {
1872 reader.get_i64_bulk(count)
1873 }),
1874 PrimitiveKind::ArrayF32 => generate_deserialize_array(quote! {
1875 reader.get_f32_bulk(count)
1876 }),
1877 PrimitiveKind::ArrayF64 => generate_deserialize_array(quote! {
1878 reader.get_f64_bulk(count)
1879 }),
1880 PrimitiveKind::ArrayString => {
1881 let deserialize_element = generate_deserialize(quote! {
1882 Result::<String, DeserializationError>::Ok(reader.get_string().to_string())
1883 });
1884 generate_deserialize_array(quote! {
1885 let mut res = Vec::<String>::with_capacity(count as usize);
1886 for _i in 0..count {
1887 res.push(#deserialize_element);
1888 }
1889 res
1890 })
1891 }
1892 })
1893 }
1894 FrozenTy::FrozenScalar(scalar) => {
1895 if is_dynamic_value_id(&scalar.reference.id) {
1897 return Ok(quote! {
1898 arora_buffers::serde_uuid::deserialize_from_reader(reader)
1899 });
1900 }
1901 let mod_prefix = generated_mod_ident_from_id(&scalar.reference.id, registry)
1902 .await
1903 .map_err(GenerationError::RegistryError)?;
1904 let check_type_bool = check_type != CheckType::No;
1905 let type_ident =
1906 type_ident_from_id(&scalar.reference.id, registry, PrefixWithMod::Yes).await?;
1907 let type_str = type_ident.to_string();
1908 Ok(match check_type {
1913 CheckType::YesResult => quote! {
1914 #mod_prefix deserialize_from_reader(reader, #check_type_bool)
1915 .map_err(|e| format!("failed to deserialize {}: {}", #type_str, e))?
1916 },
1917 _ => quote! {
1918 #mod_prefix deserialize_from_reader(reader, #check_type_bool)
1919 .expect(&format!("failed to deserialize {}", #type_str))
1920 },
1921 })
1922 }
1923 FrozenTy::FrozenArray(array) => {
1924 let type_ident =
1925 type_ident_from_id(&array.reference.id, registry, PrefixWithMod::Yes).await?;
1926 let element_record_type = registry
1927 .type_of(&Selector::Id(array.reference.id.to_owned()))
1928 .await
1929 .map_err(GenerationError::RegistryError)?;
1930 let element_check_type = CheckType::No;
1937 let deserialize_element = generate_deserialize_from_frozen(
1938 &FrozenTy::FrozenScalar(FrozenScalar {
1939 reference: array.reference.to_owned(),
1940 }),
1941 registry,
1942 element_check_type,
1943 )
1944 .await?;
1945 let type_enum = match element_record_type {
1946 RecordType::Enumeration => quote! { TYPE_ENUMERATION },
1947 RecordType::Structure => quote! { TYPE_STRUCTURE },
1948 _ => unreachable!("unexpected type of element in array"),
1949 };
1950 let raw_id = RawUuidValue(&array.reference.id);
1951 let array_checks = match check_type {
1952 CheckType::Yes => quote! {
1953 {
1954 let _at = reader.next_type();
1955 assert_eq!(_at, Some(TYPE_ARRAY));
1956 }
1957 let (ty, count) = reader.get_array();
1958 assert_eq!(ty, #type_enum);
1959 {
1960 let _id = reader.get_structure_field();
1961 assert_eq!(_id, &#raw_id);
1962 }
1963 },
1964 _ => quote! {
1965 {
1966 let _at = reader.next_type();
1967 if _at != Some(TYPE_ARRAY) {
1968 return Err(format!("expected array, got {:?}", _at));
1969 }
1970 }
1971 let (ty, count) = reader.get_array();
1972 if ty != #type_enum {
1973 return Err(format!("expected array element type {:?}, got {:?}", #type_enum, ty));
1974 }
1975 {
1976 let _id = reader.get_structure_field();
1977 if _id != &#raw_id {
1978 return Err("array type id mismatch".to_string());
1979 }
1980 }
1981 },
1982 };
1983 Ok(quote! {{
1984 #array_checks
1985 let mut res = Vec::<#type_ident>::with_capacity(count as usize);
1986 for _i in 0..count {
1987 res.push(#deserialize_element);
1988 }
1989 res
1990 }})
1991 }
1992 }
1993}
1994
1995pub fn token_stream_to_file<P: AsRef<path::Path>>(
1996 file_path: P,
1997 tokens: &TokenStream,
1998) -> Result<Directory, VfsError> {
1999 let file_path = file_path.as_ref();
2000 let file_name = file_path.file_name().unwrap().to_str().unwrap();
2001 let parent_path = file_path.parent().unwrap();
2002 let mut output = Directory::new();
2003 let parent_dir = match output.ensure_directories(parent_path) {
2004 Ok(dir) => dir,
2005 Err(VfsError::EmptyPath) => &mut output,
2006 Err(err) => return Err(err),
2007 };
2008 parent_dir.insert(file_name, File::new(tokens.to_string()))?;
2009 Ok(output)
2010}
2011
2012pub fn type_ident(type_name: &String) -> Ident {
2013 format_ident!("{}", type_name.to_case(Case::UpperCamel))
2014}
2015
2016pub fn struct_field_const_id_ident(struct_name: &String, field_name: &String) -> Ident {
2017 format_ident!(
2018 "{}_{}_FIELD_RAW_ID",
2019 struct_name.to_case(Case::UpperSnake),
2020 field_name.to_case(Case::UpperSnake)
2021 )
2022}
2023
2024pub fn struct_field_ident(struct_name: &String, field_name: &String) -> TokenStream {
2025 format!(
2026 "{}::{}",
2027 struct_name.to_case(Case::UpperCamel),
2028 field_name.to_case(Case::UpperCamel)
2029 )
2030 .parse()
2031 .unwrap()
2032}
2033
2034pub fn struct_field_intermediate_variable_ident(
2035 struct_name: &String,
2036 field_name: &String,
2037) -> Ident {
2038 format_ident!(
2039 "{}_{}",
2040 struct_name.to_case(Case::Snake),
2041 field_name.to_case(Case::Snake),
2042 )
2043}
2044
2045pub fn enum_variant_ident(enum_name: &String, variant_name: &String) -> TokenStream {
2046 format!(
2047 "{}::{}",
2048 enum_name.to_case(Case::UpperCamel),
2049 variant_name.to_case(Case::UpperCamel),
2050 )
2051 .parse()
2052 .unwrap()
2053}
2054
2055pub fn enum_variant_const_id_ident(enum_name: &String, variant_name: &String) -> Ident {
2056 format_ident!(
2057 "{}_{}_VARIANT_RAW_ID",
2058 enum_name.to_case(Case::UpperSnake),
2059 variant_name.to_case(Case::UpperSnake),
2060 )
2061}
2062
2063pub fn generate_const_id_declaration(
2065 name: &String,
2066 ident: &Ident,
2067 id: &Uuid,
2068 public: Public,
2069) -> TokenStream {
2070 let id_str = id.to_string();
2071 let id_bytes = RawUuidValue(id);
2072 let const_id_doc = format!("{}: {}", name, id_str);
2073 let maybe_pub = match public {
2074 Public::Yes => quote! { pub },
2075 Public::No => quote! {},
2076 };
2077 quote! {
2078 #[doc = #const_id_doc]
2079 #maybe_pub const #ident: [u8; 16] = #id_bytes;
2080 }
2081}
2082
2083pub fn function_const_id_ident(function_name: &String) -> Ident {
2084 format_ident!(
2085 "{}_FUNCTION_RAW_ID",
2086 function_name.to_case(Case::UpperSnake),
2087 )
2088}
2089
2090pub fn function_param_const_id_ident(function_name: &String, param_name: &String) -> Ident {
2091 format_ident!(
2092 "{}_{}_PARAMETER_RAW_ID",
2093 function_name.to_case(Case::UpperSnake),
2094 param_name.to_case(Case::UpperSnake),
2095 )
2096}
2097
2098fn param_ident(param_id: &Uuid, param: &Parameter) -> Ident {
2099 let param_id_sanitized = param_id.to_string().replace("-", "");
2100 format_ident!(
2101 "param_{}_{}",
2102 param.name.to_case(Case::Snake),
2103 param_id_sanitized
2104 )
2105}
2106
2107pub fn variable_ident(name: &String) -> Ident {
2108 format_ident!("{}", name.to_case(Case::Snake))
2109}
2110
2111async fn type_ident_from_frozen(
2112 ty: &FrozenTy,
2113 registry: &mut dyn ReadableRegistry,
2114 with_mod: PrefixWithMod,
2115) -> Result<TokenStream, GenerationError> {
2116 Ok(match ty {
2117 FrozenTy::Primitive(primitive) => match *primitive {
2118 Primitive::UNIT => quote! { () },
2119 Primitive::BOOLEAN => quote!(bool),
2120 Primitive::U8 => quote!(u8),
2121 Primitive::U16 => quote!(u16),
2122 Primitive::U32 => quote!(u32),
2123 Primitive::U64 => quote!(u64),
2124 Primitive::I8 => quote!(i8),
2125 Primitive::I16 => quote!(i16),
2126 Primitive::I32 => quote!(i32),
2127 Primitive::I64 => quote!(i64),
2128 Primitive::F32 => quote!(f32),
2129 Primitive::F64 => quote!(f64),
2130 Primitive::STRING => quote!(String),
2131 Primitive::ARRAY_BOOLEAN => quote!(Vec<bool>),
2132 Primitive::ARRAY_U8 => quote!(Vec<u8>),
2133 Primitive::ARRAY_U16 => quote!(Vec<u16>),
2134 Primitive::ARRAY_U32 => quote!(Vec<u32>),
2135 Primitive::ARRAY_U64 => quote!(Vec<u64>),
2136 Primitive::ARRAY_I8 => quote!(Vec<i8>),
2137 Primitive::ARRAY_I16 => quote!(Vec<i16>),
2138 Primitive::ARRAY_I32 => quote!(Vec<i32>),
2139 Primitive::ARRAY_I64 => quote!(Vec<i64>),
2140 Primitive::ARRAY_F32 => quote!(Vec<f32>),
2141 Primitive::ARRAY_F64 => quote!(Vec<f64>),
2142 Primitive::ARRAY_STRING => quote!(Vec<String>),
2143 },
2144 FrozenTy::FrozenScalar(scalar) => {
2145 type_ident_from_id(&scalar.reference.id, registry, with_mod).await?
2146 }
2147 FrozenTy::FrozenArray(array) => {
2148 let type_ident = type_ident_from_id(&array.reference.id, registry, with_mod).await?;
2149 quote! { Vec<#type_ident> }
2150 }
2151 })
2152}
2153
2154fn is_dynamic_value_id(id: &Uuid) -> bool {
2160 *id == *arora_types::ty::ARRAY_VALUE_ID || *id == *arora_types::ty::KEY_VALUE_ID
2161}
2162
2163fn dynamic_value_type() -> TokenStream {
2165 quote! { arora_types::value::Value }
2166}
2167
2168async fn type_ident_from_id(
2169 id: &Uuid,
2170 registry: &mut dyn ReadableRegistry,
2171 with_mod: PrefixWithMod,
2172) -> Result<TokenStream, GenerationError> {
2173 if is_dynamic_value_id(id) {
2174 return Ok(dynamic_value_type());
2175 }
2176 let type_def = registry
2177 .get_type(&Selector::Id(id.to_owned()), &VersionReq::STAR)
2178 .await
2179 .map_err(GenerationError::RegistryError)?;
2180 type_ident_from_definition(&type_def, id, registry, with_mod).await
2181}
2182
2183async fn type_ident_from_definition(
2184 type_def: &TypeDefinitionFrozen,
2185 id: &Uuid,
2186 registry: &mut dyn ReadableRegistry,
2187 with_mod: PrefixWithMod,
2188) -> Result<TokenStream, GenerationError> {
2189 Ok(match type_def {
2190 TypeDefinitionFrozen::Primitive(primitive) => match primitive {
2191 PrimitiveKind::Unit => quote! { () },
2192 PrimitiveKind::Boolean => quote!(bool),
2193 PrimitiveKind::U8 => quote!(u8),
2194 PrimitiveKind::U16 => quote!(u16),
2195 PrimitiveKind::U32 => quote!(u32),
2196 PrimitiveKind::U64 => quote!(u64),
2197 PrimitiveKind::I8 => quote!(i8),
2198 PrimitiveKind::I16 => quote!(i16),
2199 PrimitiveKind::I32 => quote!(i32),
2200 PrimitiveKind::I64 => quote!(i64),
2201 PrimitiveKind::F32 => quote!(f32),
2202 PrimitiveKind::F64 => quote!(f64),
2203 PrimitiveKind::String => quote!(String),
2204 PrimitiveKind::ArrayBoolean => quote!(Vec<bool>),
2205 PrimitiveKind::ArrayU8 => quote!(Vec<u8>),
2206 PrimitiveKind::ArrayU16 => quote!(Vec<u16>),
2207 PrimitiveKind::ArrayU32 => quote!(Vec<u32>),
2208 PrimitiveKind::ArrayU64 => quote!(Vec<u64>),
2209 PrimitiveKind::ArrayI8 => quote!(Vec<i8>),
2210 PrimitiveKind::ArrayI16 => quote!(Vec<i16>),
2211 PrimitiveKind::ArrayI32 => quote!(Vec<i32>),
2212 PrimitiveKind::ArrayI64 => quote!(Vec<i64>),
2213 PrimitiveKind::ArrayF32 => quote!(Vec<f32>),
2214 PrimitiveKind::ArrayF64 => quote!(Vec<f64>),
2215 PrimitiveKind::ArrayString => quote!(Vec<String>),
2216 },
2217 TypeDefinitionFrozen::Enumeration(enumeration) => {
2218 type_ident_from_name_and_id(&enumeration.name, id, registry, with_mod)
2219 .await
2220 .map_err(GenerationError::RegistryError)?
2221 }
2222 TypeDefinitionFrozen::Structure(structure) => {
2223 type_ident_from_name_and_id(&structure.name, id, registry, with_mod)
2224 .await
2225 .map_err(GenerationError::RegistryError)?
2226 }
2227 })
2228}
2229
2230async fn type_ident_from_name_and_id(
2231 name: &String,
2232 id: &Uuid,
2233 registry: &mut dyn ReadableRegistry,
2234 with_mod: PrefixWithMod,
2235) -> Result<TokenStream, RegistryError> {
2236 let mod_prefix = match with_mod {
2237 PrefixWithMod::Yes => generated_mod_ident_from_id(id, registry).await?,
2238 PrefixWithMod::No => quote! {},
2239 };
2240 let type_ident = type_ident(name);
2241 Ok(quote! { #mod_prefix #type_ident })
2242}
2243
2244fn type_kind_ident_from_primitive(primitive: &PrimitiveKind) -> TokenStream {
2245 match primitive {
2246 PrimitiveKind::Unit => quote! { TYPE_UNIT },
2247 PrimitiveKind::Boolean => quote! { TYPE_BOOLEAN },
2248 PrimitiveKind::U8 => quote! { TYPE_U8 },
2249 PrimitiveKind::U16 => quote! { TYPE_U16 },
2250 PrimitiveKind::U32 => quote! { TYPE_U32 },
2251 PrimitiveKind::U64 => quote! { TYPE_U64 },
2252 PrimitiveKind::I8 => quote! { TYPE_I8 },
2253 PrimitiveKind::I16 => quote! { TYPE_I16 },
2254 PrimitiveKind::I32 => quote! { TYPE_I32 },
2255 PrimitiveKind::I64 => quote! { TYPE_I64 },
2256 PrimitiveKind::F32 => quote! { TYPE_F32 },
2257 PrimitiveKind::F64 => quote! { TYPE_F64 },
2258 PrimitiveKind::String => quote! { TYPE_STRING },
2259 PrimitiveKind::ArrayBoolean
2260 | PrimitiveKind::ArrayU8
2261 | PrimitiveKind::ArrayU16
2262 | PrimitiveKind::ArrayU32
2263 | PrimitiveKind::ArrayU64
2264 | PrimitiveKind::ArrayI8
2265 | PrimitiveKind::ArrayI16
2266 | PrimitiveKind::ArrayI32
2267 | PrimitiveKind::ArrayI64
2268 | PrimitiveKind::ArrayF32
2269 | PrimitiveKind::ArrayF64
2270 | PrimitiveKind::ArrayString => quote! { TYPE_ARRAY },
2271 }
2272}
2273
2274async fn generated_mod_ident_from_id(
2276 id: &Uuid,
2277 registry: &mut dyn ReadableRegistry,
2278) -> Result<TokenStream, RegistryError> {
2279 let mod_path = registry.resolve_id(id).await?;
2280 let mod_ident = mod_ident_from_path(&mod_path);
2281 Ok(quote! { arora_generated::#mod_ident })
2282}
2283
2284fn mod_ident_from_path(path: &str) -> TokenStream {
2285 let path_parts = path.split(".").collect::<Vec<&str>>();
2286 let path_parts = path_parts
2287 .iter()
2288 .map(|part| format_ident!("{}", part.to_case(Case::Snake)));
2289 quote! { #(#path_parts ::)* }
2290}
2291
2292#[derive(Clone, Copy, Eq, PartialEq)]
2293pub enum CheckType {
2294 Yes,
2296 YesResult,
2298 No,
2299}
2300
2301#[derive(Clone, Copy, Eq, PartialEq)]
2302pub enum PrefixWithMod {
2303 Yes,
2304 No,
2305}
2306
2307#[derive(Clone, Copy, Eq, PartialEq)]
2308pub enum Public {
2309 Yes,
2310 No,
2311}
2312
2313#[derive(Display, Debug)]
2314pub enum GenerationError {
2315 ModuleDeclarationError(ModuleDeclarationError),
2316 RegistryError(RegistryError),
2317 VfsError(VfsError),
2318 IoError(std::io::Error),
2319 Generic(String),
2320}
2321
2322impl std::error::Error for GenerationError {}
2323
2324pub struct RawUuidValue<'a>(pub &'a Uuid);
2326
2327impl<'a> Display for RawUuidValue<'a> {
2328 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2329 write!(f, "{:#04x?}", self.0.as_bytes())
2330 }
2331}
2332
2333impl<'a> ToTokens for RawUuidValue<'a> {
2334 fn to_tokens(&self, tokens: &mut TokenStream) {
2335 let new_tokens: TokenStream = self.to_string().parse().unwrap();
2336 tokens.extend(new_tokens);
2337 }
2338}