use crate::helpers::{encoded_args, fn_args_with_types_path, generate_doc_comments};
use convert_case::{Case, Casing};
use genco::prelude::*;
use rust::Tokens;
use sails_idl_parser_v2::{ast, visitor::Visitor};
pub(crate) struct CtorGenerator<'ast> {
program_name: &'ast str,
sails_path: &'ast str,
ctor_tokens: Tokens,
io_tokens: Tokens,
trait_ctors_tokens: Tokens,
}
impl<'ast> CtorGenerator<'ast> {
pub(crate) fn new(program_name: &'ast str, sails_path: &'ast str) -> Self {
Self {
program_name,
sails_path,
ctor_tokens: Tokens::new(),
io_tokens: Tokens::new(),
trait_ctors_tokens: Tokens::new(),
}
}
pub(crate) fn finalize(self) -> Tokens {
quote! {
pub trait $(self.program_name)Ctors {
type Env: $(self.sails_path)::client::GearEnv;
$(self.trait_ctors_tokens)
}
impl<E: $(self.sails_path)::client::GearEnv> $(self.program_name)Ctors for $(self.sails_path)::client::Deployment<$(self.program_name)Program, E> {
type Env = E;
$(self.ctor_tokens)
}
$['\n']
pub mod io {
use super::*;
$(self.io_tokens)
}
}
}
}
impl<'ast> Visitor<'ast> for CtorGenerator<'ast> {
fn visit_ctor_func(&mut self, func: &'ast ast::CtorFunc) {
let fn_name = &func.name;
let fn_name_snake = &fn_name.to_case(Case::Snake);
let params_with_types = &fn_args_with_types_path(&func.params, "");
let args = &encoded_args(&func.params);
generate_doc_comments(&mut self.trait_ctors_tokens, &func.docs);
if fn_name_snake == "new" {
quote_in! {self.trait_ctors_tokens =>
$['\r'] #[allow(clippy::new_ret_no_self)]
$['\r'] #[allow(clippy::wrong_self_convention)]
};
}
quote_in! { self.trait_ctors_tokens =>
$['\r']
fn $fn_name_snake (self, $params_with_types) -> $(self.sails_path)::client::PendingCtor<$(self.program_name)Program, io::$fn_name, Self::Env>;
};
quote_in! { self.ctor_tokens =>
$['\r']
fn $fn_name_snake (self, $params_with_types) -> $(self.sails_path)::client::PendingCtor<$(self.program_name)Program, io::$fn_name, Self::Env> {
self.pending_ctor($args)
}
};
let params_with_types_super = &fn_args_with_types_path(&func.params, "super");
let entry_id = func.entry_id;
let io_output_type = if let Some(throws) = &func.throws {
let err_ty = crate::type_generators::generate_type_decl_with_path(throws, "super");
format!("() | {err_ty}")
} else {
"()".to_string()
};
quote_in! { self.io_tokens =>
$(self.sails_path)::io_struct_impl!($fn_name ($params_with_types_super) -> $io_output_type, $entry_id);
};
}
}