ploidy_codegen_rust/
resource.rs1use heck::ToSnakeCase;
2use ploidy_core::{
3 codegen::IntoCode,
4 ir::{InlineIrTypePathRoot, InlineIrTypeView, IrOperationView},
5};
6use proc_macro2::TokenStream;
7use quote::{ToTokens, TokenStreamExt, quote};
8
9use super::{
10 enum_::CodegenEnum, naming::CodegenTypeName, operation::CodegenOperation,
11 struct_::CodegenStruct, tagged::CodegenTagged, untagged::CodegenUntagged,
12};
13
14pub struct CodegenResource<'a> {
17 resource: &'a str,
18 operations: &'a [IrOperationView<'a>],
19}
20
21impl<'a> CodegenResource<'a> {
22 pub fn new(resource: &'a str, operations: &'a [IrOperationView<'a>]) -> Self {
23 Self {
24 resource,
25 operations,
26 }
27 }
28}
29
30impl ToTokens for CodegenResource<'_> {
31 fn to_tokens(&self, tokens: &mut TokenStream) {
32 let feature_name = self.resource;
33 let methods: Vec<TokenStream> = self
34 .operations
35 .iter()
36 .map(|view| CodegenOperation::new(view).into_token_stream())
37 .collect();
38
39 let mut inlines = self
40 .operations
41 .iter()
42 .flat_map(|op| op.inlines())
43 .filter(|ty| {
44 matches!(ty.path().root, InlineIrTypePathRoot::Resource(r) if r == self.resource)
49 })
50 .map(|view| {
51 let name = CodegenTypeName::Inline(&view);
52 match &view {
53 InlineIrTypeView::Enum(_, view) => {
54 CodegenEnum::new(name, view).into_token_stream()
55 }
56 InlineIrTypeView::Struct(_, view) => {
57 CodegenStruct::new(name, view).into_token_stream()
58 }
59 InlineIrTypeView::Tagged(_, view) => {
60 CodegenTagged::new(name, view).into_token_stream()
61 }
62 InlineIrTypeView::Untagged(_, view) => {
63 CodegenUntagged::new(name, view).into_token_stream()
64 }
65 }
66 });
67 let fields_module = inlines.next().map(|head| {
68 quote! {
69 pub mod types {
70 #head
71 #(#inlines)*
72 }
73 }
74 });
75
76 tokens.append_all(quote! {
77 #[cfg(feature = #feature_name)]
78 impl crate::client::Client {
79 #(#methods)*
80 }
81 #fields_module
82 });
83 }
84}
85
86impl IntoCode for CodegenResource<'_> {
87 type Code = (String, TokenStream);
88
89 fn into_code(self) -> Self::Code {
90 (
91 format!("src/client/{}.rs", self.resource.to_snake_case()),
92 self.into_token_stream(),
93 )
94 }
95}