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