protoc_gen_rust_temporal/model.rs
1//! Internal representation produced by `parse.rs` and consumed by `render.rs`.
2//!
3//! The schema deliberately mirrors cludden's `temporal.v1.*` annotation
4//! surface (see `proto/temporal/v1/temporal.proto`), only retaining the
5//! fields needed for v1 Rust client emit. Anything we read but ignore (XNS,
6//! patches, CLI options) lives in the descriptor pool and is silently
7//! dropped here.
8
9use std::time::Duration;
10
11/// One Temporal-bearing proto service after parsing + validation.
12#[derive(Debug)]
13pub struct ServiceModel {
14 /// Fully-qualified proto package, e.g. `"jobs.v1"`.
15 pub package: String,
16 /// Service name from the proto, e.g. `"JobService"`.
17 pub service: String,
18 /// Source `.proto` file path as `protoc` saw it.
19 pub source_file: String,
20 /// `temporal.v1.service.task_queue` if the service carries the annotation.
21 /// Used as the default `task_queue` when a workflow does not override it.
22 pub default_task_queue: Option<String>,
23 pub workflows: Vec<WorkflowModel>,
24 pub signals: Vec<SignalModel>,
25 pub queries: Vec<QueryModel>,
26 pub updates: Vec<UpdateModel>,
27 pub activities: Vec<ActivityModel>,
28}
29
30#[derive(Debug)]
31pub struct WorkflowModel {
32 /// Rpc method name as declared in proto (e.g. `"RunJob"`).
33 pub rpc_method: String,
34 /// Cross-language workflow registration name. Defaults to
35 /// `"<package>.<Service>/<rpc>"` when `WorkflowOptions.name` is empty.
36 pub registered_name: String,
37 pub input_type: ProtoType,
38 pub output_type: ProtoType,
39 /// Effective task queue: `WorkflowOptions.task_queue` if set, else the
40 /// service-level default. `None` means neither was supplied — render
41 /// will require the caller to pass one.
42 pub task_queue: Option<String>,
43 /// Parsed form of cludden's `id` Go-template expression, compiled at
44 /// parse time against the workflow's input message descriptor. Each
45 /// segment is either a literal piece of the template or a reference to
46 /// a field on the input message. Render emits a private
47 /// `<wf>_id(input: &Input) -> String` function that walks the segments
48 /// via `format!`, so the substitution happens at codegen time — no
49 /// runtime template engine required.
50 pub id_expression: Option<Vec<IdTemplateSegment>>,
51 pub id_reuse_policy: Option<IdReusePolicy>,
52 pub execution_timeout: Option<Duration>,
53 pub run_timeout: Option<Duration>,
54 pub task_timeout: Option<Duration>,
55 /// Additional names this workflow is also registered under.
56 pub aliases: Vec<String>,
57 pub attached_signals: Vec<SignalRef>,
58 pub attached_queries: Vec<QueryRef>,
59 pub attached_updates: Vec<UpdateRef>,
60}
61
62/// Reference from a `WorkflowOptions.signal` entry to a sibling signal rpc.
63#[derive(Debug, Clone)]
64pub struct SignalRef {
65 /// Value of the `ref` field — must match a sibling rpc method name.
66 pub rpc_method: String,
67 /// If `true`, emit a `_with_start` free function alongside the client.
68 pub start: bool,
69}
70
71#[derive(Debug, Clone)]
72pub struct QueryRef {
73 pub rpc_method: String,
74}
75
76#[derive(Debug, Clone)]
77pub struct UpdateRef {
78 pub rpc_method: String,
79 pub start: bool,
80 pub validate: Option<bool>,
81}
82
83#[derive(Debug)]
84pub struct SignalModel {
85 pub rpc_method: String,
86 /// Cross-language signal name. Defaults to `rpc_method`.
87 pub registered_name: String,
88 pub input_type: ProtoType,
89 /// Must be `google.protobuf.Empty` — validated.
90 pub output_type: ProtoType,
91}
92
93#[derive(Debug)]
94pub struct QueryModel {
95 pub rpc_method: String,
96 pub registered_name: String,
97 pub input_type: ProtoType,
98 pub output_type: ProtoType,
99}
100
101#[derive(Debug)]
102pub struct UpdateModel {
103 pub rpc_method: String,
104 pub registered_name: String,
105 pub input_type: ProtoType,
106 pub output_type: ProtoType,
107 /// Whether `UpdateOptions.validate` was set on this rpc.
108 pub validate: bool,
109}
110
111#[derive(Debug)]
112pub struct ActivityModel {
113 /// Rpc method name. Activity emit is validate-only in v1, but we still
114 /// resolve names so collisions with workflow / signal / query / update
115 /// can be rejected.
116 pub rpc_method: String,
117 pub registered_name: String,
118 pub input_type: ProtoType,
119 pub output_type: ProtoType,
120}
121
122/// A proto type reference, resolved to its fully-qualified name.
123#[derive(Debug, Clone, PartialEq, Eq)]
124pub struct ProtoType {
125 /// Fully-qualified proto type name, e.g. `"jobs.v1.JobInput"` — never
126 /// includes the leading `.` that descriptors use.
127 pub full_name: String,
128 /// `true` when the type is `google.protobuf.Empty`.
129 pub is_empty: bool,
130}
131
132impl ProtoType {
133 pub fn new(full_name: impl Into<String>) -> Self {
134 let full_name = full_name.into();
135 let normalised = full_name
136 .strip_prefix('.')
137 .unwrap_or(&full_name)
138 .to_string();
139 let is_empty = normalised == "google.protobuf.Empty";
140 Self {
141 full_name: normalised,
142 is_empty,
143 }
144 }
145
146 /// Final path segment of `full_name`. For `Empty`, returns `"()"` to
147 /// reflect the render-time substitution.
148 pub fn rust_name(&self) -> &str {
149 if self.is_empty {
150 return "()";
151 }
152 self.full_name.rsplit('.').next().unwrap_or(&self.full_name)
153 }
154}
155
156/// One segment of a workflow's `id` template, resolved against the
157/// workflow input message's descriptor at parse time.
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub enum IdTemplateSegment {
160 /// A literal piece of the template — emitted verbatim into the
161 /// generated `format!`.
162 Literal(String),
163 /// A reference to a field on the workflow input message. The string
164 /// is the **Rust** field name (snake_case), so generated code can
165 /// substitute `input.<field>` directly. Validated to exist on the
166 /// input descriptor at parse time.
167 Field(String),
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171pub enum IdReusePolicy {
172 AllowDuplicate,
173 AllowDuplicateFailedOnly,
174 RejectDuplicate,
175 TerminateIfRunning,
176}
177
178impl IdReusePolicy {
179 /// Variant identifier on `temporalio_common::WorkflowIdReusePolicy`.
180 pub fn rust_variant(self) -> &'static str {
181 match self {
182 Self::AllowDuplicate => "AllowDuplicate",
183 Self::AllowDuplicateFailedOnly => "AllowDuplicateFailedOnly",
184 Self::RejectDuplicate => "RejectDuplicate",
185 Self::TerminateIfRunning => "TerminateIfRunning",
186 }
187 }
188}