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