ploidy_codegen_rust/
types.rs

1use std::collections::BTreeSet;
2
3use ploidy_core::{codegen::IntoCode, ir::View};
4use proc_macro2::TokenStream;
5use quote::{ToTokens, TokenStreamExt, quote};
6
7use super::{graph::CodegenGraph, naming::SchemaIdent};
8
9/// Generates the `types/mod.rs` module.
10pub struct CodegenTypesModule<'a> {
11    graph: &'a CodegenGraph<'a>,
12}
13
14impl<'a> CodegenTypesModule<'a> {
15    pub fn new(graph: &'a CodegenGraph<'a>) -> Self {
16        Self { graph }
17    }
18}
19
20impl ToTokens for CodegenTypesModule<'_> {
21    fn to_tokens(&self, tokens: &mut TokenStream) {
22        let mut mods = Vec::new();
23        let mut uses = Vec::new();
24
25        for view in self.graph.schemas() {
26            let resources: BTreeSet<_> = view.used_by().map(|op| op.resource()).collect();
27            let Some(cfg_attr) = cfg_attr(&resources) else {
28                continue;
29            };
30
31            let ext = view.extensions();
32            let info = ext.get::<SchemaIdent>().unwrap();
33            let module = info.module();
34            mods.push(quote! {
35                #cfg_attr
36                pub mod #module;
37            });
38
39            let ty = info.ty();
40            uses.push(quote! {
41                #cfg_attr
42                pub use #module::#ty;
43            });
44        }
45
46        tokens.append_all(quote! {
47            #(#mods)*
48
49            #(#uses)*
50        });
51    }
52}
53
54impl IntoCode for CodegenTypesModule<'_> {
55    type Code = (&'static str, TokenStream);
56
57    fn into_code(self) -> Self::Code {
58        ("src/types/mod.rs", self.into_token_stream())
59    }
60}
61
62/// Generates a `#[cfg(feature = "...")]` or `#[cfg(any(feature = "...", ...))]`
63/// attribute for the given resources.
64fn cfg_attr(resources: &BTreeSet<&str>) -> Option<TokenStream> {
65    let mut features = resources.iter().peekable();
66    let first = features.next()?;
67    Some(match features.next() {
68        Some(next) => {
69            let rest = features.map(|f| quote! { feature = #f });
70            quote! { #[cfg(any(feature = #first, feature = #next, #(#rest),*))] }
71        }
72        None => quote! { #[cfg(feature = #first)] },
73    })
74}