ploidy_codegen_rust/
schema.rs

1use ploidy_core::{
2    codegen::IntoCode,
3    ir::{InlineIrTypeView, SchemaIrTypeView, View},
4};
5use proc_macro2::TokenStream;
6use quote::{ToTokens, TokenStreamExt, quote};
7
8use super::{
9    enum_::CodegenEnum, naming::CodegenTypeName, struct_::CodegenStruct, tagged::CodegenTagged,
10    untagged::CodegenUntagged,
11};
12
13/// Generates a module for a named schema type.
14#[derive(Debug)]
15pub struct CodegenSchemaType<'a> {
16    name: CodegenTypeName<'a>,
17    ty: &'a SchemaIrTypeView<'a>,
18}
19
20impl<'a> CodegenSchemaType<'a> {
21    pub fn new(name: CodegenTypeName<'a>, ty: &'a SchemaIrTypeView<'a>) -> Self {
22        Self { name, ty }
23    }
24}
25
26impl ToTokens for CodegenSchemaType<'_> {
27    fn to_tokens(&self, tokens: &mut TokenStream) {
28        let name = self.name;
29        let code = match self.ty {
30            SchemaIrTypeView::Struct(_, view) => CodegenStruct::new(name, view).into_token_stream(),
31            SchemaIrTypeView::Enum(_, view) => CodegenEnum::new(name, view).into_token_stream(),
32            SchemaIrTypeView::Tagged(_, view) => CodegenTagged::new(name, view).into_token_stream(),
33            SchemaIrTypeView::Untagged(_, view) => {
34                CodegenUntagged::new(name, view).into_token_stream()
35            }
36        };
37        let mut inlines = self.ty.inlines().map(|view| match view {
38            InlineIrTypeView::Enum(path, view) => {
39                CodegenEnum::new(CodegenTypeName::Inline(path), &view).into_token_stream()
40            }
41            InlineIrTypeView::Struct(path, view) => {
42                CodegenStruct::new(CodegenTypeName::Inline(path), &view).into_token_stream()
43            }
44            InlineIrTypeView::Untagged(path, view) => {
45                CodegenUntagged::new(CodegenTypeName::Inline(path), &view).into_token_stream()
46            }
47        });
48        let fields_module = inlines.next().map(|head| {
49            quote! {
50                pub mod types {
51                    #head
52                    #(#inlines)*
53                }
54            }
55        });
56        tokens.append_all(quote! {
57            #code
58            #fields_module
59        });
60    }
61}
62
63impl IntoCode for CodegenSchemaType<'_> {
64    type Code = (String, TokenStream);
65
66    fn into_code(self) -> Self::Code {
67        let name = match self.name {
68            CodegenTypeName::Schema(_, ident) => {
69                format!("src/types/{}.rs", ident.module().to_token_stream())
70            }
71            CodegenTypeName::Inline(..) => {
72                unreachable!("inline types shouldn't be written to disk")
73            }
74        };
75        (name, self.into_token_stream())
76    }
77}