ploidy_codegen_rust/
types.rs1use std::collections::BTreeSet;
2
3use itertools::Itertools;
4use ploidy_core::{codegen::IntoCode, ir::View};
5use proc_macro2::TokenStream;
6use quote::{ToTokens, TokenStreamExt, quote};
7
8use super::{
9 graph::CodegenGraph,
10 naming::{CodegenIdent, CodegenIdentUsage},
11};
12
13pub struct CodegenTypesModule<'a> {
15 graph: &'a CodegenGraph<'a>,
16}
17
18impl<'a> CodegenTypesModule<'a> {
19 pub fn new(graph: &'a CodegenGraph<'a>) -> Self {
20 Self { graph }
21 }
22}
23
24impl ToTokens for CodegenTypesModule<'_> {
25 fn to_tokens(&self, tokens: &mut TokenStream) {
26 let mut tys = self
27 .graph
28 .schemas()
29 .filter_map(|view| {
30 let resources: BTreeSet<_> = view.used_by().map(|op| op.resource()).collect();
31 let cfg_attr = cfg_attr(&resources)?;
32 Some((view.extensions().get::<CodegenIdent>()?.clone(), cfg_attr))
33 })
34 .collect_vec();
35 tys.sort_by(|(a, _), (b, _)| a.cmp(b));
36
37 let mods = tys.iter().map(|(ident, cfg_attr)| {
38 let mod_name = CodegenIdentUsage::Module(ident);
39 quote! {
40 #cfg_attr
41 pub mod #mod_name;
42 }
43 });
44 let uses = tys.iter().map(|(ident, cfg_attr)| {
45 let mod_name = CodegenIdentUsage::Module(ident);
46 let ty_name = CodegenIdentUsage::Type(ident);
47 quote! {
48 #cfg_attr
49 pub use #mod_name::#ty_name;
50 }
51 });
52
53 tokens.append_all(quote! {
54 #(#mods)*
55
56 #(#uses)*
57 });
58 }
59}
60
61impl IntoCode for CodegenTypesModule<'_> {
62 type Code = (&'static str, TokenStream);
63
64 fn into_code(self) -> Self::Code {
65 ("src/types/mod.rs", self.into_token_stream())
66 }
67}
68
69fn cfg_attr(resources: &BTreeSet<&str>) -> Option<TokenStream> {
72 let mut features = resources.iter().peekable();
73 let first = features.next()?;
74 Some(match features.next() {
75 Some(next) => {
76 let rest = features.map(|f| quote! { feature = #f });
77 quote! { #[cfg(any(feature = #first, feature = #next, #(#rest),*))] }
78 }
79 None => quote! { #[cfg(feature = #first)] },
80 })
81}