use crate::renderer::data_renderer::full::quote_contract_struct::quote_contract_id_struct_name;
use crate::renderer::renderer_utils::quote_escaped_ident;
use crate::renderer::type_renderer::quote_type;
use crate::renderer::{RenderContext, to_module_path};
use daml_lf::element::{DamlInterface, DamlTyConName};
use heck::ToSnakeCase;
use proc_macro2::TokenStream;
use quote::quote;
use std::iter;
pub fn quote_interface_trait_path(tycon: &DamlTyConName<'_>) -> TokenStream {
let (package_name, module_path, data_name) = match tycon {
DamlTyConName::Absolute(abs) => (abs.package_name(), abs.module_path().collect::<Vec<_>>(), abs.data_name()),
DamlTyConName::Local(local) => {
(local.package_name(), local.module_path().collect::<Vec<_>>(), local.data_name())
},
DamlTyConName::NonLocal(nlocal) => {
(nlocal.target_package_name(), nlocal.target_module_path().collect::<Vec<_>>(), nlocal.data_name())
},
};
let path: Vec<&str> = if package_name.is_empty() {
module_path
} else {
iter::once(package_name).chain(module_path).collect()
};
let segments: Vec<_> = path.into_iter().map(ToSnakeCase::to_snake_case).map(quote_escaped_ident).collect();
let name_tokens = quote_escaped_ident(data_name);
quote!(crate :: #( #segments :: )* #name_tokens)
}
fn quote_interface_path_from_parts<'a, M: IntoIterator<Item = &'a str>>(
package_name: Option<&'a str>,
module_path: M,
entity_name: &str,
) -> TokenStream {
let path: Vec<&str> = match package_name {
Some(name) if !name.is_empty() => iter::once(name).chain(module_path).collect(),
_ => module_path.into_iter().collect(),
};
let segments: Vec<_> = path.into_iter().map(ToSnakeCase::to_snake_case).map(quote_escaped_ident).collect();
let name_tokens = quote_escaped_ident(entity_name);
quote!(crate :: #( #segments :: )* #name_tokens)
}
pub fn quote_interface_choices(
ctx: &RenderContext<'_>,
template_name: &str,
interface: &DamlInterface<'_>,
) -> TokenStream {
let contract_id_struct = quote_contract_id_struct_name(template_name);
let iface_path = quote_interface_path_from_parts(
ctx.package_name_for(interface.package_id()),
interface.module_path(),
interface.name(),
);
let iface_prefix = interface.name().to_snake_case();
let method_tokens: Vec<_> = interface
.choices()
.iter()
.map(|choice| {
let choice_name_lit = choice.name();
let choice_snake = choice.name().to_snake_case();
let method_ident = quote_escaped_ident(format!("{iface_prefix}_{choice_snake}_command"));
let arg_field = choice.fields().first().expect("choice must carry an arg field");
let arg_type_tokens = quote_type(ctx, arg_field.ty());
quote!(
pub fn #method_ident(&self, arg: impl Into<#arg_type_tokens>) -> DamlExerciseCommand {
let template_id = <Self as #iface_path>::interface_id();
let params: DamlValue =
<#arg_type_tokens as DamlSerializeInto<DamlValue>>::serialize_into(arg.into());
DamlExerciseCommand::new(
template_id,
self.contract_id().as_str(),
#choice_name_lit,
params
)
}
)
})
.collect();
if method_tokens.is_empty() {
quote!()
} else {
quote!(
impl #contract_id_struct {
#( #method_tokens )*
}
)
}
}
pub fn quote_daml_interface(ctx: &RenderContext<'_>, interface: &DamlInterface<'_>) -> TokenStream {
let trait_name_tokens = quote_escaped_ident(interface.name());
let module_name = to_module_path(interface.module_path());
let entity_name = interface.name();
let identifier_ctor = if let Some(name) = ctx.package_name_for(interface.package_id()) {
quote!(DamlIdentifier::from_package_name(#name, #module_name, #entity_name))
} else {
let package_id = interface.package_id();
quote!(DamlIdentifier::new(#package_id, #module_name, #entity_name))
};
quote!(
pub trait #trait_name_tokens {
fn interface_id() -> DamlIdentifier {
#identifier_ctor
}
}
)
}