daml_codegen/renderer/data_renderer/full/
quote_choices.rs

1use proc_macro2::TokenStream;
2
3use quote::quote;
4
5use crate::renderer::data_renderer::full::quote_contract_struct::quote_contract_id_struct_name;
6use crate::renderer::data_renderer::full::quote_method_arguments;
7use crate::renderer::renderer_utils::quote_escaped_ident;
8use crate::renderer::type_renderer::quote_type;
9use crate::renderer::{IsRenderable, RenderContext};
10use daml_lf::element::{DamlChoice, DamlField, DamlType};
11use heck::ToSnakeCase;
12
13pub fn quote_choice(ctx: &RenderContext<'_>, name: &str, items: &[DamlChoice<'_>]) -> TokenStream {
14    let all_choice_methods_tokens = quote_all_choice_methods(ctx, name, items);
15    let contract_struct_name_tokens = quote_contract_id_struct_name(name);
16    quote!(
17        impl #contract_struct_name_tokens {
18            #all_choice_methods_tokens
19        }
20    )
21}
22
23/// Generate all choice methods within the parent `impl` block.
24fn quote_all_choice_methods(ctx: &RenderContext<'_>, struct_name: &str, items: &[DamlChoice<'_>]) -> TokenStream {
25    let all_choice_methods: Vec<_> = items.iter().map(|choice| quote_choice_method(ctx, struct_name, choice)).collect();
26    quote!(
27        #( #all_choice_methods )*
28    )
29}
30
31/// Generate the `pub fn foo(&self, ...)` choice method.
32fn quote_choice_method(ctx: &RenderContext<'_>, struct_name: &str, choice: &DamlChoice<'_>) -> TokenStream {
33    let choice_name = &choice.name();
34    let struct_name_tokens = quote_escaped_ident(struct_name);
35    let method_name_command_tokens = quote_command_method_name(&choice.name().to_snake_case());
36    let _method_name_tokens = quote_escaped_ident(&choice.name().to_snake_case());
37    let choice_argument_tokens = quote_method_arguments(&choice.fields().iter().collect::<Vec<_>>());
38    let supported_fields: Vec<_> =
39        choice.fields().iter().filter(|&field| IsRenderable::new(ctx).check_type(field.ty())).collect();
40    let all_choice_fields = quote_all_choice_fields(&supported_fields);
41    quote!(
42        pub fn #method_name_command_tokens(&self, #choice_argument_tokens) -> DamlExerciseCommand {
43            let template_id = #struct_name_tokens::package_id();
44            #all_choice_fields
45            DamlExerciseCommand::new(
46                template_id,
47                self.contract_id().as_str(),
48                #choice_name,
49                params
50            )
51        }
52    )
53}
54
55/// Generate the `DamlValue::Record` containing all choice fields.
56fn quote_all_choice_fields(supported_fields: &[&DamlField<'_>]) -> TokenStream {
57    let all_choice_fields = quote_declare_all_choice_fields(supported_fields);
58    if all_choice_fields.is_empty() {
59        quote!(
60            let params = DamlValue::Record(DamlRecord::new(vec![], None::<DamlIdentifier>));
61        )
62    } else {
63        quote!(
64            let mut records = vec![];
65            #all_choice_fields
66            let params = DamlValue::Record(DamlRecord::new(records, None::<DamlIdentifier>));
67        )
68    }
69}
70
71/// Generate all choice fields.
72fn quote_declare_all_choice_fields(choice_parameters: &[&DamlField<'_>]) -> TokenStream {
73    choice_parameters.iter().map(|&field| quote_declare_choice_field(field.name(), field.ty())).collect()
74}
75
76/// Generate a choice field.
77fn quote_declare_choice_field(field_name: &str, field_type: &DamlType<'_>) -> TokenStream {
78    let field_source_tokens = quote_escaped_ident(field_name);
79    let name_string = quote!(#field_name);
80    let choice_type_tokens = quote_type(field_type);
81    let serialize_value_tokens = quote!(
82        <#choice_type_tokens as DamlSerializeInto<DamlValue>>::serialize_into(#field_source_tokens.into())
83    );
84    quote!(
85        records.push(DamlRecordField::new(Some(#name_string), #serialize_value_tokens));
86    )
87}
88
89fn quote_command_method_name(name: &str) -> TokenStream {
90    quote_escaped_ident(format!("{}_command", name))
91}