use std::fmt::Write;
use heck::{ToShoutySnakeCase, ToSnakeCase};
use crate::model::{
IdTemplateSegment, QueryModel, ServiceModel, SignalModel, UpdateModel, WorkflowModel,
};
pub fn render(svc: &ServiceModel) -> String {
let mut out = String::new();
let mod_name = mod_name(svc);
let proto_mod = proto_module_path(&svc.package);
let client_struct = format!("{}Client", svc.service);
let _ = writeln!(
out,
"// Code generated by protoc-gen-rust-temporal. DO NOT EDIT."
);
let _ = writeln!(out, "// source: {}", svc.source_file);
let _ = writeln!(out);
let _ = writeln!(out, "#[allow(clippy::all, unused_imports, dead_code)]");
let _ = writeln!(out, "pub mod {mod_name} {{");
let _ = writeln!(out, " use anyhow::Result;");
let _ = writeln!(out, " use std::time::Duration;");
let _ = writeln!(out, " use crate::temporal_runtime;");
let _ = writeln!(out, " use {proto_mod}::*;");
let _ = writeln!(out);
render_message_type_impls(&mut out, svc);
render_constants(&mut out, svc);
render_id_fns(&mut out, svc);
render_client_struct(&mut out, svc, &client_struct);
for wf in &svc.workflows {
render_start_options(&mut out, wf);
render_handle(&mut out, svc, wf);
}
render_with_start_functions(&mut out, svc);
let _ = writeln!(out, "}}");
out
}
fn render_message_type_impls(out: &mut String, svc: &ServiceModel) {
use std::collections::BTreeMap;
let mut by_rust_name: BTreeMap<String, String> = BTreeMap::new();
let mut record = |pt: &crate::model::ProtoType| {
if pt.is_empty {
return;
}
by_rust_name
.entry(pt.rust_name().to_string())
.or_insert_with(|| pt.full_name.clone());
};
for wf in &svc.workflows {
record(&wf.input_type);
record(&wf.output_type);
}
for s in &svc.signals {
record(&s.input_type);
record(&s.output_type);
}
for q in &svc.queries {
record(&q.input_type);
record(&q.output_type);
}
for u in &svc.updates {
record(&u.input_type);
record(&u.output_type);
}
if by_rust_name.is_empty() {
return;
}
for (rust_name, full_name) in &by_rust_name {
let _ = writeln!(
out,
" impl temporal_runtime::TemporalProtoMessage for {rust_name} {{"
);
let _ = writeln!(
out,
" const MESSAGE_TYPE: &'static str = \"{full_name}\";"
);
let _ = writeln!(out, " }}");
}
let _ = writeln!(out);
}
fn render_constants(out: &mut String, svc: &ServiceModel) {
for wf in &svc.workflows {
let const_name = format!("{}_WORKFLOW_NAME", wf.rpc_method.to_shouty_snake_case());
let _ = writeln!(
out,
" pub const {const_name}: &str = \"{}\";",
wf.registered_name
);
if let Some(tq) = effective_task_queue(svc, wf) {
let tq_const = format!("{}_TASK_QUEUE", wf.rpc_method.to_shouty_snake_case());
let _ = writeln!(out, " pub const {tq_const}: &str = \"{tq}\";");
}
}
if !svc.workflows.is_empty() {
let _ = writeln!(out);
}
}
fn render_id_fns(out: &mut String, svc: &ServiceModel) {
let mut emitted_any = false;
for wf in &svc.workflows {
let Some(segments) = wf.id_expression.as_ref() else {
continue;
};
emitted_any = true;
let fn_name = format!("{}_id", wf.rpc_method.to_snake_case());
let (fmt, args) = compile_id_template(segments);
if wf.input_type.is_empty {
let _ = writeln!(out, " fn {fn_name}() -> String {{");
if fmt.is_empty() {
let _ = writeln!(out, " String::new()");
} else {
let _ = writeln!(out, " \"{fmt}\".to_string()");
}
let _ = writeln!(out, " }}");
let _ = writeln!(out);
continue;
}
let input_ty = wf.input_type.rust_name();
let _ = writeln!(out, " fn {fn_name}(input: &{input_ty}) -> String {{");
if args.is_empty() {
let _ = writeln!(out, " let _ = input;");
let _ = writeln!(out, " \"{fmt}\".to_string()");
} else {
let _ = writeln!(out, " format!(\"{fmt}\", {})", args.join(", "));
}
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
if emitted_any {
}
}
fn id_fallback_call(wf: &WorkflowModel, in_self_method: bool) -> String {
if wf.id_expression.is_none() {
return "temporal_runtime::random_workflow_id()".to_string();
}
let fn_name = format!("{}_id", wf.rpc_method.to_snake_case());
if wf.input_type.is_empty {
return format!("{fn_name}()");
}
if in_self_method {
format!("{fn_name}(&input)")
} else {
format!("{fn_name}(&workflow_input)")
}
}
fn compile_id_template(segments: &[IdTemplateSegment]) -> (String, Vec<String>) {
let mut fmt = String::new();
let mut args = Vec::new();
for seg in segments {
match seg {
IdTemplateSegment::Literal(s) => {
fmt.push_str(&s.replace('{', "{{").replace('}', "}}"));
}
IdTemplateSegment::Field(rust_name) => {
fmt.push_str("{}");
args.push(format!("input.{rust_name}"));
}
}
}
(fmt, args)
}
fn render_client_struct(out: &mut String, svc: &ServiceModel, client_struct: &str) {
let _ = writeln!(out, " pub struct {client_struct} {{");
let _ = writeln!(out, " client: temporal_runtime::TemporalClient,");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
let _ = writeln!(out, " impl {client_struct} {{");
let _ = writeln!(
out,
" pub fn new(client: temporal_runtime::TemporalClient) -> Self {{"
);
let _ = writeln!(out, " Self {{ client }}");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
let _ = writeln!(
out,
" pub fn inner(&self) -> &temporal_runtime::TemporalClient {{"
);
let _ = writeln!(out, " &self.client");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
for wf in &svc.workflows {
render_client_workflow_methods(out, svc, wf);
}
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
fn render_client_workflow_methods(out: &mut String, svc: &ServiceModel, wf: &WorkflowModel) {
let method_snake = wf.rpc_method.to_snake_case();
let handle_struct = format!("{}Handle", wf.rpc_method);
let opts_struct = format!("{}StartOptions", wf.rpc_method);
let const_name = format!("{}_WORKFLOW_NAME", wf.rpc_method.to_shouty_snake_case());
let _ = writeln!(
out,
" /// Start a new `{}` workflow.",
wf.registered_name
);
let _ = writeln!(out, " pub async fn {method_snake}(");
let _ = writeln!(out, " &self,");
if !wf.input_type.is_empty {
let _ = writeln!(out, " input: {},", wf.input_type.rust_name());
}
let _ = writeln!(out, " opts: {opts_struct},");
let _ = writeln!(out, " ) -> Result<{handle_struct}> {{");
render_start_body(
out,
svc,
wf,
&const_name,
" ",
);
let _ = writeln!(out, " Ok({handle_struct} {{ inner }})");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
let _ = writeln!(
out,
" /// Attach to a running `{}` workflow by id.",
wf.registered_name
);
let _ = writeln!(
out,
" pub fn {method_snake}_handle(&self, workflow_id: impl Into<String>) -> {handle_struct} {{"
);
let _ = writeln!(out, " {handle_struct} {{");
let _ = writeln!(
out,
" inner: temporal_runtime::attach_handle(&self.client, workflow_id.into()),"
);
let _ = writeln!(out, " }}");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
fn render_start_body(
out: &mut String,
svc: &ServiceModel,
wf: &WorkflowModel,
const_name: &str,
leading_indent: &str,
) {
let ind = leading_indent;
let _ = writeln!(
out,
"{ind}let workflow_id = opts.workflow_id.unwrap_or_else(|| {{"
);
let _ = writeln!(
out,
"{ind} {}",
id_fallback_call(wf, true)
);
let _ = writeln!(out, "{ind}}});");
if let Some(tq) = effective_task_queue(svc, wf) {
let _ = writeln!(
out,
"{ind}let task_queue = opts.task_queue.unwrap_or_else(|| \"{tq}\".to_string());"
);
} else {
let _ = writeln!(
out,
"{ind}let task_queue = opts.task_queue.expect(\"workflow has no proto-level task_queue; opts.task_queue is required\");"
);
}
if wf.input_type.is_empty {
let _ = writeln!(
out,
"{ind}let inner = temporal_runtime::start_workflow_proto_empty("
);
let _ = writeln!(out, "{ind} &self.client,");
let _ = writeln!(out, "{ind} {const_name},");
let _ = writeln!(out, "{ind} &workflow_id,");
let _ = writeln!(out, "{ind} &task_queue,");
} else {
let _ = writeln!(
out,
"{ind}let inner = temporal_runtime::start_workflow_proto("
);
let _ = writeln!(out, "{ind} &self.client,");
let _ = writeln!(out, "{ind} {const_name},");
let _ = writeln!(out, "{ind} &workflow_id,");
let _ = writeln!(out, "{ind} &task_queue,");
let _ = writeln!(out, "{ind} &input,");
}
let _ = writeln!(out, "{ind} opts.id_reuse_policy,");
let _ = writeln!(out, "{ind} opts.execution_timeout,");
let _ = writeln!(out, "{ind} opts.run_timeout,");
let _ = writeln!(out, "{ind} opts.task_timeout,");
let _ = writeln!(out, "{ind}).await?;");
}
fn render_start_options(out: &mut String, wf: &WorkflowModel) {
let opts_struct = format!("{}StartOptions", wf.rpc_method);
let _ = writeln!(out, " #[derive(Debug, Default, Clone)]");
let _ = writeln!(out, " pub struct {opts_struct} {{");
let _ = writeln!(out, " pub workflow_id: Option<String>,");
let _ = writeln!(out, " pub task_queue: Option<String>,");
let _ = writeln!(
out,
" pub id_reuse_policy: Option<temporal_runtime::WorkflowIdReusePolicy>,"
);
let _ = writeln!(out, " pub execution_timeout: Option<Duration>,");
let _ = writeln!(out, " pub run_timeout: Option<Duration>,");
let _ = writeln!(out, " pub task_timeout: Option<Duration>,");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
let mut defaults: Vec<(&'static str, String, &'static str)> = Vec::new();
if let Some(p) = wf.id_reuse_policy {
defaults.push((
"default_id_reuse_policy",
format!(
"temporal_runtime::WorkflowIdReusePolicy::{}",
p.rust_variant()
),
"temporal_runtime::WorkflowIdReusePolicy",
));
}
if let Some(d) = wf.execution_timeout {
defaults.push(("default_execution_timeout", duration_literal(d), "Duration"));
}
if let Some(d) = wf.run_timeout {
defaults.push(("default_run_timeout", duration_literal(d), "Duration"));
}
if let Some(d) = wf.task_timeout {
defaults.push(("default_task_timeout", duration_literal(d), "Duration"));
}
if !defaults.is_empty() {
let _ = writeln!(out, " impl {opts_struct} {{");
for (name, value, return_ty) in &defaults {
let _ = writeln!(out, " pub fn {name}() -> {return_ty} {{");
let _ = writeln!(out, " {value}");
let _ = writeln!(out, " }}");
}
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
}
fn render_handle(out: &mut String, svc: &ServiceModel, wf: &WorkflowModel) {
let handle_struct = format!("{}Handle", wf.rpc_method);
let _ = writeln!(out, " pub struct {handle_struct} {{");
let _ = writeln!(out, " inner: temporal_runtime::WorkflowHandle,");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
let _ = writeln!(out, " impl {handle_struct} {{");
let _ = writeln!(out, " pub fn workflow_id(&self) -> &str {{");
let _ = writeln!(out, " self.inner.workflow_id()");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
let _ = writeln!(
out,
" /// Wait for the workflow to complete and return its output."
);
if wf.output_type.is_empty {
let _ = writeln!(out, " pub async fn result(&self) -> Result<()> {{");
let _ = writeln!(
out,
" temporal_runtime::wait_result_unit(&self.inner).await"
);
let _ = writeln!(out, " }}");
} else {
let output_ty = wf.output_type.rust_name();
let _ = writeln!(
out,
" pub async fn result(&self) -> Result<{output_ty}> {{"
);
let _ = writeln!(
out,
" temporal_runtime::wait_result_proto::<{output_ty}>(&self.inner).await"
);
let _ = writeln!(out, " }}");
}
let _ = writeln!(out);
for sref in &wf.attached_signals {
if let Some(sig) = svc.signals.iter().find(|s| s.rpc_method == sref.rpc_method) {
render_signal_method(out, sig);
}
}
for qref in &wf.attached_queries {
if let Some(q) = svc
.queries
.iter()
.find(|qq| qq.rpc_method == qref.rpc_method)
{
render_query_method(out, q);
}
}
for uref in &wf.attached_updates {
if let Some(u) = svc
.updates
.iter()
.find(|uu| uu.rpc_method == uref.rpc_method)
{
render_update_method(out, u);
}
}
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
fn render_signal_method(out: &mut String, sig: &SignalModel) {
let method_snake = sig.rpc_method.to_snake_case();
let _ = writeln!(
out,
" /// Send the `{}` signal.",
sig.registered_name
);
if sig.input_type.is_empty {
let _ = writeln!(
out,
" pub async fn {method_snake}(&self) -> Result<()> {{"
);
let _ = writeln!(
out,
" temporal_runtime::signal_unit(&self.inner, \"{}\").await",
sig.registered_name
);
let _ = writeln!(out, " }}");
} else {
let input_ty = sig.input_type.rust_name();
let _ = writeln!(
out,
" pub async fn {method_snake}(&self, input: {input_ty}) -> Result<()> {{"
);
let _ = writeln!(
out,
" temporal_runtime::signal_proto(&self.inner, \"{}\", &input).await",
sig.registered_name
);
let _ = writeln!(out, " }}");
}
let _ = writeln!(out);
}
fn render_query_method(out: &mut String, q: &QueryModel) {
let method_snake = q.rpc_method.to_snake_case();
let out_ty = q.output_type.rust_name();
let _ = writeln!(out, " /// Run the `{}` query.", q.registered_name);
if q.input_type.is_empty {
let _ = writeln!(
out,
" pub async fn {method_snake}(&self) -> Result<{out_ty}> {{"
);
let _ = writeln!(
out,
" temporal_runtime::query_proto_empty::<{out_ty}>(&self.inner, \"{}\").await",
q.registered_name
);
let _ = writeln!(out, " }}");
} else {
let in_ty = q.input_type.rust_name();
let _ = writeln!(
out,
" pub async fn {method_snake}(&self, input: {in_ty}) -> Result<{out_ty}> {{"
);
let _ = writeln!(
out,
" temporal_runtime::query_proto::<{in_ty}, {out_ty}>(&self.inner, \"{}\", &input).await",
q.registered_name
);
let _ = writeln!(out, " }}");
}
let _ = writeln!(out);
}
fn render_update_method(out: &mut String, u: &UpdateModel) {
let method_snake = u.rpc_method.to_snake_case();
let out_ty = u.output_type.rust_name();
let _ = writeln!(out, " /// Run the `{}` update.", u.registered_name);
if u.input_type.is_empty {
let _ = writeln!(
out,
" pub async fn {method_snake}(&self, wait_policy: temporal_runtime::WaitPolicy) -> Result<{out_ty}> {{"
);
let _ = writeln!(
out,
" temporal_runtime::update_proto_empty::<{out_ty}>(&self.inner, \"{}\", wait_policy).await",
u.registered_name
);
let _ = writeln!(out, " }}");
} else {
let in_ty = u.input_type.rust_name();
let _ = writeln!(
out,
" pub async fn {method_snake}(&self, input: {in_ty}, wait_policy: temporal_runtime::WaitPolicy) -> Result<{out_ty}> {{"
);
let _ = writeln!(
out,
" temporal_runtime::update_proto::<{in_ty}, {out_ty}>(&self.inner, \"{}\", &input, wait_policy).await",
u.registered_name
);
let _ = writeln!(out, " }}");
}
let _ = writeln!(out);
}
fn render_with_start_functions(out: &mut String, svc: &ServiceModel) {
for wf in &svc.workflows {
for sref in &wf.attached_signals {
if !sref.start {
continue;
}
let Some(sig) = svc.signals.iter().find(|s| s.rpc_method == sref.rpc_method) else {
continue;
};
render_signal_with_start_fn(out, svc, wf, sig);
}
for uref in &wf.attached_updates {
if !uref.start {
continue;
}
let Some(u) = svc
.updates
.iter()
.find(|uu| uu.rpc_method == uref.rpc_method)
else {
continue;
};
render_update_with_start_fn(out, svc, wf, u);
}
}
}
fn render_signal_with_start_fn(
out: &mut String,
svc: &ServiceModel,
wf: &WorkflowModel,
sig: &SignalModel,
) {
let fn_name = format!("{}_with_start", sig.rpc_method.to_snake_case());
let handle_struct = format!("{}Handle", wf.rpc_method);
let opts_struct = format!("{}StartOptions", wf.rpc_method);
let const_name = format!("{}_WORKFLOW_NAME", wf.rpc_method.to_shouty_snake_case());
let _ = writeln!(
out,
" /// Start `{}` and atomically deliver the `{}` signal.",
wf.registered_name, sig.registered_name
);
let _ = writeln!(out, " pub async fn {fn_name}(");
let _ = writeln!(out, " client: &temporal_runtime::TemporalClient,");
if !sig.input_type.is_empty {
let _ = writeln!(out, " signal_input: {},", sig.input_type.rust_name());
}
if !wf.input_type.is_empty {
let _ = writeln!(
out,
" workflow_input: {},",
wf.input_type.rust_name()
);
}
let _ = writeln!(out, " opts: {opts_struct},");
let _ = writeln!(out, " ) -> Result<{handle_struct}> {{");
let signal_input_expr = if sig.input_type.is_empty {
"&()".to_string()
} else {
"&signal_input".to_string()
};
let workflow_input_expr = if wf.input_type.is_empty {
"&()".to_string()
} else {
"&workflow_input".to_string()
};
let _ = writeln!(
out,
" let workflow_id = opts.workflow_id.clone().unwrap_or_else(|| {{"
);
let _ = writeln!(
out,
" {}",
id_fallback_call(wf, false)
);
let _ = writeln!(out, " }});");
if let Some(tq) = effective_task_queue(svc, wf) {
let _ = writeln!(
out,
" let task_queue = opts.task_queue.unwrap_or_else(|| \"{tq}\".to_string());"
);
} else {
let _ = writeln!(
out,
" let task_queue = opts.task_queue.expect(\"workflow has no proto-level task_queue; opts.task_queue is required\");"
);
}
let _ = writeln!(
out,
" let inner = temporal_runtime::signal_with_start_workflow_proto("
);
let _ = writeln!(out, " client,");
let _ = writeln!(out, " {const_name},");
let _ = writeln!(out, " &workflow_id,");
let _ = writeln!(out, " &task_queue,");
let _ = writeln!(out, " {workflow_input_expr},");
let _ = writeln!(out, " \"{}\",", sig.registered_name);
let _ = writeln!(out, " {signal_input_expr},");
let _ = writeln!(out, " opts.id_reuse_policy,");
let _ = writeln!(out, " opts.execution_timeout,");
let _ = writeln!(out, " opts.run_timeout,");
let _ = writeln!(out, " opts.task_timeout,");
let _ = writeln!(out, " ).await?;");
let _ = writeln!(out, " Ok({handle_struct} {{ inner }})");
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
fn render_update_with_start_fn(
out: &mut String,
svc: &ServiceModel,
wf: &WorkflowModel,
u: &UpdateModel,
) {
let fn_name = format!("{}_with_start", u.rpc_method.to_snake_case());
let handle_struct = format!("{}Handle", wf.rpc_method);
let opts_struct = format!("{}StartOptions", wf.rpc_method);
let const_name = format!("{}_WORKFLOW_NAME", wf.rpc_method.to_shouty_snake_case());
let _ = writeln!(
out,
" /// Start `{}` and atomically deliver the `{}` update.",
wf.registered_name, u.registered_name
);
let _ = writeln!(out, " pub async fn {fn_name}(");
let _ = writeln!(out, " client: &temporal_runtime::TemporalClient,");
if !u.input_type.is_empty {
let _ = writeln!(out, " update_input: {},", u.input_type.rust_name());
}
if !wf.input_type.is_empty {
let _ = writeln!(
out,
" workflow_input: {},",
wf.input_type.rust_name()
);
}
let _ = writeln!(out, " opts: {opts_struct},");
let _ = writeln!(out, " wait_policy: temporal_runtime::WaitPolicy,");
let _ = writeln!(
out,
" ) -> Result<({handle_struct}, {})> {{",
u.output_type.rust_name()
);
let update_input_expr = if u.input_type.is_empty {
"&()".to_string()
} else {
"&update_input".to_string()
};
let workflow_input_expr = if wf.input_type.is_empty {
"&()".to_string()
} else {
"&workflow_input".to_string()
};
let _ = writeln!(
out,
" let workflow_id = opts.workflow_id.clone().unwrap_or_else(|| {{"
);
let _ = writeln!(
out,
" {}",
id_fallback_call(wf, false)
);
let _ = writeln!(out, " }});");
if let Some(tq) = effective_task_queue(svc, wf) {
let _ = writeln!(
out,
" let task_queue = opts.task_queue.unwrap_or_else(|| \"{tq}\".to_string());"
);
} else {
let _ = writeln!(
out,
" let task_queue = opts.task_queue.expect(\"workflow has no proto-level task_queue; opts.task_queue is required\");"
);
}
let _ = writeln!(
out,
" let (inner, update_result) = temporal_runtime::update_with_start_workflow_proto::<{}, {}, {}>(",
wf.input_type.rust_name(),
u.input_type.rust_name(),
u.output_type.rust_name(),
);
let _ = writeln!(out, " client,");
let _ = writeln!(out, " {const_name},");
let _ = writeln!(out, " &workflow_id,");
let _ = writeln!(out, " &task_queue,");
let _ = writeln!(out, " {workflow_input_expr},");
let _ = writeln!(out, " \"{}\",", u.registered_name);
let _ = writeln!(out, " {update_input_expr},");
let _ = writeln!(out, " wait_policy,");
let _ = writeln!(out, " opts.id_reuse_policy,");
let _ = writeln!(out, " opts.execution_timeout,");
let _ = writeln!(out, " opts.run_timeout,");
let _ = writeln!(out, " opts.task_timeout,");
let _ = writeln!(out, " ).await?;");
let _ = writeln!(
out,
" Ok(({handle_struct} {{ inner }}, update_result))"
);
let _ = writeln!(out, " }}");
let _ = writeln!(out);
}
fn effective_task_queue<'a>(svc: &'a ServiceModel, wf: &'a WorkflowModel) -> Option<&'a str> {
wf.task_queue
.as_deref()
.or(svc.default_task_queue.as_deref())
}
fn duration_literal(d: std::time::Duration) -> String {
let secs = d.as_secs();
let nanos = d.subsec_nanos();
if nanos == 0 {
format!("Duration::from_secs({secs})")
} else {
format!("Duration::new({secs}, {nanos})")
}
}
fn mod_name(svc: &ServiceModel) -> String {
format!(
"{}_{}_temporal",
svc.package.replace('.', "_"),
svc.service.to_snake_case()
)
}
fn proto_module_path(package: &str) -> String {
let mut p = String::from("crate");
if package.is_empty() {
return p;
}
for seg in package.split('.') {
p.push_str("::");
p.push_str(seg);
}
p
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mod_name_lowers_dots_and_camel() {
let svc = make_service("jobs.v1", "JobService");
assert_eq!(mod_name(&svc), "jobs_v1_job_service_temporal");
}
#[test]
fn proto_module_path_walks_package() {
assert_eq!(proto_module_path("jobs.v1"), "crate::jobs::v1");
assert_eq!(proto_module_path(""), "crate");
}
fn make_service(package: &str, service: &str) -> ServiceModel {
ServiceModel {
package: package.to_string(),
service: service.to_string(),
source_file: "test.proto".to_string(),
default_task_queue: None,
workflows: vec![],
signals: vec![],
queries: vec![],
updates: vec![],
activities: vec![],
}
}
}