use std::collections::{BTreeMap, BTreeSet};
use cratestack_core::{Field, Procedure};
use quote::quote;
use crate::include::grpc_pb::message::{self, render_message};
use crate::shared::{ident, to_snake_case};
pub(super) fn render_procedure_input(
procedure: &Procedure,
numbers: &BTreeMap<String, i32>,
enum_names: &BTreeSet<&str>,
) -> Result<proc_macro2::TokenStream, String> {
let base = cratestack_proto::to_pascal_case(&procedure.name);
let message_name = format!("{base}Input");
let module_ident = ident(&to_snake_case(&procedure.name));
let domain_path = quote! { super::super::procedures::#module_ident::Args };
let fields: Vec<Field> = procedure
.args
.iter()
.map(|arg| Field {
docs: arg.docs.clone(),
name: arg.name.clone(),
name_span: arg.name_span,
ty: arg.ty.clone(),
attributes: Vec::new(),
span: arg.span,
})
.collect();
let field_refs: Vec<&Field> = fields.iter().collect();
let rendered = render_message(&message_name, domain_path, &field_refs, numbers, enum_names)?;
Ok(rendered.tokens)
}
pub(super) fn render_procedure_output(
procedure: &Procedure,
numbers: &BTreeMap<String, i32>,
enum_names: &BTreeSet<&str>,
) -> Result<proc_macro2::TokenStream, String> {
let base = cratestack_proto::to_pascal_case(&procedure.name);
let message_name = format!("{base}Output");
let ident_tok = ident(&message_name);
let module_ident = ident(&to_snake_case(&procedure.name));
let domain_path = quote! { super::super::procedures::#module_ident::Output };
let number = *numbers
.get("result")
.ok_or_else(|| format!("no `.pb.lock` entry for `{message_name}.result`"))?;
let result_ty = cratestack_proto::monomorphize_return_type(&procedure.return_type);
let domain_expr = quote! { (*value).clone() };
let plan = message::render_field(
&message_name,
"result",
&result_ty,
domain_expr,
number,
enum_names,
);
let prost_field = plan.prost_field;
let from_domain_init = plan.from_domain_init;
Ok(quote! {
#[derive(Clone, PartialEq, ::cratestack::grpc::prost::Message)]
pub struct #ident_tok {
#prost_field
}
impl ::core::convert::From<&#domain_path> for #ident_tok {
fn from(value: &#domain_path) -> Self {
Self {
#from_domain_init
}
}
}
})
}