Skip to main content

temporalio_protos/protos/
mod.rs

1//! Contains the protobuf definitions used as arguments to and return values from interactions with
2//! the Temporal Core SDK. Language SDK authors can generate structs using the proto definitions
3//! that will match the generated structs in this module.
4
5pub mod constants;
6mod task_token;
7/// Utility functions for working with protobuf types.
8pub mod utilities;
9pub use task_token::TaskToken;
10
11/// Payload metadata key that identifies the encoding format.
12pub static ENCODING_PAYLOAD_KEY: &str = "encoding";
13/// The metadata value for JSON-encoded payloads.
14pub static JSON_ENCODING_VAL: &str = "json/plain";
15/// The details key used in patched marker payloads.
16pub static PATCHED_MARKER_DETAILS_KEY: &str = "patch-data";
17/// The search attribute key used when registering change versions
18pub static VERSION_SEARCH_ATTR_KEY: &str = "TemporalChangeVersion";
19
20macro_rules! include_proto_with_serde {
21    ($pkg:tt) => {
22        tonic::include_proto!($pkg);
23
24        #[cfg(feature = "serde_serialize")]
25        include!(concat!(env!("OUT_DIR"), concat!("/", $pkg, ".serde.rs")));
26    };
27}
28
29#[allow(
30    clippy::large_enum_variant,
31    clippy::derive_partial_eq_without_eq,
32    clippy::reserve_after_initialization
33)]
34// I'd prefer not to do this, but there are some generated things that just don't need it.
35#[allow(missing_docs)]
36pub mod coresdk {
37    //! Contains all protobufs relating to communication between core and lang-specific SDKs
38    tonic::include_proto!("coresdk");
39    pub use self::sdk_helpers::*;
40    mod sdk_helpers {
41        use super::*;
42
43        use crate::protos::{
44            ENCODING_PAYLOAD_KEY, JSON_ENCODING_VAL,
45            temporal::api::{
46                common::v1::{Payload, Payloads, RetryPolicy, WorkflowExecution},
47                enums::v1::{
48                    ApplicationErrorCategory, TimeoutType, VersioningBehavior,
49                    WorkflowTaskFailedCause,
50                },
51                failure::v1::{
52                    ActivityFailureInfo, ApplicationFailureInfo, Failure, TimeoutFailureInfo,
53                    failure::FailureInfo,
54                },
55                workflowservice::v1::PollActivityTaskQueueResponse,
56            },
57        };
58        use activity_task::ActivityTask;
59        use serde::{Deserialize, Serialize};
60        use std::{
61            collections::HashMap,
62            convert::TryFrom,
63            fmt::{Display, Formatter},
64            iter::FromIterator,
65        };
66        use workflow_activation::{WorkflowActivationJob, workflow_activation_job};
67        use workflow_commands::{WorkflowCommand, workflow_command, workflow_command::Variant};
68        use workflow_completion::{WorkflowActivationCompletion, workflow_activation_completion};
69
70        pub type HistoryEventId = i64;
71
72        impl From<workflow_activation_job::Variant> for WorkflowActivationJob {
73            fn from(a: workflow_activation_job::Variant) -> Self {
74                Self { variant: Some(a) }
75            }
76        }
77
78        impl From<Vec<WorkflowCommand>> for workflow_completion::Success {
79            fn from(v: Vec<WorkflowCommand>) -> Self {
80                Self {
81                    commands: v,
82                    used_internal_flags: vec![],
83                    versioning_behavior: VersioningBehavior::Unspecified.into(),
84                }
85            }
86        }
87
88        impl From<workflow_command::Variant> for WorkflowCommand {
89            fn from(v: workflow_command::Variant) -> Self {
90                Self {
91                    variant: Some(v),
92                    ..Default::default()
93                }
94            }
95        }
96
97        impl workflow_completion::Success {
98            pub fn from_variants(cmds: Vec<Variant>) -> Self {
99                let cmds: Vec<_> = cmds.into_iter().map(|c| c.into()).collect();
100                cmds.into()
101            }
102        }
103
104        impl WorkflowActivationCompletion {
105            /// Create a successful activation with no commands in it
106            pub fn empty(run_id: impl Into<String>) -> Self {
107                let success = workflow_completion::Success::from_variants(vec![]);
108                Self {
109                    run_id: run_id.into(),
110                    status: Some(workflow_activation_completion::Status::Successful(success)),
111                    ..Default::default()
112                }
113            }
114
115            /// Create a successful activation from a list of command variants
116            pub fn from_cmds(
117                run_id: impl Into<String>,
118                cmds: Vec<workflow_command::Variant>,
119            ) -> Self {
120                let success = workflow_completion::Success::from_variants(cmds);
121                Self {
122                    run_id: run_id.into(),
123                    status: Some(workflow_activation_completion::Status::Successful(success)),
124                    ..Default::default()
125                }
126            }
127
128            /// Create a successful activation from just one command variant
129            pub fn from_cmd(run_id: impl Into<String>, cmd: workflow_command::Variant) -> Self {
130                let success = workflow_completion::Success::from_variants(vec![cmd]);
131                Self {
132                    run_id: run_id.into(),
133                    status: Some(workflow_activation_completion::Status::Successful(success)),
134                    ..Default::default()
135                }
136            }
137
138            pub fn fail(
139                run_id: impl Into<String>,
140                failure: Failure,
141                cause: Option<WorkflowTaskFailedCause>,
142            ) -> Self {
143                Self {
144                    run_id: run_id.into(),
145                    status: Some(workflow_activation_completion::Status::Failed(
146                        workflow_completion::Failure {
147                            failure: Some(failure),
148                            force_cause: cause.unwrap_or(WorkflowTaskFailedCause::Unspecified)
149                                as i32,
150                        },
151                    )),
152                    ..Default::default()
153                }
154            }
155
156            /// Returns true if the activation has either a fail, continue, cancel, or complete workflow
157            /// execution command in it.
158            pub fn has_execution_ending(&self) -> bool {
159                self.has_complete_workflow_execution()
160                    || self.has_fail_execution()
161                    || self.has_continue_as_new()
162                    || self.has_cancel_workflow_execution()
163            }
164
165            /// Returns true if the activation contains a fail workflow execution command
166            pub fn has_fail_execution(&self) -> bool {
167                if let Some(workflow_activation_completion::Status::Successful(s)) = &self.status {
168                    return s.commands.iter().any(|wfc| {
169                        matches!(
170                            wfc,
171                            WorkflowCommand {
172                                variant: Some(workflow_command::Variant::FailWorkflowExecution(_)),
173                                ..
174                            }
175                        )
176                    });
177                }
178                false
179            }
180
181            /// Returns true if the activation contains a cancel workflow execution command
182            pub fn has_cancel_workflow_execution(&self) -> bool {
183                if let Some(workflow_activation_completion::Status::Successful(s)) = &self.status {
184                    return s.commands.iter().any(|wfc| {
185                        matches!(
186                            wfc,
187                            WorkflowCommand {
188                                variant: Some(workflow_command::Variant::CancelWorkflowExecution(
189                                    _
190                                )),
191                                ..
192                            }
193                        )
194                    });
195                }
196                false
197            }
198
199            /// Returns true if the activation contains a continue as new workflow execution command
200            pub fn has_continue_as_new(&self) -> bool {
201                if let Some(workflow_activation_completion::Status::Successful(s)) = &self.status {
202                    return s.commands.iter().any(|wfc| {
203                        matches!(
204                            wfc,
205                            WorkflowCommand {
206                                variant: Some(
207                                    workflow_command::Variant::ContinueAsNewWorkflowExecution(_)
208                                ),
209                                ..
210                            }
211                        )
212                    });
213                }
214                false
215            }
216
217            /// Returns true if the activation contains a complete workflow execution command
218            pub fn has_complete_workflow_execution(&self) -> bool {
219                self.complete_workflow_execution_value().is_some()
220            }
221
222            /// Returns the completed execution result value, if any
223            pub fn complete_workflow_execution_value(&self) -> Option<&Payload> {
224                if let Some(workflow_activation_completion::Status::Successful(s)) = &self.status {
225                    s.commands.iter().find_map(|wfc| match wfc {
226                        WorkflowCommand {
227                            variant: Some(workflow_command::Variant::CompleteWorkflowExecution(v)),
228                            ..
229                        } => v.result.as_ref(),
230                        _ => None,
231                    })
232                } else {
233                    None
234                }
235            }
236
237            /// Returns true if the activation completion is a success with no commands
238            pub fn is_empty(&self) -> bool {
239                if let Some(workflow_activation_completion::Status::Successful(s)) = &self.status {
240                    return s.commands.is_empty();
241                }
242                false
243            }
244
245            pub fn add_internal_flags(&mut self, patch: u32) {
246                if let Some(workflow_activation_completion::Status::Successful(s)) =
247                    &mut self.status
248                {
249                    s.used_internal_flags.push(patch);
250                }
251            }
252        }
253
254        /// Makes converting outgoing lang commands into [WorkflowActivationCompletion]s easier
255        pub trait IntoCompletion {
256            /// The conversion function
257            fn into_completion(self, run_id: String) -> WorkflowActivationCompletion;
258        }
259
260        impl IntoCompletion for workflow_command::Variant {
261            fn into_completion(self, run_id: String) -> WorkflowActivationCompletion {
262                WorkflowActivationCompletion::from_cmd(run_id, self)
263            }
264        }
265
266        impl<I, V> IntoCompletion for I
267        where
268            I: IntoIterator<Item = V>,
269            V: Into<WorkflowCommand>,
270        {
271            fn into_completion(self, run_id: String) -> WorkflowActivationCompletion {
272                let success = self.into_iter().map(Into::into).collect::<Vec<_>>().into();
273                WorkflowActivationCompletion {
274                    run_id,
275                    status: Some(workflow_activation_completion::Status::Successful(success)),
276                    ..Default::default()
277                }
278            }
279        }
280
281        impl Display for WorkflowActivationCompletion {
282            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
283                write!(
284                    f,
285                    "WorkflowActivationCompletion(run_id: {}, status: ",
286                    &self.run_id
287                )?;
288                match &self.status {
289                    None => write!(f, "empty")?,
290                    Some(s) => write!(f, "{s}")?,
291                };
292                write!(f, ")")
293            }
294        }
295
296        impl Display for workflow_activation_completion::Status {
297            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
298                match self {
299                    workflow_activation_completion::Status::Successful(
300                        workflow_completion::Success { commands, .. },
301                    ) => {
302                        write!(f, "Success(")?;
303                        let mut written = 0;
304                        for c in commands {
305                            write!(f, "{c} ")?;
306                            written += 1;
307                            if written >= 10 && written < commands.len() {
308                                write!(f, "... {} more", commands.len() - written)?;
309                                break;
310                            }
311                        }
312                        write!(f, ")")
313                    }
314                    workflow_activation_completion::Status::Failed(_) => {
315                        write!(f, "Failed")
316                    }
317                }
318            }
319        }
320
321        impl ActivityTask {
322            pub fn start_from_poll_resp(r: PollActivityTaskQueueResponse) -> Self {
323                let (workflow_id, run_id) = r
324                    .workflow_execution
325                    .map(|we| (we.workflow_id, we.run_id))
326                    .unwrap_or_default();
327                Self {
328                    task_token: r.task_token,
329                    variant: Some(activity_task::activity_task::Variant::Start(
330                        activity_task::Start {
331                            workflow_namespace: r.workflow_namespace,
332                            workflow_type: r
333                                .workflow_type
334                                .map_or_else(|| "".to_string(), |wt| wt.name),
335                            workflow_execution: Some(WorkflowExecution {
336                                workflow_id,
337                                run_id,
338                            }),
339                            activity_id: r.activity_id,
340                            activity_type: r
341                                .activity_type
342                                .map_or_else(|| "".to_string(), |at| at.name),
343                            header_fields: r.header.map(Into::into).unwrap_or_default(),
344                            input: Vec::from_payloads(r.input),
345                            heartbeat_details: Vec::from_payloads(r.heartbeat_details),
346                            scheduled_time: r.scheduled_time,
347                            current_attempt_scheduled_time: r.current_attempt_scheduled_time,
348                            started_time: r.started_time,
349                            attempt: r.attempt as u32,
350                            schedule_to_close_timeout: r.schedule_to_close_timeout,
351                            start_to_close_timeout: r.start_to_close_timeout,
352                            heartbeat_timeout: r.heartbeat_timeout,
353                            retry_policy: r.retry_policy.map(fix_retry_policy),
354                            priority: r.priority,
355                            is_local: false,
356                            run_id: r.activity_run_id,
357                        },
358                    )),
359                }
360            }
361        }
362
363        impl Failure {
364            pub fn is_timeout(
365                &self,
366            ) -> Option<crate::protos::temporal::api::enums::v1::TimeoutType> {
367                match &self.failure_info {
368                    Some(FailureInfo::TimeoutFailureInfo(ti)) => Some(ti.timeout_type()),
369                    _ => {
370                        if let Some(c) = &self.cause {
371                            c.is_timeout()
372                        } else {
373                            None
374                        }
375                    }
376                }
377            }
378
379            pub fn application_failure(message: String, non_retryable: bool) -> Self {
380                Self {
381                    message,
382                    failure_info: Some(FailureInfo::ApplicationFailureInfo(
383                        ApplicationFailureInfo {
384                            non_retryable,
385                            ..Default::default()
386                        },
387                    )),
388                    ..Default::default()
389                }
390            }
391
392            pub fn application_failure_from_error(ae: anyhow::Error, non_retryable: bool) -> Self {
393                Self {
394                    failure_info: Some(FailureInfo::ApplicationFailureInfo(
395                        ApplicationFailureInfo {
396                            non_retryable,
397                            ..Default::default()
398                        },
399                    )),
400                    ..ae.chain()
401                        .rfold(None, |cause, e| {
402                            Some(Self {
403                                message: e.to_string(),
404                                cause: cause.map(Box::new),
405                                ..Default::default()
406                            })
407                        })
408                        .unwrap_or_default()
409                }
410            }
411
412            pub fn timeout(timeout_type: TimeoutType) -> Self {
413                Self {
414                    message: "Activity timed out".to_string(),
415                    cause: Some(Box::new(Failure {
416                        message: "Activity timed out".to_string(),
417                        failure_info: Some(FailureInfo::TimeoutFailureInfo(TimeoutFailureInfo {
418                            timeout_type: timeout_type.into(),
419                            ..Default::default()
420                        })),
421                        ..Default::default()
422                    })),
423                    failure_info: Some(FailureInfo::ActivityFailureInfo(
424                        ActivityFailureInfo::default(),
425                    )),
426                    ..Default::default()
427                }
428            }
429
430            /// Extracts an ApplicationFailureInfo from a Failure instance if it exists
431            pub fn maybe_application_failure(&self) -> Option<&ApplicationFailureInfo> {
432                if let Failure {
433                    failure_info: Some(FailureInfo::ApplicationFailureInfo(f)),
434                    ..
435                } = self
436                {
437                    Some(f)
438                } else {
439                    None
440                }
441            }
442
443            // Checks if a failure is an ApplicationFailure with Benign category.
444            pub fn is_benign_application_failure(&self) -> bool {
445                self.maybe_application_failure()
446                    .is_some_and(|app_info| app_info.category() == ApplicationErrorCategory::Benign)
447            }
448        }
449
450        impl Display for Failure {
451            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
452                write!(f, "Failure({}, ", self.message)?;
453                match self.failure_info.as_ref() {
454                    None => write!(f, "missing info")?,
455                    Some(FailureInfo::TimeoutFailureInfo(v)) => {
456                        write!(f, "Timeout: {:?}", v.timeout_type())?;
457                    }
458                    Some(FailureInfo::ApplicationFailureInfo(v)) => {
459                        write!(f, "Application Failure: {}", v.r#type)?;
460                    }
461                    Some(FailureInfo::CanceledFailureInfo(_)) => {
462                        write!(f, "Cancelled")?;
463                    }
464                    Some(FailureInfo::TerminatedFailureInfo(_)) => {
465                        write!(f, "Terminated")?;
466                    }
467                    Some(FailureInfo::ServerFailureInfo(_)) => {
468                        write!(f, "Server Failure")?;
469                    }
470                    Some(FailureInfo::ResetWorkflowFailureInfo(_)) => {
471                        write!(f, "Reset Workflow")?;
472                    }
473                    Some(FailureInfo::ActivityFailureInfo(v)) => {
474                        write!(
475                            f,
476                            "Activity Failure: scheduled_event_id: {}",
477                            v.scheduled_event_id
478                        )?;
479                    }
480                    Some(FailureInfo::ChildWorkflowExecutionFailureInfo(v)) => {
481                        write!(
482                            f,
483                            "Child Workflow: started_event_id: {}",
484                            v.started_event_id
485                        )?;
486                    }
487                    Some(FailureInfo::NexusOperationExecutionFailureInfo(v)) => {
488                        write!(
489                            f,
490                            "Nexus Operation Failure: scheduled_event_id: {}",
491                            v.scheduled_event_id
492                        )?;
493                    }
494                    Some(FailureInfo::NexusHandlerFailureInfo(v)) => {
495                        write!(f, "Nexus Handler Failure: {}", v.r#type)?;
496                    }
497                }
498                write!(f, ")")
499            }
500        }
501
502        impl From<&str> for Failure {
503            fn from(v: &str) -> Self {
504                Failure::application_failure(v.to_string(), false)
505            }
506        }
507
508        impl From<String> for Failure {
509            fn from(v: String) -> Self {
510                Failure::application_failure(v, false)
511            }
512        }
513
514        impl From<anyhow::Error> for Failure {
515            fn from(ae: anyhow::Error) -> Self {
516                Failure::application_failure_from_error(ae, false)
517            }
518        }
519
520        pub trait FromPayloadsExt {
521            fn from_payloads(p: Option<Payloads>) -> Self;
522        }
523        impl<T> FromPayloadsExt for T
524        where
525            T: FromIterator<Payload>,
526        {
527            fn from_payloads(p: Option<Payloads>) -> Self {
528                match p {
529                    None => std::iter::empty().collect(),
530                    Some(p) => p.payloads.into_iter().collect(),
531                }
532            }
533        }
534
535        pub trait IntoPayloadsExt {
536            fn into_payloads(self) -> Option<Payloads>;
537        }
538        impl<T> IntoPayloadsExt for T
539        where
540            T: IntoIterator<Item = Payload>,
541        {
542            fn into_payloads(self) -> Option<Payloads> {
543                let mut iterd = self.into_iter().peekable();
544                if iterd.peek().is_none() {
545                    None
546                } else {
547                    Some(Payloads {
548                        payloads: iterd.collect(),
549                    })
550                }
551            }
552        }
553
554        impl From<Payload> for Payloads {
555            fn from(p: Payload) -> Self {
556                Self { payloads: vec![p] }
557            }
558        }
559
560        impl<T> From<T> for Payloads
561        where
562            T: AsRef<[u8]>,
563        {
564            fn from(v: T) -> Self {
565                Self {
566                    payloads: vec![v.into()],
567                }
568            }
569        }
570
571        #[derive(thiserror::Error, Debug)]
572        pub enum PayloadDeserializeErr {
573            /// This deserializer does not handle this type of payload. Allows composing multiple
574            /// deserializers.
575            #[error("This deserializer does not understand this payload")]
576            DeserializerDoesNotHandle,
577            #[error("Error during deserialization: {0}")]
578            DeserializeErr(#[from] anyhow::Error),
579        }
580
581        // TODO: Once the prototype SDK is un-prototyped this serialization will need to be compat with
582        //   other SDKs (given they might execute an activity).
583        pub trait AsJsonPayloadExt {
584            fn as_json_payload(&self) -> anyhow::Result<Payload>;
585        }
586        impl<T> AsJsonPayloadExt for T
587        where
588            T: Serialize,
589        {
590            fn as_json_payload(&self) -> anyhow::Result<Payload> {
591                let as_json = serde_json::to_string(self)?;
592                let mut metadata = HashMap::new();
593                metadata.insert(
594                    ENCODING_PAYLOAD_KEY.to_string(),
595                    JSON_ENCODING_VAL.as_bytes().to_vec(),
596                );
597                Ok(Payload {
598                    metadata,
599                    data: as_json.into_bytes(),
600                    external_payloads: Default::default(),
601                })
602            }
603        }
604
605        pub trait FromJsonPayloadExt: Sized {
606            fn from_json_payload(payload: &Payload) -> Result<Self, PayloadDeserializeErr>;
607        }
608        impl<T> FromJsonPayloadExt for T
609        where
610            T: for<'de> Deserialize<'de>,
611        {
612            fn from_json_payload(payload: &Payload) -> Result<Self, PayloadDeserializeErr> {
613                if !payload.is_json_payload() {
614                    return Err(PayloadDeserializeErr::DeserializerDoesNotHandle);
615                }
616                let payload_str =
617                    std::str::from_utf8(&payload.data).map_err(anyhow::Error::from)?;
618                Ok(serde_json::from_str(payload_str).map_err(anyhow::Error::from)?)
619            }
620        }
621
622        /// Errors when converting from a [Payloads] api proto to our internal [Payload]
623        #[derive(derive_more::Display, Debug)]
624        pub enum PayloadsToPayloadError {
625            MoreThanOnePayload,
626            NoPayload,
627        }
628        impl TryFrom<Payloads> for Payload {
629            type Error = PayloadsToPayloadError;
630
631            fn try_from(mut v: Payloads) -> Result<Self, Self::Error> {
632                match v.payloads.pop() {
633                    None => Err(PayloadsToPayloadError::NoPayload),
634                    Some(p) => {
635                        if v.payloads.is_empty() {
636                            Ok(p)
637                        } else {
638                            Err(PayloadsToPayloadError::MoreThanOnePayload)
639                        }
640                    }
641                }
642            }
643        }
644
645        /// If initial_interval is missing, fills it with zero value to prevent crashes
646        /// (lang assumes that RetryPolicy always has initial_interval set).
647        pub(super) fn fix_retry_policy(mut retry_policy: RetryPolicy) -> RetryPolicy {
648            if retry_policy.initial_interval.is_none() {
649                retry_policy.initial_interval = Default::default();
650            }
651            retry_policy
652        }
653    }
654    #[allow(clippy::module_inception)]
655    pub mod activity_task {
656        tonic::include_proto!("coresdk.activity_task");
657        mod sdk_helpers {
658            use super::*;
659            use crate::protos::{coresdk::ActivityTaskCompletion, task_token::format_task_token};
660            use std::fmt::{Display, Formatter};
661
662            impl ActivityTask {
663                pub fn cancel_from_ids(
664                    task_token: Vec<u8>,
665                    reason: ActivityCancelReason,
666                    details: ActivityCancellationDetails,
667                ) -> Self {
668                    Self {
669                        task_token,
670                        variant: Some(activity_task::Variant::Cancel(Cancel {
671                            reason: reason as i32,
672                            details: Some(details),
673                        })),
674                    }
675                }
676
677                // Checks if both the primary reason or details have a timeout cancellation.
678                pub fn is_timeout(&self) -> bool {
679                    match &self.variant {
680                        Some(activity_task::Variant::Cancel(Cancel { reason, details })) => {
681                            *reason == ActivityCancelReason::TimedOut as i32
682                                || details.as_ref().is_some_and(|d| d.is_timed_out)
683                        }
684                        _ => false,
685                    }
686                }
687
688                pub fn primary_reason_to_cancellation_details(
689                    reason: ActivityCancelReason,
690                ) -> ActivityCancellationDetails {
691                    ActivityCancellationDetails {
692                        is_not_found: reason == ActivityCancelReason::NotFound,
693                        is_cancelled: reason == ActivityCancelReason::Cancelled,
694                        is_paused: reason == ActivityCancelReason::Paused,
695                        is_timed_out: reason == ActivityCancelReason::TimedOut,
696                        is_worker_shutdown: reason == ActivityCancelReason::WorkerShutdown,
697                        is_reset: reason == ActivityCancelReason::Reset,
698                    }
699                }
700            }
701
702            impl Display for ActivityTaskCompletion {
703                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
704                    write!(
705                        f,
706                        "ActivityTaskCompletion(token: {}",
707                        format_task_token(&self.task_token),
708                    )?;
709                    if let Some(r) = self.result.as_ref().and_then(|r| r.status.as_ref()) {
710                        write!(f, ", {r}")?;
711                    } else {
712                        write!(f, ", missing result")?;
713                    }
714                    write!(f, ")")
715                }
716            }
717        }
718    }
719    #[allow(clippy::module_inception)]
720    pub mod activity_result {
721        tonic::include_proto!("coresdk.activity_result");
722        mod sdk_helpers {
723            use super::*;
724            use crate::protos::{
725                coresdk::activity_result::activity_resolution::Status,
726                temporal::api::{
727                    common::v1::Payload,
728                    enums::v1::TimeoutType,
729                    failure::v1::{CanceledFailureInfo, Failure as APIFailure, failure},
730                },
731            };
732            use activity_execution_result as aer;
733            use anyhow::anyhow;
734            use std::fmt::{Display, Formatter};
735
736            impl ActivityExecutionResult {
737                pub const fn ok(result: Payload) -> Self {
738                    Self {
739                        status: Some(aer::Status::Completed(Success {
740                            result: Some(result),
741                        })),
742                    }
743                }
744
745                pub fn fail(fail: APIFailure) -> Self {
746                    Self {
747                        status: Some(aer::Status::Failed(Failure {
748                            failure: Some(fail),
749                        })),
750                    }
751                }
752
753                pub fn cancel(fail: APIFailure) -> Self {
754                    Self {
755                        status: Some(aer::Status::Cancelled(Cancellation {
756                            failure: Some(fail),
757                        })),
758                    }
759                }
760
761                pub fn cancel_from_details(payload: Option<Payload>) -> Self {
762                    Self {
763                        status: Some(aer::Status::Cancelled(Cancellation::from_details(payload))),
764                    }
765                }
766
767                pub const fn will_complete_async() -> Self {
768                    Self {
769                        status: Some(aer::Status::WillCompleteAsync(WillCompleteAsync {})),
770                    }
771                }
772
773                pub fn is_cancelled(&self) -> bool {
774                    matches!(self.status, Some(aer::Status::Cancelled(_)))
775                }
776            }
777
778            impl Display for aer::Status {
779                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
780                    write!(f, "ActivityExecutionResult(")?;
781                    match self {
782                        aer::Status::Completed(v) => {
783                            write!(f, "{v})")
784                        }
785                        aer::Status::Failed(v) => {
786                            write!(f, "{v})")
787                        }
788                        aer::Status::Cancelled(v) => {
789                            write!(f, "{v})")
790                        }
791                        aer::Status::WillCompleteAsync(_) => {
792                            write!(f, "Will complete async)")
793                        }
794                    }
795                }
796            }
797
798            impl Display for Success {
799                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
800                    write!(f, "Success(")?;
801                    if let Some(ref v) = self.result {
802                        write!(f, "{v}")?;
803                    }
804                    write!(f, ")")
805                }
806            }
807
808            impl Display for Failure {
809                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
810                    write!(f, "Failure(")?;
811                    if let Some(ref v) = self.failure {
812                        write!(f, "{v}")?;
813                    }
814                    write!(f, ")")
815                }
816            }
817
818            impl Display for Cancellation {
819                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
820                    write!(f, "Cancellation(")?;
821                    if let Some(ref v) = self.failure {
822                        write!(f, "{v}")?;
823                    }
824                    write!(f, ")")
825                }
826            }
827
828            impl From<Result<Payload, APIFailure>> for ActivityExecutionResult {
829                fn from(r: Result<Payload, APIFailure>) -> Self {
830                    Self {
831                        status: match r {
832                            Ok(p) => Some(aer::Status::Completed(Success { result: Some(p) })),
833                            Err(f) => Some(aer::Status::Failed(Failure { failure: Some(f) })),
834                        },
835                    }
836                }
837            }
838
839            impl ActivityResolution {
840                /// Extract an activity's payload if it completed successfully, or return an error for all
841                /// other outcomes.
842                pub fn success_payload_or_error(self) -> Result<Option<Payload>, anyhow::Error> {
843                    let Some(status) = self.status else {
844                        return Err(anyhow!("Activity completed without a status"));
845                    };
846
847                    match status {
848                        activity_resolution::Status::Completed(success) => Ok(success.result),
849                        e => Err(anyhow!("Activity was not successful: {e:?}")),
850                    }
851                }
852
853                pub fn unwrap_ok_payload(self) -> Payload {
854                    self.success_payload_or_error().unwrap().unwrap()
855                }
856
857                pub fn completed_ok(&self) -> bool {
858                    matches!(self.status, Some(activity_resolution::Status::Completed(_)))
859                }
860
861                pub fn failed(&self) -> bool {
862                    matches!(self.status, Some(activity_resolution::Status::Failed(_)))
863                }
864
865                pub fn timed_out(&self) -> Option<TimeoutType> {
866                    match self.status {
867                        Some(activity_resolution::Status::Failed(Failure {
868                            failure: Some(ref f),
869                        })) => f.is_timeout(),
870                        _ => None,
871                    }
872                }
873
874                pub fn cancelled(&self) -> bool {
875                    matches!(self.status, Some(activity_resolution::Status::Cancelled(_)))
876                }
877
878                /// If this resolution is any kind of failure, return the inner failure details. Panics
879                /// if the activity succeeded, is in backoff, or this resolution is malformed.
880                pub fn unwrap_failure(self) -> APIFailure {
881                    match self.status.unwrap() {
882                        Status::Failed(f) => f.failure.unwrap(),
883                        Status::Cancelled(c) => c.failure.unwrap(),
884                        _ => panic!("Actvity did not fail"),
885                    }
886                }
887            }
888
889            impl Cancellation {
890                /// Create a cancellation result from some payload. This is to be used when telling Core
891                /// that an activity completed as cancelled.
892                pub fn from_details(details: Option<Payload>) -> Self {
893                    Cancellation {
894                        failure: Some(APIFailure {
895                            message: "Activity cancelled".to_string(),
896                            failure_info: Some(failure::FailureInfo::CanceledFailureInfo(
897                                CanceledFailureInfo {
898                                    details: details.map(Into::into),
899                                    identity: Default::default(),
900                                },
901                            )),
902                            ..Default::default()
903                        }),
904                    }
905                }
906            }
907        }
908    }
909    pub mod common {
910        tonic::include_proto!("coresdk.common");
911        pub use self::sdk_helpers::*;
912        mod sdk_helpers {
913            use crate::protos::{
914                PATCHED_MARKER_DETAILS_KEY,
915                coresdk::{
916                    AsJsonPayloadExt, FromJsonPayloadExt, IntoPayloadsExt,
917                    external_data::{LocalActivityMarkerData, PatchedMarkerData},
918                },
919                temporal::api::common::v1::{Payload, Payloads},
920            };
921            use std::collections::HashMap;
922
923            pub fn build_has_change_marker_details(
924                patch_id: impl Into<String>,
925                deprecated: bool,
926            ) -> anyhow::Result<HashMap<String, Payloads>> {
927                let mut hm = HashMap::new();
928                let encoded = PatchedMarkerData {
929                    id: patch_id.into(),
930                    deprecated,
931                }
932                .as_json_payload()?;
933                hm.insert(PATCHED_MARKER_DETAILS_KEY.to_string(), encoded.into());
934                Ok(hm)
935            }
936
937            pub fn decode_change_marker_details(
938                details: &HashMap<String, Payloads>,
939            ) -> Option<(String, bool)> {
940                // We used to write change markers with plain bytes, so try to decode if they are
941                // json first, then fall back to that.
942                if let Some(cd) = details.get(PATCHED_MARKER_DETAILS_KEY) {
943                    let decoded =
944                        PatchedMarkerData::from_json_payload(cd.payloads.first()?).ok()?;
945                    return Some((decoded.id, decoded.deprecated));
946                }
947
948                let id_entry = details.get("patch_id")?.payloads.first()?;
949                let deprecated_entry = details.get("deprecated")?.payloads.first()?;
950                let name = std::str::from_utf8(&id_entry.data).ok()?;
951                let deprecated = *deprecated_entry.data.first()? != 0;
952                Some((name.to_string(), deprecated))
953            }
954
955            pub fn build_local_activity_marker_details(
956                metadata: LocalActivityMarkerData,
957                result: Option<Payload>,
958            ) -> HashMap<String, Payloads> {
959                let mut hm = HashMap::new();
960                // It would be more efficient for this to be proto binary, but then it shows up as
961                // meaningless in the Temporal UI...
962                if let Some(jsonified) = metadata.as_json_payload().into_payloads() {
963                    hm.insert("data".to_string(), jsonified);
964                }
965                if let Some(res) = result {
966                    hm.insert("result".to_string(), res.into());
967                }
968                hm
969            }
970
971            /// Given a marker detail map, returns just the local activity info, but not the payload.
972            /// This is fairly inexpensive. Deserializing the whole payload may not be.
973            pub fn extract_local_activity_marker_data(
974                details: &HashMap<String, Payloads>,
975            ) -> Option<LocalActivityMarkerData> {
976                details
977                    .get("data")
978                    .and_then(|p| p.payloads.first())
979                    .and_then(|p| std::str::from_utf8(&p.data).ok())
980                    .and_then(|s| serde_json::from_str(s).ok())
981            }
982
983            /// Given a marker detail map, returns the local activity info and the result payload
984            /// if they are found and the marker data is well-formed. This removes the data from the
985            /// map.
986            pub fn extract_local_activity_marker_details(
987                details: &mut HashMap<String, Payloads>,
988            ) -> (Option<LocalActivityMarkerData>, Option<Payload>) {
989                let data = extract_local_activity_marker_data(details);
990                let result = details.remove("result").and_then(|mut p| p.payloads.pop());
991                (data, result)
992            }
993        }
994    }
995    pub mod external_data {
996        tonic::include_proto!("coresdk.external_data");
997        mod sdk_helpers {
998            use prost_types::{Duration, Timestamp};
999            use serde::{Deserialize, Deserializer, Serialize, Serializer};
1000
1001            // Buncha hullaballoo because prost types aren't serde compat.
1002            // See https://github.com/tokio-rs/prost/issues/75 which hilariously Chad opened ages ago
1003
1004            #[derive(Serialize, Deserialize)]
1005            #[serde(remote = "Timestamp")]
1006            struct TimestampDef {
1007                seconds: i64,
1008                nanos: i32,
1009            }
1010            pub(crate) mod opt_timestamp {
1011                use super::*;
1012
1013                pub(crate) fn serialize<S>(
1014                    value: &Option<Timestamp>,
1015                    serializer: S,
1016                ) -> Result<S::Ok, S::Error>
1017                where
1018                    S: Serializer,
1019                {
1020                    #[derive(Serialize)]
1021                    struct Helper<'a>(#[serde(with = "TimestampDef")] &'a Timestamp);
1022
1023                    value.as_ref().map(Helper).serialize(serializer)
1024                }
1025
1026                pub(crate) fn deserialize<'de, D>(
1027                    deserializer: D,
1028                ) -> Result<Option<Timestamp>, D::Error>
1029                where
1030                    D: Deserializer<'de>,
1031                {
1032                    #[derive(Deserialize)]
1033                    struct Helper(#[serde(with = "TimestampDef")] Timestamp);
1034
1035                    let helper = Option::deserialize(deserializer)?;
1036                    Ok(helper.map(|Helper(external)| external))
1037                }
1038            }
1039
1040            // Luckily Duration is also stored the exact same way
1041            #[derive(Serialize, Deserialize)]
1042            #[serde(remote = "Duration")]
1043            struct DurationDef {
1044                seconds: i64,
1045                nanos: i32,
1046            }
1047            pub(crate) mod opt_duration {
1048                use super::*;
1049
1050                pub(crate) fn serialize<S>(
1051                    value: &Option<Duration>,
1052                    serializer: S,
1053                ) -> Result<S::Ok, S::Error>
1054                where
1055                    S: Serializer,
1056                {
1057                    #[derive(Serialize)]
1058                    struct Helper<'a>(#[serde(with = "DurationDef")] &'a Duration);
1059
1060                    value.as_ref().map(Helper).serialize(serializer)
1061                }
1062
1063                pub(crate) fn deserialize<'de, D>(
1064                    deserializer: D,
1065                ) -> Result<Option<Duration>, D::Error>
1066                where
1067                    D: Deserializer<'de>,
1068                {
1069                    #[derive(Deserialize)]
1070                    struct Helper(#[serde(with = "DurationDef")] Duration);
1071
1072                    let helper = Option::deserialize(deserializer)?;
1073                    Ok(helper.map(|Helper(external)| external))
1074                }
1075            }
1076        }
1077    }
1078    pub mod workflow_activation {
1079        tonic::include_proto!("coresdk.workflow_activation");
1080        pub use self::sdk_helpers::*;
1081        mod sdk_helpers {
1082            use super::*;
1083            use crate::protos::{
1084                coresdk::{
1085                    FromPayloadsExt,
1086                    activity_result::{ActivityResolution, activity_resolution},
1087                    common::NamespacedWorkflowExecution,
1088                    fix_retry_policy,
1089                    workflow_activation::remove_from_cache::EvictionReason,
1090                },
1091                temporal::api::{
1092                    enums::v1::WorkflowTaskFailedCause,
1093                    history::v1::{
1094                        WorkflowExecutionCancelRequestedEventAttributes,
1095                        WorkflowExecutionSignaledEventAttributes,
1096                        WorkflowExecutionStartedEventAttributes,
1097                    },
1098                    query::v1::WorkflowQuery,
1099                },
1100            };
1101            use prost_types::Timestamp;
1102            use std::fmt::{Display, Formatter};
1103
1104            pub fn create_evict_activation(
1105                run_id: String,
1106                message: String,
1107                reason: EvictionReason,
1108            ) -> WorkflowActivation {
1109                WorkflowActivation {
1110                    timestamp: None,
1111                    run_id,
1112                    is_replaying: false,
1113                    history_length: 0,
1114                    jobs: vec![WorkflowActivationJob::from(
1115                        workflow_activation_job::Variant::RemoveFromCache(RemoveFromCache {
1116                            message,
1117                            reason: reason as i32,
1118                        }),
1119                    )],
1120                    available_internal_flags: vec![],
1121                    history_size_bytes: 0,
1122                    continue_as_new_suggested: false,
1123                    deployment_version_for_current_task: None,
1124                    last_sdk_version: String::new(),
1125                    suggest_continue_as_new_reasons: vec![],
1126                    target_worker_deployment_version_changed: false,
1127                }
1128            }
1129
1130            pub fn query_to_job(id: String, q: WorkflowQuery) -> QueryWorkflow {
1131                QueryWorkflow {
1132                    query_id: id,
1133                    query_type: q.query_type,
1134                    arguments: Vec::from_payloads(q.query_args),
1135                    headers: q.header.map(|h| h.into()).unwrap_or_default(),
1136                }
1137            }
1138
1139            impl WorkflowActivation {
1140                /// Returns true if the only job in the activation is eviction
1141                pub fn is_only_eviction(&self) -> bool {
1142                    matches!(
1143                        self.jobs.as_slice(),
1144                        [WorkflowActivationJob {
1145                            variant: Some(workflow_activation_job::Variant::RemoveFromCache(_))
1146                        }]
1147                    )
1148                }
1149
1150                /// Returns eviction reason if this activation is an eviction
1151                pub fn eviction_reason(&self) -> Option<EvictionReason> {
1152                    self.jobs.iter().find_map(|j| {
1153                        if let Some(workflow_activation_job::Variant::RemoveFromCache(ref rj)) =
1154                            j.variant
1155                        {
1156                            EvictionReason::try_from(rj.reason).ok()
1157                        } else {
1158                            None
1159                        }
1160                    })
1161                }
1162            }
1163
1164            impl workflow_activation_job::Variant {
1165                pub fn is_local_activity_resolution(&self) -> bool {
1166                    matches!(self, workflow_activation_job::Variant::ResolveActivity(ra) if ra.is_local)
1167                }
1168            }
1169
1170            impl Display for EvictionReason {
1171                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1172                    write!(f, "{self:?}")
1173                }
1174            }
1175
1176            impl From<EvictionReason> for WorkflowTaskFailedCause {
1177                fn from(value: EvictionReason) -> Self {
1178                    match value {
1179                        EvictionReason::Nondeterminism => {
1180                            WorkflowTaskFailedCause::NonDeterministicError
1181                        }
1182                        _ => WorkflowTaskFailedCause::Unspecified,
1183                    }
1184                }
1185            }
1186
1187            impl Display for WorkflowActivation {
1188                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1189                    write!(f, "WorkflowActivation(")?;
1190                    write!(f, "run_id: {}, ", self.run_id)?;
1191                    write!(f, "is_replaying: {}, ", self.is_replaying)?;
1192                    write!(
1193                        f,
1194                        "jobs: {})",
1195                        self.jobs
1196                            .iter()
1197                            .map(ToString::to_string)
1198                            .collect::<Vec<_>>()
1199                            .as_slice()
1200                            .join(", ")
1201                    )
1202                }
1203            }
1204
1205            impl Display for WorkflowActivationJob {
1206                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1207                    match &self.variant {
1208                        None => write!(f, "empty"),
1209                        Some(v) => write!(f, "{v}"),
1210                    }
1211                }
1212            }
1213
1214            impl Display for workflow_activation_job::Variant {
1215                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1216                    match self {
1217                        workflow_activation_job::Variant::InitializeWorkflow(_) => {
1218                            write!(f, "InitializeWorkflow")
1219                        }
1220                        workflow_activation_job::Variant::FireTimer(t) => {
1221                            write!(f, "FireTimer({})", t.seq)
1222                        }
1223                        workflow_activation_job::Variant::UpdateRandomSeed(_) => {
1224                            write!(f, "UpdateRandomSeed")
1225                        }
1226                        workflow_activation_job::Variant::QueryWorkflow(_) => {
1227                            write!(f, "QueryWorkflow")
1228                        }
1229                        workflow_activation_job::Variant::CancelWorkflow(_) => {
1230                            write!(f, "CancelWorkflow")
1231                        }
1232                        workflow_activation_job::Variant::SignalWorkflow(_) => {
1233                            write!(f, "SignalWorkflow")
1234                        }
1235                        workflow_activation_job::Variant::ResolveActivity(r) => {
1236                            write!(
1237                                f,
1238                                "ResolveActivity({}, {})",
1239                                r.seq,
1240                                r.result
1241                                    .as_ref()
1242                                    .unwrap_or(&ActivityResolution { status: None })
1243                            )
1244                        }
1245                        workflow_activation_job::Variant::NotifyHasPatch(_) => {
1246                            write!(f, "NotifyHasPatch")
1247                        }
1248                        workflow_activation_job::Variant::ResolveChildWorkflowExecutionStart(_) => {
1249                            write!(f, "ResolveChildWorkflowExecutionStart")
1250                        }
1251                        workflow_activation_job::Variant::ResolveChildWorkflowExecution(_) => {
1252                            write!(f, "ResolveChildWorkflowExecution")
1253                        }
1254                        workflow_activation_job::Variant::ResolveSignalExternalWorkflow(_) => {
1255                            write!(f, "ResolveSignalExternalWorkflow")
1256                        }
1257                        workflow_activation_job::Variant::RemoveFromCache(_) => {
1258                            write!(f, "RemoveFromCache")
1259                        }
1260                        workflow_activation_job::Variant::ResolveRequestCancelExternalWorkflow(
1261                            _,
1262                        ) => {
1263                            write!(f, "ResolveRequestCancelExternalWorkflow")
1264                        }
1265                        workflow_activation_job::Variant::DoUpdate(u) => {
1266                            write!(f, "DoUpdate({})", u.id)
1267                        }
1268                        workflow_activation_job::Variant::ResolveNexusOperationStart(_) => {
1269                            write!(f, "ResolveNexusOperationStart")
1270                        }
1271                        workflow_activation_job::Variant::ResolveNexusOperation(_) => {
1272                            write!(f, "ResolveNexusOperation")
1273                        }
1274                    }
1275                }
1276            }
1277
1278            impl Display for ActivityResolution {
1279                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1280                    match self.status {
1281                        None => {
1282                            write!(f, "None")
1283                        }
1284                        Some(activity_resolution::Status::Failed(_)) => {
1285                            write!(f, "Failed")
1286                        }
1287                        Some(activity_resolution::Status::Completed(_)) => {
1288                            write!(f, "Completed")
1289                        }
1290                        Some(activity_resolution::Status::Cancelled(_)) => {
1291                            write!(f, "Cancelled")
1292                        }
1293                        Some(activity_resolution::Status::Backoff(_)) => {
1294                            write!(f, "Backoff")
1295                        }
1296                    }
1297                }
1298            }
1299
1300            impl Display for QueryWorkflow {
1301                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1302                    write!(
1303                        f,
1304                        "QueryWorkflow(id: {}, type: {})",
1305                        self.query_id, self.query_type
1306                    )
1307                }
1308            }
1309
1310            impl From<(WorkflowExecutionSignaledEventAttributes, i64)> for SignalWorkflow {
1311                fn from(
1312                    (a, originating_event_id): (WorkflowExecutionSignaledEventAttributes, i64),
1313                ) -> Self {
1314                    Self {
1315                        signal_name: a.signal_name,
1316                        input: Vec::from_payloads(a.input),
1317                        identity: a.identity,
1318                        headers: a.header.map(Into::into).unwrap_or_default(),
1319                        originating_event_id,
1320                    }
1321                }
1322            }
1323
1324            impl From<WorkflowExecutionCancelRequestedEventAttributes> for CancelWorkflow {
1325                fn from(a: WorkflowExecutionCancelRequestedEventAttributes) -> Self {
1326                    Self { reason: a.cause }
1327                }
1328            }
1329
1330            /// Create a [InitializeWorkflow] job from corresponding event attributes
1331            pub fn start_workflow_from_attribs(
1332                attrs: WorkflowExecutionStartedEventAttributes,
1333                workflow_id: String,
1334                randomness_seed: u64,
1335                start_time: Timestamp,
1336                originating_event_id: i64,
1337            ) -> InitializeWorkflow {
1338                InitializeWorkflow {
1339                    workflow_type: attrs.workflow_type.map(|wt| wt.name).unwrap_or_default(),
1340                    workflow_id,
1341                    arguments: Vec::from_payloads(attrs.input),
1342                    randomness_seed,
1343                    headers: attrs.header.unwrap_or_default().fields,
1344                    identity: attrs.identity,
1345                    parent_workflow_info: attrs.parent_workflow_execution.map(|pe| {
1346                        NamespacedWorkflowExecution {
1347                            namespace: attrs.parent_workflow_namespace,
1348                            run_id: pe.run_id,
1349                            workflow_id: pe.workflow_id,
1350                        }
1351                    }),
1352                    workflow_execution_timeout: attrs.workflow_execution_timeout,
1353                    workflow_run_timeout: attrs.workflow_run_timeout,
1354                    workflow_task_timeout: attrs.workflow_task_timeout,
1355                    continued_from_execution_run_id: attrs.continued_execution_run_id,
1356                    continued_initiator: attrs.initiator,
1357                    continued_failure: attrs.continued_failure,
1358                    last_completion_result: attrs.last_completion_result,
1359                    first_execution_run_id: attrs.first_execution_run_id,
1360                    retry_policy: attrs.retry_policy.map(fix_retry_policy),
1361                    attempt: attrs.attempt,
1362                    cron_schedule: attrs.cron_schedule,
1363                    workflow_execution_expiration_time: attrs.workflow_execution_expiration_time,
1364                    cron_schedule_to_schedule_interval: attrs.first_workflow_task_backoff,
1365                    memo: attrs.memo,
1366                    search_attributes: attrs.search_attributes,
1367                    start_time: Some(start_time),
1368                    root_workflow: attrs.root_workflow_execution,
1369                    priority: attrs.priority,
1370                    originating_event_id,
1371                    original_execution_run_id: attrs.original_execution_run_id,
1372                }
1373            }
1374        }
1375    }
1376    pub mod workflow_completion {
1377        tonic::include_proto!("coresdk.workflow_completion");
1378        mod sdk_helpers {
1379            use super::*;
1380            use crate::protos::temporal::api::{enums::v1::WorkflowTaskFailedCause, failure};
1381
1382            impl workflow_activation_completion::Status {
1383                pub const fn is_success(&self) -> bool {
1384                    match &self {
1385                        Self::Successful(_) => true,
1386                        Self::Failed(_) => false,
1387                    }
1388                }
1389            }
1390
1391            impl From<failure::v1::Failure> for Failure {
1392                fn from(f: failure::v1::Failure) -> Self {
1393                    Failure {
1394                        failure: Some(f),
1395                        force_cause: WorkflowTaskFailedCause::Unspecified as i32,
1396                    }
1397                }
1398            }
1399        }
1400    }
1401    pub mod child_workflow {
1402        tonic::include_proto!("coresdk.child_workflow");
1403    }
1404    pub mod nexus {
1405        tonic::include_proto!("coresdk.nexus");
1406        pub use self::sdk_helpers::*;
1407        mod sdk_helpers {
1408            use super::*;
1409            use crate::protos::temporal::api::workflowservice::v1::PollNexusTaskQueueResponse;
1410            use std::fmt::{Display, Formatter};
1411
1412            impl NexusTask {
1413                /// Unwrap the inner server-delivered nexus task if that's what this is, else panic.
1414                pub fn unwrap_task(self) -> PollNexusTaskQueueResponse {
1415                    if let Some(nexus_task::Variant::Task(t)) = self.variant {
1416                        return t;
1417                    }
1418                    panic!("Nexus task did not contain a server task");
1419                }
1420
1421                /// Get the task token
1422                pub fn task_token(&self) -> &[u8] {
1423                    match &self.variant {
1424                        Some(nexus_task::Variant::Task(t)) => t.task_token.as_slice(),
1425                        Some(nexus_task::Variant::CancelTask(c)) => c.task_token.as_slice(),
1426                        None => panic!("Nexus task did not contain a task token"),
1427                    }
1428                }
1429            }
1430
1431            impl Display for nexus_task_completion::Status {
1432                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1433                    write!(f, "NexusTaskCompletion(")?;
1434                    match self {
1435                        nexus_task_completion::Status::Completed(c) => {
1436                            write!(f, "{c}")
1437                        }
1438                        nexus_task_completion::Status::AckCancel(_) => {
1439                            write!(f, "AckCancel")
1440                        }
1441                        #[allow(deprecated)]
1442                        nexus_task_completion::Status::Error(error) => {
1443                            write!(f, "Error({error:?})")
1444                        }
1445                        nexus_task_completion::Status::Failure(failure) => {
1446                            write!(f, "{failure}")
1447                        }
1448                    }?;
1449                    write!(f, ")")
1450                }
1451            }
1452
1453            #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1454            pub enum NexusOperationErrorState {
1455                Failed,
1456                Canceled,
1457            }
1458
1459            impl Display for NexusOperationErrorState {
1460                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1461                    match self {
1462                        Self::Failed => write!(f, "failed"),
1463                        Self::Canceled => write!(f, "canceled"),
1464                    }
1465                }
1466            }
1467        }
1468    }
1469    pub mod workflow_commands {
1470        tonic::include_proto!("coresdk.workflow_commands");
1471        mod sdk_helpers {
1472            use super::*;
1473            use crate::protos::temporal::api::{common::v1::Payloads, enums::v1::QueryResultType};
1474            use std::fmt::{Display, Formatter};
1475
1476            impl Display for WorkflowCommand {
1477                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1478                    match &self.variant {
1479                        None => write!(f, "Empty"),
1480                        Some(v) => write!(f, "{v}"),
1481                    }
1482                }
1483            }
1484
1485            impl Display for StartTimer {
1486                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1487                    write!(f, "StartTimer({})", self.seq)
1488                }
1489            }
1490
1491            impl Display for ScheduleActivity {
1492                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1493                    write!(f, "ScheduleActivity({}, {})", self.seq, self.activity_type)
1494                }
1495            }
1496
1497            impl Display for ScheduleLocalActivity {
1498                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1499                    write!(
1500                        f,
1501                        "ScheduleLocalActivity({}, {})",
1502                        self.seq, self.activity_type
1503                    )
1504                }
1505            }
1506
1507            impl Display for QueryResult {
1508                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1509                    write!(f, "RespondToQuery({})", self.query_id)
1510                }
1511            }
1512
1513            impl Display for RequestCancelActivity {
1514                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1515                    write!(f, "RequestCancelActivity({})", self.seq)
1516                }
1517            }
1518
1519            impl Display for RequestCancelLocalActivity {
1520                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1521                    write!(f, "RequestCancelLocalActivity({})", self.seq)
1522                }
1523            }
1524
1525            impl Display for CancelTimer {
1526                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1527                    write!(f, "CancelTimer({})", self.seq)
1528                }
1529            }
1530
1531            impl Display for CompleteWorkflowExecution {
1532                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1533                    write!(f, "CompleteWorkflowExecution")
1534                }
1535            }
1536
1537            impl Display for FailWorkflowExecution {
1538                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1539                    write!(f, "FailWorkflowExecution")
1540                }
1541            }
1542
1543            impl Display for ContinueAsNewWorkflowExecution {
1544                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1545                    write!(f, "ContinueAsNewWorkflowExecution")
1546                }
1547            }
1548
1549            impl Display for CancelWorkflowExecution {
1550                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1551                    write!(f, "CancelWorkflowExecution")
1552                }
1553            }
1554
1555            impl Display for SetPatchMarker {
1556                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1557                    write!(f, "SetPatchMarker({})", self.patch_id)
1558                }
1559            }
1560
1561            impl Display for StartChildWorkflowExecution {
1562                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1563                    write!(
1564                        f,
1565                        "StartChildWorkflowExecution({}, {})",
1566                        self.seq, self.workflow_type
1567                    )
1568                }
1569            }
1570
1571            impl Display for RequestCancelExternalWorkflowExecution {
1572                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1573                    write!(f, "RequestCancelExternalWorkflowExecution({})", self.seq)
1574                }
1575            }
1576
1577            impl Display for UpsertWorkflowSearchAttributes {
1578                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1579                    let keys: Vec<_> = self
1580                        .search_attributes
1581                        .as_ref()
1582                        .map(|sa| sa.indexed_fields.keys().collect())
1583                        .unwrap_or_default();
1584                    write!(f, "UpsertWorkflowSearchAttributes({:?})", keys)
1585                }
1586            }
1587
1588            impl Display for SignalExternalWorkflowExecution {
1589                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1590                    write!(f, "SignalExternalWorkflowExecution({})", self.seq)
1591                }
1592            }
1593
1594            impl Display for CancelSignalWorkflow {
1595                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1596                    write!(f, "CancelSignalWorkflow({})", self.seq)
1597                }
1598            }
1599
1600            impl Display for CancelChildWorkflowExecution {
1601                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1602                    write!(
1603                        f,
1604                        "CancelChildWorkflowExecution({})",
1605                        self.child_workflow_seq
1606                    )
1607                }
1608            }
1609
1610            impl Display for ModifyWorkflowProperties {
1611                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1612                    write!(
1613                        f,
1614                        "ModifyWorkflowProperties(upserted memo keys: {:?})",
1615                        self.upserted_memo.as_ref().map(|m| m.fields.keys())
1616                    )
1617                }
1618            }
1619
1620            impl Display for UpdateResponse {
1621                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1622                    write!(
1623                        f,
1624                        "UpdateResponse(protocol_instance_id: {}, response: {:?})",
1625                        self.protocol_instance_id, self.response
1626                    )
1627                }
1628            }
1629
1630            impl Display for ScheduleNexusOperation {
1631                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1632                    write!(f, "ScheduleNexusOperation({})", self.seq)
1633                }
1634            }
1635
1636            impl Display for RequestCancelNexusOperation {
1637                fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1638                    write!(f, "RequestCancelNexusOperation({})", self.seq)
1639                }
1640            }
1641
1642            impl QueryResult {
1643                /// Helper to construct the Temporal API query result types.
1644                pub fn into_components(
1645                    self,
1646                ) -> (String, QueryResultType, Option<Payloads>, String) {
1647                    match self {
1648                        QueryResult {
1649                            variant: Some(query_result::Variant::Succeeded(qs)),
1650                            query_id,
1651                        } => (
1652                            query_id,
1653                            QueryResultType::Answered,
1654                            qs.response.map(Into::into),
1655                            "".to_string(),
1656                        ),
1657                        QueryResult {
1658                            variant: Some(query_result::Variant::Failed(err)),
1659                            query_id,
1660                        } => (query_id, QueryResultType::Failed, None, err.message),
1661                        QueryResult {
1662                            variant: None,
1663                            query_id,
1664                        } => (
1665                            query_id,
1666                            QueryResultType::Failed,
1667                            None,
1668                            "Query response was empty".to_string(),
1669                        ),
1670                    }
1671                }
1672            }
1673        }
1674    }
1675}
1676
1677// No need to lint these
1678#[allow(
1679    clippy::all,
1680    missing_docs,
1681    rustdoc::broken_intra_doc_links,
1682    rustdoc::bare_urls
1683)]
1684// This is disgusting, but unclear to me how to avoid it. TODO: Discuss w/ prost maintainer
1685pub mod temporal {
1686    pub mod api {
1687        pub mod activity {
1688            pub mod v1 {
1689                tonic::include_proto!("temporal.api.activity.v1");
1690            }
1691        }
1692        pub mod batch {
1693            pub mod v1 {
1694                tonic::include_proto!("temporal.api.batch.v1");
1695            }
1696        }
1697        pub mod callback {
1698            pub mod v1 {
1699                tonic::include_proto!("temporal.api.callback.v1");
1700            }
1701        }
1702        pub mod command {
1703            pub mod v1 {
1704                tonic::include_proto!("temporal.api.command.v1");
1705                pub use self::sdk_helpers::*;
1706                mod sdk_helpers {
1707                    use super::*;
1708                    use crate::protos::{
1709                        coresdk::{IntoPayloadsExt, workflow_commands},
1710                        temporal::api::{
1711                            common::v1::{ActivityType, WorkflowType},
1712                            enums::v1::CommandType,
1713                        },
1714                    };
1715                    use command::Attributes;
1716                    use std::fmt::{Display, Formatter};
1717
1718                    impl From<command::Attributes> for Command {
1719                        fn from(c: command::Attributes) -> Self {
1720                            match c {
1721                                a @ Attributes::StartTimerCommandAttributes(_) => Self {
1722                                    command_type: CommandType::StartTimer as i32,
1723                                    attributes: Some(a),
1724                                    user_metadata: Default::default(),
1725                                    event_group_markers: Default::default(),
1726                                },
1727                                a @ Attributes::CancelTimerCommandAttributes(_) => Self {
1728                                    command_type: CommandType::CancelTimer as i32,
1729                                    attributes: Some(a),
1730                                    user_metadata: Default::default(),
1731                                    event_group_markers: Default::default(),
1732                                },
1733                                a @ Attributes::CompleteWorkflowExecutionCommandAttributes(_) => {
1734                                    Self {
1735                                        command_type: CommandType::CompleteWorkflowExecution as i32,
1736                                        attributes: Some(a),
1737                                        user_metadata: Default::default(),
1738                                        event_group_markers: Default::default(),
1739                                    }
1740                                }
1741                                a @ Attributes::FailWorkflowExecutionCommandAttributes(_) => Self {
1742                                    command_type: CommandType::FailWorkflowExecution as i32,
1743                                    attributes: Some(a),
1744                                    user_metadata: Default::default(),
1745                                    event_group_markers: Default::default(),
1746                                },
1747                                a @ Attributes::ScheduleActivityTaskCommandAttributes(_) => Self {
1748                                    command_type: CommandType::ScheduleActivityTask as i32,
1749                                    attributes: Some(a),
1750                                    user_metadata: Default::default(),
1751                                    event_group_markers: Default::default(),
1752                                },
1753                                a @ Attributes::RequestCancelActivityTaskCommandAttributes(_) => {
1754                                    Self {
1755                                        command_type: CommandType::RequestCancelActivityTask as i32,
1756                                        attributes: Some(a),
1757                                        user_metadata: Default::default(),
1758                                        event_group_markers: Default::default(),
1759                                    }
1760                                }
1761                                a
1762                                @ Attributes::ContinueAsNewWorkflowExecutionCommandAttributes(
1763                                    _,
1764                                ) => Self {
1765                                    command_type: CommandType::ContinueAsNewWorkflowExecution
1766                                        as i32,
1767                                    attributes: Some(a),
1768                                    user_metadata: Default::default(),
1769                                    event_group_markers: Default::default(),
1770                                },
1771                                a @ Attributes::CancelWorkflowExecutionCommandAttributes(_) => {
1772                                    Self {
1773                                        command_type: CommandType::CancelWorkflowExecution as i32,
1774                                        attributes: Some(a),
1775                                        user_metadata: Default::default(),
1776                                        event_group_markers: Default::default(),
1777                                    }
1778                                }
1779                                a @ Attributes::RecordMarkerCommandAttributes(_) => Self {
1780                                    command_type: CommandType::RecordMarker as i32,
1781                                    attributes: Some(a),
1782                                    user_metadata: Default::default(),
1783                                    event_group_markers: Default::default(),
1784                                },
1785                                a @ Attributes::ProtocolMessageCommandAttributes(_) => Self {
1786                                    command_type: CommandType::ProtocolMessage as i32,
1787                                    attributes: Some(a),
1788                                    user_metadata: Default::default(),
1789                                    event_group_markers: Default::default(),
1790                                },
1791                                a @ Attributes::RequestCancelNexusOperationCommandAttributes(_) => {
1792                                    Self {
1793                                        command_type: CommandType::RequestCancelNexusOperation
1794                                            as i32,
1795                                        attributes: Some(a),
1796                                        user_metadata: Default::default(),
1797                                        event_group_markers: Default::default(),
1798                                    }
1799                                }
1800                                _ => unimplemented!(),
1801                            }
1802                        }
1803                    }
1804
1805                    impl Display for Command {
1806                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1807                            let ct = CommandType::try_from(self.command_type)
1808                                .unwrap_or(CommandType::Unspecified);
1809                            write!(f, "{:?}", ct)
1810                        }
1811                    }
1812
1813                    pub trait CommandAttributesExt {
1814                        fn as_type(&self) -> CommandType;
1815                    }
1816
1817                    impl CommandAttributesExt for command::Attributes {
1818                        fn as_type(&self) -> CommandType {
1819                            match self {
1820                            Attributes::ScheduleActivityTaskCommandAttributes(_) => {
1821                                CommandType::ScheduleActivityTask
1822                            }
1823                            Attributes::StartTimerCommandAttributes(_) => CommandType::StartTimer,
1824                            Attributes::CompleteWorkflowExecutionCommandAttributes(_) => {
1825                                CommandType::CompleteWorkflowExecution
1826                            }
1827                            Attributes::FailWorkflowExecutionCommandAttributes(_) => {
1828                                CommandType::FailWorkflowExecution
1829                            }
1830                            Attributes::RequestCancelActivityTaskCommandAttributes(_) => {
1831                                CommandType::RequestCancelActivityTask
1832                            }
1833                            Attributes::CancelTimerCommandAttributes(_) => CommandType::CancelTimer,
1834                            Attributes::CancelWorkflowExecutionCommandAttributes(_) => {
1835                                CommandType::CancelWorkflowExecution
1836                            }
1837                            Attributes::RequestCancelExternalWorkflowExecutionCommandAttributes(
1838                                _,
1839                            ) => CommandType::RequestCancelExternalWorkflowExecution,
1840                            Attributes::RecordMarkerCommandAttributes(_) => {
1841                                CommandType::RecordMarker
1842                            }
1843                            Attributes::ContinueAsNewWorkflowExecutionCommandAttributes(_) => {
1844                                CommandType::ContinueAsNewWorkflowExecution
1845                            }
1846                            Attributes::StartChildWorkflowExecutionCommandAttributes(_) => {
1847                                CommandType::StartChildWorkflowExecution
1848                            }
1849                            Attributes::SignalExternalWorkflowExecutionCommandAttributes(_) => {
1850                                CommandType::SignalExternalWorkflowExecution
1851                            }
1852                            Attributes::UpsertWorkflowSearchAttributesCommandAttributes(_) => {
1853                                CommandType::UpsertWorkflowSearchAttributes
1854                            }
1855                            Attributes::ProtocolMessageCommandAttributes(_) => {
1856                                CommandType::ProtocolMessage
1857                            }
1858                            Attributes::ModifyWorkflowPropertiesCommandAttributes(_) => {
1859                                CommandType::ModifyWorkflowProperties
1860                            }
1861                            Attributes::ScheduleNexusOperationCommandAttributes(_) => {
1862                                CommandType::ScheduleNexusOperation
1863                            }
1864                            Attributes::RequestCancelNexusOperationCommandAttributes(_) => {
1865                                CommandType::RequestCancelNexusOperation
1866                            }
1867                        }
1868                        }
1869                    }
1870
1871                    impl Display for command::Attributes {
1872                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1873                            write!(f, "{:?}", self.as_type())
1874                        }
1875                    }
1876
1877                    impl From<workflow_commands::StartTimer> for command::Attributes {
1878                        fn from(s: workflow_commands::StartTimer) -> Self {
1879                            Self::StartTimerCommandAttributes(StartTimerCommandAttributes {
1880                                timer_id: s.seq.to_string(),
1881                                start_to_fire_timeout: s.start_to_fire_timeout,
1882                            })
1883                        }
1884                    }
1885
1886                    impl From<workflow_commands::UpsertWorkflowSearchAttributes> for command::Attributes {
1887                        fn from(s: workflow_commands::UpsertWorkflowSearchAttributes) -> Self {
1888                            Self::UpsertWorkflowSearchAttributesCommandAttributes(
1889                                UpsertWorkflowSearchAttributesCommandAttributes {
1890                                    search_attributes: s.search_attributes,
1891                                },
1892                            )
1893                        }
1894                    }
1895
1896                    impl From<workflow_commands::ModifyWorkflowProperties> for command::Attributes {
1897                        fn from(s: workflow_commands::ModifyWorkflowProperties) -> Self {
1898                            Self::ModifyWorkflowPropertiesCommandAttributes(
1899                                ModifyWorkflowPropertiesCommandAttributes {
1900                                    upserted_memo: s.upserted_memo.map(Into::into),
1901                                },
1902                            )
1903                        }
1904                    }
1905
1906                    impl From<workflow_commands::CancelTimer> for command::Attributes {
1907                        fn from(s: workflow_commands::CancelTimer) -> Self {
1908                            Self::CancelTimerCommandAttributes(CancelTimerCommandAttributes {
1909                                timer_id: s.seq.to_string(),
1910                            })
1911                        }
1912                    }
1913
1914                    pub fn schedule_activity_cmd_to_api(
1915                        s: workflow_commands::ScheduleActivity,
1916                        use_workflow_build_id: bool,
1917                    ) -> command::Attributes {
1918                        command::Attributes::ScheduleActivityTaskCommandAttributes(
1919                            ScheduleActivityTaskCommandAttributes {
1920                                activity_id: s.activity_id,
1921                                activity_type: Some(ActivityType {
1922                                    name: s.activity_type,
1923                                }),
1924                                task_queue: Some(s.task_queue.into()),
1925                                header: Some(s.headers.into()),
1926                                input: s.arguments.into_payloads(),
1927                                schedule_to_close_timeout: s.schedule_to_close_timeout,
1928                                schedule_to_start_timeout: s.schedule_to_start_timeout,
1929                                start_to_close_timeout: s.start_to_close_timeout,
1930                                heartbeat_timeout: s.heartbeat_timeout,
1931                                retry_policy: s.retry_policy.map(Into::into),
1932                                request_eager_execution: !s.do_not_eagerly_execute,
1933                                use_workflow_build_id,
1934                                priority: s.priority,
1935                            },
1936                        )
1937                    }
1938
1939                    #[allow(deprecated)]
1940                    pub fn start_child_workflow_cmd_to_api(
1941                        s: workflow_commands::StartChildWorkflowExecution,
1942                        inherit_build_id: bool,
1943                    ) -> command::Attributes {
1944                        command::Attributes::StartChildWorkflowExecutionCommandAttributes(
1945                            StartChildWorkflowExecutionCommandAttributes {
1946                                workflow_id: s.workflow_id,
1947                                workflow_type: Some(WorkflowType {
1948                                    name: s.workflow_type,
1949                                }),
1950                                control: "".into(),
1951                                namespace: s.namespace,
1952                                task_queue: Some(s.task_queue.into()),
1953                                header: Some(s.headers.into()),
1954                                memo: Some(s.memo.into()),
1955                                search_attributes: s.search_attributes,
1956                                input: s.input.into_payloads(),
1957                                workflow_id_reuse_policy: s.workflow_id_reuse_policy,
1958                                workflow_execution_timeout: s.workflow_execution_timeout,
1959                                workflow_run_timeout: s.workflow_run_timeout,
1960                                workflow_task_timeout: s.workflow_task_timeout,
1961                                retry_policy: s.retry_policy.map(Into::into),
1962                                cron_schedule: s.cron_schedule.clone(),
1963                                parent_close_policy: s.parent_close_policy,
1964                                inherit_build_id,
1965                                priority: s.priority,
1966                                versioning_override: None,
1967                            },
1968                        )
1969                    }
1970
1971                    impl From<workflow_commands::CompleteWorkflowExecution> for command::Attributes {
1972                        fn from(c: workflow_commands::CompleteWorkflowExecution) -> Self {
1973                            Self::CompleteWorkflowExecutionCommandAttributes(
1974                                CompleteWorkflowExecutionCommandAttributes {
1975                                    result: c.result.map(Into::into),
1976                                },
1977                            )
1978                        }
1979                    }
1980
1981                    impl From<workflow_commands::FailWorkflowExecution> for command::Attributes {
1982                        fn from(c: workflow_commands::FailWorkflowExecution) -> Self {
1983                            Self::FailWorkflowExecutionCommandAttributes(
1984                                FailWorkflowExecutionCommandAttributes {
1985                                    failure: c.failure.map(Into::into),
1986                                },
1987                            )
1988                        }
1989                    }
1990
1991                    #[allow(deprecated)]
1992                    pub fn continue_as_new_cmd_to_api(
1993                        c: workflow_commands::ContinueAsNewWorkflowExecution,
1994                        inherit_build_id: bool,
1995                    ) -> command::Attributes {
1996                        command::Attributes::ContinueAsNewWorkflowExecutionCommandAttributes(
1997                            ContinueAsNewWorkflowExecutionCommandAttributes {
1998                                workflow_type: Some(c.workflow_type.into()),
1999                                task_queue: Some(c.task_queue.into()),
2000                                input: c.arguments.into_payloads(),
2001                                workflow_run_timeout: c.workflow_run_timeout,
2002                                workflow_task_timeout: c.workflow_task_timeout,
2003                                memo: if c.memo.is_empty() {
2004                                    None
2005                                } else {
2006                                    Some(c.memo.into())
2007                                },
2008                                header: if c.headers.is_empty() {
2009                                    None
2010                                } else {
2011                                    Some(c.headers.into())
2012                                },
2013                                retry_policy: c.retry_policy,
2014                                search_attributes: c.search_attributes,
2015                                backoff_start_interval: c.backoff_start_interval,
2016                                inherit_build_id,
2017                                initial_versioning_behavior: c.initial_versioning_behavior,
2018                                ..Default::default()
2019                            },
2020                        )
2021                    }
2022
2023                    impl From<workflow_commands::CancelWorkflowExecution> for command::Attributes {
2024                        fn from(_c: workflow_commands::CancelWorkflowExecution) -> Self {
2025                            Self::CancelWorkflowExecutionCommandAttributes(
2026                                CancelWorkflowExecutionCommandAttributes { details: None },
2027                            )
2028                        }
2029                    }
2030
2031                    impl From<workflow_commands::ScheduleNexusOperation> for command::Attributes {
2032                        fn from(c: workflow_commands::ScheduleNexusOperation) -> Self {
2033                            Self::ScheduleNexusOperationCommandAttributes(
2034                                ScheduleNexusOperationCommandAttributes {
2035                                    endpoint: c.endpoint,
2036                                    service: c.service,
2037                                    operation: c.operation,
2038                                    input: c.input,
2039                                    schedule_to_close_timeout: c.schedule_to_close_timeout,
2040                                    schedule_to_start_timeout: c.schedule_to_start_timeout,
2041                                    start_to_close_timeout: c.start_to_close_timeout,
2042                                    nexus_header: c.nexus_header,
2043                                },
2044                            )
2045                        }
2046                    }
2047                }
2048            }
2049        }
2050        #[allow(rustdoc::invalid_html_tags)]
2051        pub mod cloud {
2052            pub mod account {
2053                pub mod v1 {
2054                    tonic::include_proto!("temporal.api.cloud.account.v1");
2055                }
2056            }
2057            pub mod auditlog {
2058                pub mod v1 {
2059                    tonic::include_proto!("temporal.api.cloud.auditlog.v1");
2060                }
2061            }
2062            pub mod billing {
2063                pub mod v1 {
2064                    tonic::include_proto!("temporal.api.cloud.billing.v1");
2065                }
2066            }
2067            pub mod cloudservice {
2068                pub mod v1 {
2069                    tonic::include_proto!("temporal.api.cloud.cloudservice.v1");
2070                }
2071            }
2072            pub mod connectivityrule {
2073                pub mod v1 {
2074                    tonic::include_proto!("temporal.api.cloud.connectivityrule.v1");
2075                }
2076            }
2077            pub mod identity {
2078                pub mod v1 {
2079                    tonic::include_proto!("temporal.api.cloud.identity.v1");
2080                }
2081            }
2082            pub mod namespace {
2083                pub mod v1 {
2084                    tonic::include_proto!("temporal.api.cloud.namespace.v1");
2085                }
2086            }
2087            pub mod nexus {
2088                pub mod v1 {
2089                    tonic::include_proto!("temporal.api.cloud.nexus.v1");
2090                }
2091            }
2092            pub mod operation {
2093                pub mod v1 {
2094                    tonic::include_proto!("temporal.api.cloud.operation.v1");
2095                }
2096            }
2097            pub mod region {
2098                pub mod v1 {
2099                    tonic::include_proto!("temporal.api.cloud.region.v1");
2100                }
2101            }
2102            pub mod resource {
2103                pub mod v1 {
2104                    tonic::include_proto!("temporal.api.cloud.resource.v1");
2105                }
2106            }
2107            pub mod sink {
2108                pub mod v1 {
2109                    tonic::include_proto!("temporal.api.cloud.sink.v1");
2110                }
2111            }
2112            pub mod usage {
2113                pub mod v1 {
2114                    tonic::include_proto!("temporal.api.cloud.usage.v1");
2115                }
2116            }
2117        }
2118        pub mod common {
2119            pub mod v1 {
2120                include_proto_with_serde!("temporal.api.common.v1");
2121                mod sdk_helpers {
2122                    use super::*;
2123                    use crate::protos::{ENCODING_PAYLOAD_KEY, JSON_ENCODING_VAL};
2124                    use base64::{Engine, prelude::BASE64_STANDARD};
2125                    use std::{
2126                        collections::HashMap,
2127                        fmt::{Display, Formatter},
2128                    };
2129
2130                    impl<T> From<T> for Payload
2131                    where
2132                        T: AsRef<[u8]>,
2133                    {
2134                        fn from(v: T) -> Self {
2135                            // TODO: Set better encodings, whole data converter deal. Setting anything
2136                            //  for now at least makes it show up in the web UI.
2137                            let mut metadata = HashMap::new();
2138                            metadata
2139                                .insert(ENCODING_PAYLOAD_KEY.to_string(), b"binary/plain".to_vec());
2140                            Self {
2141                                metadata,
2142                                data: v.as_ref().to_vec(),
2143                                external_payloads: Default::default(),
2144                            }
2145                        }
2146                    }
2147
2148                    impl Payload {
2149                        // Is its own function b/c asref causes implementation conflicts
2150                        pub fn as_slice(&self) -> &[u8] {
2151                            self.data.as_slice()
2152                        }
2153
2154                        pub fn is_json_payload(&self) -> bool {
2155                            self.metadata
2156                                .get(ENCODING_PAYLOAD_KEY)
2157                                .map(|v| v.as_slice() == JSON_ENCODING_VAL.as_bytes())
2158                                .unwrap_or_default()
2159                        }
2160                    }
2161
2162                    impl std::fmt::Debug for Payload {
2163                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2164                            if std::env::var("TEMPORAL_PRINT_FULL_PAYLOADS").is_err()
2165                                && self.data.len() > 64
2166                            {
2167                                let mut windows = self.data.as_slice().windows(32);
2168                                write!(
2169                                    f,
2170                                    "[{}..{}]",
2171                                    BASE64_STANDARD.encode(windows.next().unwrap_or_default()),
2172                                    BASE64_STANDARD.encode(windows.next_back().unwrap_or_default())
2173                                )
2174                            } else {
2175                                write!(f, "[{}]", BASE64_STANDARD.encode(&self.data))
2176                            }
2177                        }
2178                    }
2179
2180                    impl Display for Payload {
2181                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2182                            write!(f, "{:?}", self)
2183                        }
2184                    }
2185
2186                    impl Display for Header {
2187                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2188                            write!(f, "Header(")?;
2189                            for kv in &self.fields {
2190                                write!(f, "{}: ", kv.0)?;
2191                                write!(f, "{}, ", kv.1)?;
2192                            }
2193                            write!(f, ")")
2194                        }
2195                    }
2196
2197                    impl From<Header> for HashMap<String, Payload> {
2198                        fn from(h: Header) -> Self {
2199                            h.fields.into_iter().map(|(k, v)| (k, v.into())).collect()
2200                        }
2201                    }
2202
2203                    impl From<Memo> for HashMap<String, Payload> {
2204                        fn from(h: Memo) -> Self {
2205                            h.fields.into_iter().map(|(k, v)| (k, v.into())).collect()
2206                        }
2207                    }
2208
2209                    impl From<SearchAttributes> for HashMap<String, Payload> {
2210                        fn from(h: SearchAttributes) -> Self {
2211                            h.indexed_fields
2212                                .into_iter()
2213                                .map(|(k, v)| (k, v.into()))
2214                                .collect()
2215                        }
2216                    }
2217
2218                    impl From<HashMap<String, Payload>> for SearchAttributes {
2219                        fn from(h: HashMap<String, Payload>) -> Self {
2220                            Self {
2221                                indexed_fields: h.into_iter().map(|(k, v)| (k, v.into())).collect(),
2222                            }
2223                        }
2224                    }
2225
2226                    impl From<String> for ActivityType {
2227                        fn from(name: String) -> Self {
2228                            Self { name }
2229                        }
2230                    }
2231
2232                    impl From<&str> for ActivityType {
2233                        fn from(name: &str) -> Self {
2234                            Self {
2235                                name: name.to_string(),
2236                            }
2237                        }
2238                    }
2239
2240                    impl From<ActivityType> for String {
2241                        fn from(at: ActivityType) -> Self {
2242                            at.name
2243                        }
2244                    }
2245
2246                    impl From<&str> for WorkflowType {
2247                        fn from(v: &str) -> Self {
2248                            Self {
2249                                name: v.to_string(),
2250                            }
2251                        }
2252                    }
2253                }
2254            }
2255        }
2256        pub mod compute {
2257            pub mod v1 {
2258                tonic::include_proto!("temporal.api.compute.v1");
2259            }
2260        }
2261        pub mod deployment {
2262            pub mod v1 {
2263                tonic::include_proto!("temporal.api.deployment.v1");
2264            }
2265        }
2266        pub mod enums {
2267            pub mod v1 {
2268                include_proto_with_serde!("temporal.api.enums.v1");
2269            }
2270        }
2271        pub mod errordetails {
2272            pub mod v1 {
2273                tonic::include_proto!("temporal.api.errordetails.v1");
2274            }
2275        }
2276        pub mod failure {
2277            pub mod v1 {
2278                include_proto_with_serde!("temporal.api.failure.v1");
2279            }
2280        }
2281        pub mod filter {
2282            pub mod v1 {
2283                tonic::include_proto!("temporal.api.filter.v1");
2284            }
2285        }
2286        pub mod history {
2287            pub mod v1 {
2288                tonic::include_proto!("temporal.api.history.v1");
2289                pub use self::sdk_helpers::*;
2290                mod sdk_helpers {
2291                    use super::*;
2292                    use crate::protos::temporal::api::{
2293                        enums::v1::EventType, history::v1::history_event::Attributes,
2294                    };
2295                    use anyhow::bail;
2296                    use std::fmt::{Display, Formatter};
2297
2298                    impl History {
2299                        pub fn extract_run_id_from_start(&self) -> Result<&str, anyhow::Error> {
2300                            extract_original_run_id_from_events(&self.events)
2301                        }
2302
2303                        /// Returns the event id of the final event in the history. Will return 0 if
2304                        /// there are no events.
2305                        pub fn last_event_id(&self) -> i64 {
2306                            self.events.last().map(|e| e.event_id).unwrap_or_default()
2307                        }
2308                    }
2309
2310                    pub fn extract_original_run_id_from_events(
2311                        events: &[HistoryEvent],
2312                    ) -> Result<&str, anyhow::Error> {
2313                        if let Some(Attributes::WorkflowExecutionStartedEventAttributes(wes)) =
2314                            events.get(0).and_then(|x| x.attributes.as_ref())
2315                        {
2316                            Ok(&wes.original_execution_run_id)
2317                        } else {
2318                            bail!("First event is not WorkflowExecutionStarted?!?")
2319                        }
2320                    }
2321
2322                    impl HistoryEvent {
2323                        /// Returns true if this is an event created to mirror a command
2324                        pub fn is_command_event(&self) -> bool {
2325                            EventType::try_from(self.event_type).map_or(false, |et| match et {
2326                                EventType::ActivityTaskScheduled
2327                                | EventType::ActivityTaskCancelRequested
2328                                | EventType::MarkerRecorded
2329                                | EventType::RequestCancelExternalWorkflowExecutionInitiated
2330                                | EventType::SignalExternalWorkflowExecutionInitiated
2331                                | EventType::StartChildWorkflowExecutionInitiated
2332                                | EventType::TimerCanceled
2333                                | EventType::TimerStarted
2334                                | EventType::UpsertWorkflowSearchAttributes
2335                                | EventType::WorkflowPropertiesModified
2336                                | EventType::NexusOperationScheduled
2337                                | EventType::NexusOperationCancelRequested
2338                                | EventType::WorkflowExecutionCanceled
2339                                | EventType::WorkflowExecutionCompleted
2340                                | EventType::WorkflowExecutionContinuedAsNew
2341                                | EventType::WorkflowExecutionFailed
2342                                | EventType::WorkflowExecutionUpdateAccepted
2343                                | EventType::WorkflowExecutionUpdateRejected
2344                                | EventType::WorkflowExecutionUpdateCompleted => true,
2345                                _ => false,
2346                            })
2347                        }
2348
2349                        /// Returns the command's initiating event id, if present. This is the id of the
2350                        /// event which "started" the command. Usually, the "scheduled" event for the
2351                        /// command.
2352                        pub fn get_initial_command_event_id(&self) -> Option<i64> {
2353                            self.attributes.as_ref().and_then(|a| {
2354                            // Fun! Not really any way to make this better w/o incompatibly changing
2355                            // protos.
2356                            match a {
2357                                Attributes::ActivityTaskStartedEventAttributes(a) =>
2358                                    Some(a.scheduled_event_id),
2359                                Attributes::ActivityTaskCompletedEventAttributes(a) =>
2360                                    Some(a.scheduled_event_id),
2361                                Attributes::ActivityTaskFailedEventAttributes(a) => Some(a.scheduled_event_id),
2362                                Attributes::ActivityTaskTimedOutEventAttributes(a) => Some(a.scheduled_event_id),
2363                                Attributes::ActivityTaskCancelRequestedEventAttributes(a) => Some(a.scheduled_event_id),
2364                                Attributes::ActivityTaskCanceledEventAttributes(a) => Some(a.scheduled_event_id),
2365                                Attributes::TimerFiredEventAttributes(a) => Some(a.started_event_id),
2366                                Attributes::TimerCanceledEventAttributes(a) => Some(a.started_event_id),
2367                                Attributes::RequestCancelExternalWorkflowExecutionFailedEventAttributes(a) => Some(a.initiated_event_id),
2368                                Attributes::ExternalWorkflowExecutionCancelRequestedEventAttributes(a) => Some(a.initiated_event_id),
2369                                Attributes::StartChildWorkflowExecutionFailedEventAttributes(a) => Some(a.initiated_event_id),
2370                                Attributes::ChildWorkflowExecutionStartedEventAttributes(a) => Some(a.initiated_event_id),
2371                                Attributes::ChildWorkflowExecutionCompletedEventAttributes(a) => Some(a.initiated_event_id),
2372                                Attributes::ChildWorkflowExecutionFailedEventAttributes(a) => Some(a.initiated_event_id),
2373                                Attributes::ChildWorkflowExecutionCanceledEventAttributes(a) => Some(a.initiated_event_id),
2374                                Attributes::ChildWorkflowExecutionTimedOutEventAttributes(a) => Some(a.initiated_event_id),
2375                                Attributes::ChildWorkflowExecutionTerminatedEventAttributes(a) => Some(a.initiated_event_id),
2376                                Attributes::SignalExternalWorkflowExecutionFailedEventAttributes(a) => Some(a.initiated_event_id),
2377                                Attributes::ExternalWorkflowExecutionSignaledEventAttributes(a) => Some(a.initiated_event_id),
2378                                Attributes::WorkflowTaskStartedEventAttributes(a) => Some(a.scheduled_event_id),
2379                                Attributes::WorkflowTaskCompletedEventAttributes(a) => Some(a.scheduled_event_id),
2380                                Attributes::WorkflowTaskTimedOutEventAttributes(a) => Some(a.scheduled_event_id),
2381                                Attributes::WorkflowTaskFailedEventAttributes(a) => Some(a.scheduled_event_id),
2382                                Attributes::NexusOperationStartedEventAttributes(a) => Some(a.scheduled_event_id),
2383                                Attributes::NexusOperationCompletedEventAttributes(a) => Some(a.scheduled_event_id),
2384                                Attributes::NexusOperationFailedEventAttributes(a) => Some(a.scheduled_event_id),
2385                                Attributes::NexusOperationTimedOutEventAttributes(a) => Some(a.scheduled_event_id),
2386                                Attributes::NexusOperationCanceledEventAttributes(a) => Some(a.scheduled_event_id),
2387                                Attributes::NexusOperationCancelRequestedEventAttributes(a) => Some(a.scheduled_event_id),
2388                                Attributes::NexusOperationCancelRequestCompletedEventAttributes(a) => Some(a.scheduled_event_id),
2389                                Attributes::NexusOperationCancelRequestFailedEventAttributes(a) => Some(a.scheduled_event_id),
2390                                _ => None
2391                            }
2392                        })
2393                        }
2394
2395                        /// Return the event's associated protocol instance, if one exists.
2396                        pub fn get_protocol_instance_id(&self) -> Option<&str> {
2397                            self.attributes.as_ref().and_then(|a| match a {
2398                                Attributes::WorkflowExecutionUpdateAcceptedEventAttributes(a) => {
2399                                    Some(a.protocol_instance_id.as_str())
2400                                }
2401                                _ => None,
2402                            })
2403                        }
2404
2405                        /// Returns true if the event is one which would end a workflow
2406                        pub fn is_final_wf_execution_event(&self) -> bool {
2407                            match self.event_type() {
2408                                EventType::WorkflowExecutionCompleted => true,
2409                                EventType::WorkflowExecutionCanceled => true,
2410                                EventType::WorkflowExecutionFailed => true,
2411                                EventType::WorkflowExecutionTimedOut => true,
2412                                EventType::WorkflowExecutionContinuedAsNew => true,
2413                                EventType::WorkflowExecutionTerminated => true,
2414                                _ => false,
2415                            }
2416                        }
2417
2418                        pub fn is_wft_closed_event(&self) -> bool {
2419                            match self.event_type() {
2420                                EventType::WorkflowTaskCompleted => true,
2421                                EventType::WorkflowTaskFailed => true,
2422                                EventType::WorkflowTaskTimedOut => true,
2423                                _ => false,
2424                            }
2425                        }
2426
2427                        pub fn is_ignorable(&self) -> bool {
2428                            if !self.worker_may_ignore {
2429                                return false;
2430                            }
2431                            // Never add a catch-all case to this match statement. We need to explicitly
2432                            // mark any new event types as ignorable or not.
2433                            if let Some(a) = self.attributes.as_ref() {
2434                                match a {
2435                                    Attributes::WorkflowExecutionStartedEventAttributes(_) => false,
2436                                    Attributes::WorkflowExecutionCompletedEventAttributes(_) => false,
2437                                    Attributes::WorkflowExecutionFailedEventAttributes(_) => false,
2438                                    Attributes::WorkflowExecutionTimedOutEventAttributes(_) => false,
2439                                    Attributes::WorkflowTaskScheduledEventAttributes(_) => false,
2440                                    Attributes::WorkflowTaskStartedEventAttributes(_) => false,
2441                                    Attributes::WorkflowTaskCompletedEventAttributes(_) => false,
2442                                    Attributes::WorkflowTaskTimedOutEventAttributes(_) => false,
2443                                    Attributes::WorkflowTaskFailedEventAttributes(_) => false,
2444                                    Attributes::ActivityTaskScheduledEventAttributes(_) => false,
2445                                    Attributes::ActivityTaskStartedEventAttributes(_) => false,
2446                                    Attributes::ActivityTaskCompletedEventAttributes(_) => false,
2447                                    Attributes::ActivityTaskFailedEventAttributes(_) => false,
2448                                    Attributes::ActivityTaskTimedOutEventAttributes(_) => false,
2449                                    Attributes::TimerStartedEventAttributes(_) => false,
2450                                    Attributes::TimerFiredEventAttributes(_) => false,
2451                                    Attributes::ActivityTaskCancelRequestedEventAttributes(_) => false,
2452                                    Attributes::ActivityTaskCanceledEventAttributes(_) => false,
2453                                    Attributes::TimerCanceledEventAttributes(_) => false,
2454                                    Attributes::MarkerRecordedEventAttributes(_) => false,
2455                                    Attributes::WorkflowExecutionSignaledEventAttributes(_) => false,
2456                                    Attributes::WorkflowExecutionTerminatedEventAttributes(_) => false,
2457                                    Attributes::WorkflowExecutionCancelRequestedEventAttributes(_) => false,
2458                                    Attributes::WorkflowExecutionCanceledEventAttributes(_) => false,
2459                                    Attributes::RequestCancelExternalWorkflowExecutionInitiatedEventAttributes(_) => false,
2460                                    Attributes::RequestCancelExternalWorkflowExecutionFailedEventAttributes(_) => false,
2461                                    Attributes::ExternalWorkflowExecutionCancelRequestedEventAttributes(_) => false,
2462                                    Attributes::WorkflowExecutionContinuedAsNewEventAttributes(_) => false,
2463                                    Attributes::StartChildWorkflowExecutionInitiatedEventAttributes(_) => false,
2464                                    Attributes::StartChildWorkflowExecutionFailedEventAttributes(_) => false,
2465                                    Attributes::ChildWorkflowExecutionStartedEventAttributes(_) => false,
2466                                    Attributes::ChildWorkflowExecutionCompletedEventAttributes(_) => false,
2467                                    Attributes::ChildWorkflowExecutionFailedEventAttributes(_) => false,
2468                                    Attributes::ChildWorkflowExecutionCanceledEventAttributes(_) => false,
2469                                    Attributes::ChildWorkflowExecutionTimedOutEventAttributes(_) => false,
2470                                    Attributes::ChildWorkflowExecutionTerminatedEventAttributes(_) => false,
2471                                    Attributes::SignalExternalWorkflowExecutionInitiatedEventAttributes(_) => false,
2472                                    Attributes::SignalExternalWorkflowExecutionFailedEventAttributes(_) => false,
2473                                    Attributes::ExternalWorkflowExecutionSignaledEventAttributes(_) => false,
2474                                    Attributes::UpsertWorkflowSearchAttributesEventAttributes(_) => false,
2475                                    Attributes::WorkflowExecutionUpdateAcceptedEventAttributes(_) => false,
2476                                    Attributes::WorkflowExecutionUpdateRejectedEventAttributes(_) => false,
2477                                    Attributes::WorkflowExecutionUpdateCompletedEventAttributes(_) => false,
2478                                    Attributes::WorkflowPropertiesModifiedExternallyEventAttributes(_) => false,
2479                                    Attributes::ActivityPropertiesModifiedExternallyEventAttributes(_) => false,
2480                                    Attributes::WorkflowPropertiesModifiedEventAttributes(_) => false,
2481                                    Attributes::WorkflowExecutionUpdateAdmittedEventAttributes(_) => false,
2482                                    Attributes::NexusOperationScheduledEventAttributes(_) => false,
2483                                    Attributes::NexusOperationStartedEventAttributes(_) => false,
2484                                    Attributes::NexusOperationCompletedEventAttributes(_) => false,
2485                                    Attributes::NexusOperationFailedEventAttributes(_) => false,
2486                                    Attributes::NexusOperationCanceledEventAttributes(_) => false,
2487                                    Attributes::NexusOperationTimedOutEventAttributes(_) => false,
2488                                    Attributes::NexusOperationCancelRequestedEventAttributes(_) => false,
2489                                    // !! Ignorable !!
2490                                    Attributes::WorkflowExecutionOptionsUpdatedEventAttributes(_) => true,
2491                                    Attributes::NexusOperationCancelRequestCompletedEventAttributes(_) => false,
2492                                    Attributes::NexusOperationCancelRequestFailedEventAttributes(_) => false,
2493                                    // !! Ignorable !!
2494                                    Attributes::WorkflowExecutionPausedEventAttributes(_) => true,
2495                                    // !! Ignorable !!
2496                                    Attributes::WorkflowExecutionUnpausedEventAttributes(_) => true,
2497                                    // !! Ignorable !!
2498                                    Attributes::WorkflowExecutionTimeSkippingTransitionedEventAttributes(_) => true,
2499                                }
2500                            } else {
2501                                // Any event kind we _don't_ know about is only ignorable if it says so
2502                                self.worker_may_ignore
2503                            }
2504                        }
2505                    }
2506
2507                    impl Display for HistoryEvent {
2508                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2509                            write!(
2510                                f,
2511                                "HistoryEvent(id: {}, {:?})",
2512                                self.event_id,
2513                                EventType::try_from(self.event_type).unwrap_or_default()
2514                            )
2515                        }
2516                    }
2517
2518                    impl Attributes {
2519                        pub fn event_type(&self) -> EventType {
2520                            // I just absolutely _love_ this
2521                            match self {
2522                            Attributes::WorkflowExecutionStartedEventAttributes(_) => { EventType::WorkflowExecutionStarted }
2523                            Attributes::WorkflowExecutionCompletedEventAttributes(_) => { EventType::WorkflowExecutionCompleted }
2524                            Attributes::WorkflowExecutionFailedEventAttributes(_) => { EventType::WorkflowExecutionFailed }
2525                            Attributes::WorkflowExecutionTimedOutEventAttributes(_) => { EventType::WorkflowExecutionTimedOut }
2526                            Attributes::WorkflowTaskScheduledEventAttributes(_) => { EventType::WorkflowTaskScheduled }
2527                            Attributes::WorkflowTaskStartedEventAttributes(_) => { EventType::WorkflowTaskStarted }
2528                            Attributes::WorkflowTaskCompletedEventAttributes(_) => { EventType::WorkflowTaskCompleted }
2529                            Attributes::WorkflowTaskTimedOutEventAttributes(_) => { EventType::WorkflowTaskTimedOut }
2530                            Attributes::WorkflowTaskFailedEventAttributes(_) => { EventType::WorkflowTaskFailed }
2531                            Attributes::ActivityTaskScheduledEventAttributes(_) => { EventType::ActivityTaskScheduled }
2532                            Attributes::ActivityTaskStartedEventAttributes(_) => { EventType::ActivityTaskStarted }
2533                            Attributes::ActivityTaskCompletedEventAttributes(_) => { EventType::ActivityTaskCompleted }
2534                            Attributes::ActivityTaskFailedEventAttributes(_) => { EventType::ActivityTaskFailed }
2535                            Attributes::ActivityTaskTimedOutEventAttributes(_) => { EventType::ActivityTaskTimedOut }
2536                            Attributes::TimerStartedEventAttributes(_) => { EventType::TimerStarted }
2537                            Attributes::TimerFiredEventAttributes(_) => { EventType::TimerFired }
2538                            Attributes::ActivityTaskCancelRequestedEventAttributes(_) => { EventType::ActivityTaskCancelRequested }
2539                            Attributes::ActivityTaskCanceledEventAttributes(_) => { EventType::ActivityTaskCanceled }
2540                            Attributes::TimerCanceledEventAttributes(_) => { EventType::TimerCanceled }
2541                            Attributes::MarkerRecordedEventAttributes(_) => { EventType::MarkerRecorded }
2542                            Attributes::WorkflowExecutionSignaledEventAttributes(_) => { EventType::WorkflowExecutionSignaled }
2543                            Attributes::WorkflowExecutionTerminatedEventAttributes(_) => { EventType::WorkflowExecutionTerminated }
2544                            Attributes::WorkflowExecutionCancelRequestedEventAttributes(_) => { EventType::WorkflowExecutionCancelRequested }
2545                            Attributes::WorkflowExecutionCanceledEventAttributes(_) => { EventType::WorkflowExecutionCanceled }
2546                            Attributes::RequestCancelExternalWorkflowExecutionInitiatedEventAttributes(_) => { EventType::RequestCancelExternalWorkflowExecutionInitiated }
2547                            Attributes::RequestCancelExternalWorkflowExecutionFailedEventAttributes(_) => { EventType::RequestCancelExternalWorkflowExecutionFailed }
2548                            Attributes::ExternalWorkflowExecutionCancelRequestedEventAttributes(_) => { EventType::ExternalWorkflowExecutionCancelRequested }
2549                            Attributes::WorkflowExecutionContinuedAsNewEventAttributes(_) => { EventType::WorkflowExecutionContinuedAsNew }
2550                            Attributes::StartChildWorkflowExecutionInitiatedEventAttributes(_) => { EventType::StartChildWorkflowExecutionInitiated }
2551                            Attributes::StartChildWorkflowExecutionFailedEventAttributes(_) => { EventType::StartChildWorkflowExecutionFailed }
2552                            Attributes::ChildWorkflowExecutionStartedEventAttributes(_) => { EventType::ChildWorkflowExecutionStarted }
2553                            Attributes::ChildWorkflowExecutionCompletedEventAttributes(_) => { EventType::ChildWorkflowExecutionCompleted }
2554                            Attributes::ChildWorkflowExecutionFailedEventAttributes(_) => { EventType::ChildWorkflowExecutionFailed }
2555                            Attributes::ChildWorkflowExecutionCanceledEventAttributes(_) => { EventType::ChildWorkflowExecutionCanceled }
2556                            Attributes::ChildWorkflowExecutionTimedOutEventAttributes(_) => { EventType::ChildWorkflowExecutionTimedOut }
2557                            Attributes::ChildWorkflowExecutionTerminatedEventAttributes(_) => { EventType::ChildWorkflowExecutionTerminated }
2558                            Attributes::SignalExternalWorkflowExecutionInitiatedEventAttributes(_) => { EventType::SignalExternalWorkflowExecutionInitiated }
2559                            Attributes::SignalExternalWorkflowExecutionFailedEventAttributes(_) => { EventType::SignalExternalWorkflowExecutionFailed }
2560                            Attributes::ExternalWorkflowExecutionSignaledEventAttributes(_) => { EventType::ExternalWorkflowExecutionSignaled }
2561                            Attributes::UpsertWorkflowSearchAttributesEventAttributes(_) => { EventType::UpsertWorkflowSearchAttributes }
2562                            Attributes::WorkflowExecutionUpdateAdmittedEventAttributes(_) => { EventType::WorkflowExecutionUpdateAdmitted }
2563                            Attributes::WorkflowExecutionUpdateRejectedEventAttributes(_) => { EventType::WorkflowExecutionUpdateRejected }
2564                            Attributes::WorkflowExecutionUpdateAcceptedEventAttributes(_) => { EventType::WorkflowExecutionUpdateAccepted }
2565                            Attributes::WorkflowExecutionUpdateCompletedEventAttributes(_) => { EventType::WorkflowExecutionUpdateCompleted }
2566                            Attributes::WorkflowPropertiesModifiedExternallyEventAttributes(_) => { EventType::WorkflowPropertiesModifiedExternally }
2567                            Attributes::ActivityPropertiesModifiedExternallyEventAttributes(_) => { EventType::ActivityPropertiesModifiedExternally }
2568                            Attributes::WorkflowPropertiesModifiedEventAttributes(_) => { EventType::WorkflowPropertiesModified }
2569                            Attributes::NexusOperationScheduledEventAttributes(_) => { EventType::NexusOperationScheduled }
2570                            Attributes::NexusOperationStartedEventAttributes(_) => { EventType::NexusOperationStarted }
2571                            Attributes::NexusOperationCompletedEventAttributes(_) => { EventType::NexusOperationCompleted }
2572                            Attributes::NexusOperationFailedEventAttributes(_) => { EventType::NexusOperationFailed }
2573                            Attributes::NexusOperationCanceledEventAttributes(_) => { EventType::NexusOperationCanceled }
2574                            Attributes::NexusOperationTimedOutEventAttributes(_) => { EventType::NexusOperationTimedOut }
2575                            Attributes::NexusOperationCancelRequestedEventAttributes(_) => { EventType::NexusOperationCancelRequested }
2576                            Attributes::WorkflowExecutionOptionsUpdatedEventAttributes(_) => { EventType::WorkflowExecutionOptionsUpdated }
2577                            Attributes::NexusOperationCancelRequestCompletedEventAttributes(_) => { EventType::NexusOperationCancelRequestCompleted }
2578                            Attributes::NexusOperationCancelRequestFailedEventAttributes(_) => { EventType::NexusOperationCancelRequestFailed }
2579                            Attributes::WorkflowExecutionPausedEventAttributes(_) => { EventType::WorkflowExecutionPaused }
2580                            Attributes::WorkflowExecutionUnpausedEventAttributes(_) => { EventType::WorkflowExecutionUnpaused }
2581                            Attributes::WorkflowExecutionTimeSkippingTransitionedEventAttributes(_) => { EventType::WorkflowExecutionTimeSkippingTransitioned }
2582                        }
2583                        }
2584                    }
2585                }
2586            }
2587        }
2588        pub mod namespace {
2589            pub mod v1 {
2590                tonic::include_proto!("temporal.api.namespace.v1");
2591            }
2592        }
2593        pub mod operatorservice {
2594            pub mod v1 {
2595                tonic::include_proto!("temporal.api.operatorservice.v1");
2596            }
2597        }
2598        pub mod protocol {
2599            pub mod v1 {
2600                tonic::include_proto!("temporal.api.protocol.v1");
2601                mod sdk_helpers {
2602                    use super::*;
2603                    use std::fmt::{Display, Formatter};
2604
2605                    impl Display for Message {
2606                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2607                            write!(f, "ProtocolMessage({})", self.id)
2608                        }
2609                    }
2610                }
2611            }
2612        }
2613        pub mod query {
2614            pub mod v1 {
2615                tonic::include_proto!("temporal.api.query.v1");
2616            }
2617        }
2618        pub mod replication {
2619            pub mod v1 {
2620                tonic::include_proto!("temporal.api.replication.v1");
2621            }
2622        }
2623        pub mod rules {
2624            pub mod v1 {
2625                tonic::include_proto!("temporal.api.rules.v1");
2626            }
2627        }
2628        pub mod schedule {
2629            #[allow(rustdoc::invalid_html_tags)]
2630            pub mod v1 {
2631                tonic::include_proto!("temporal.api.schedule.v1");
2632            }
2633        }
2634        pub mod sdk {
2635            pub mod v1 {
2636                tonic::include_proto!("temporal.api.sdk.v1");
2637            }
2638        }
2639        pub mod taskqueue {
2640            pub mod v1 {
2641                tonic::include_proto!("temporal.api.taskqueue.v1");
2642                mod sdk_helpers {
2643                    use super::*;
2644                    use crate::protos::temporal::api::enums::v1::TaskQueueKind;
2645
2646                    impl From<String> for TaskQueue {
2647                        fn from(name: String) -> Self {
2648                            Self {
2649                                name,
2650                                kind: TaskQueueKind::Normal as i32,
2651                                normal_name: "".to_string(),
2652                            }
2653                        }
2654                    }
2655                }
2656            }
2657        }
2658        pub mod testservice {
2659            pub mod v1 {
2660                tonic::include_proto!("temporal.api.testservice.v1");
2661            }
2662        }
2663        pub mod update {
2664            pub mod v1 {
2665                tonic::include_proto!("temporal.api.update.v1");
2666                mod sdk_helpers {
2667                    use super::*;
2668                    use crate::protos::temporal::api::update::v1::outcome::Value;
2669
2670                    impl Outcome {
2671                        pub fn is_success(&self) -> bool {
2672                            match self.value {
2673                                Some(Value::Success(_)) => true,
2674                                _ => false,
2675                            }
2676                        }
2677                    }
2678                }
2679            }
2680        }
2681        pub mod version {
2682            pub mod v1 {
2683                tonic::include_proto!("temporal.api.version.v1");
2684            }
2685        }
2686        pub mod worker {
2687            pub mod v1 {
2688                tonic::include_proto!("temporal.api.worker.v1");
2689            }
2690        }
2691        pub mod workflow {
2692            pub mod v1 {
2693                tonic::include_proto!("temporal.api.workflow.v1");
2694            }
2695        }
2696        pub mod nexus {
2697            pub mod v1 {
2698                tonic::include_proto!("temporal.api.nexus.v1");
2699                pub use self::sdk_helpers::*;
2700                mod sdk_helpers {
2701                    use super::*;
2702                    use crate::protos::{
2703                        camel_case_to_screaming_snake,
2704                        temporal::api::{
2705                            common::{
2706                                self,
2707                                v1::link::{WorkflowEvent, workflow_event},
2708                            },
2709                            enums::v1::EventType,
2710                            failure,
2711                        },
2712                    };
2713                    use anyhow::{anyhow, bail};
2714                    use http::Uri;
2715                    #[cfg(feature = "serde_serialize")]
2716                    use prost::Name;
2717                    #[cfg(feature = "serde_serialize")]
2718                    use std::collections::HashMap;
2719                    use std::fmt::{Display, Formatter};
2720
2721                    impl Display for Response {
2722                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2723                            write!(f, "NexusResponse(",)?;
2724                            match &self.variant {
2725                                None => {}
2726                                Some(v) => {
2727                                    write!(f, "{v}")?;
2728                                }
2729                            }
2730                            write!(f, ")")
2731                        }
2732                    }
2733
2734                    impl Display for response::Variant {
2735                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2736                            match self {
2737                                response::Variant::StartOperation(_) => {
2738                                    write!(f, "StartOperation")
2739                                }
2740                                response::Variant::CancelOperation(_) => {
2741                                    write!(f, "CancelOperation")
2742                                }
2743                            }
2744                        }
2745                    }
2746
2747                    impl Display for HandlerError {
2748                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2749                            write!(f, "HandlerError")
2750                        }
2751                    }
2752
2753                    pub enum NexusTaskFailure {
2754                        Legacy(HandlerError),
2755                        Temporal(failure::v1::Failure),
2756                    }
2757
2758                    static SCHEME_PREFIX: &str = "temporal://";
2759
2760                    /// Attempt to parse a nexus lint into a workflow event link
2761                    pub fn workflow_event_link_from_nexus(
2762                        l: &Link,
2763                    ) -> Result<common::v1::Link, anyhow::Error> {
2764                        if !l.url.starts_with(SCHEME_PREFIX) {
2765                            bail!("Invalid scheme for nexus link: {:?}", l.url);
2766                        }
2767                        // We strip the scheme/authority portion because of
2768                        // https://github.com/hyperium/http/issues/696
2769                        let no_authority_url = l.url.strip_prefix(SCHEME_PREFIX).unwrap();
2770                        let uri = Uri::try_from(no_authority_url)?;
2771                        let parts = uri.into_parts();
2772                        let path = parts.path_and_query.ok_or_else(|| {
2773                            anyhow!("Failed to parse nexus link, invalid path: {:?}", l)
2774                        })?;
2775                        let path_parts = path.path().split('/').collect::<Vec<_>>();
2776                        if path_parts.get(1) != Some(&"namespaces") {
2777                            bail!("Invalid path for nexus link: {:?}", l);
2778                        }
2779                        let namespace = path_parts.get(2).ok_or_else(|| {
2780                            anyhow!("Failed to parse nexus link, no namespace: {:?}", l)
2781                        })?;
2782                        if path_parts.get(3) != Some(&"workflows") {
2783                            bail!("Invalid path for nexus link, no workflows segment: {:?}", l);
2784                        }
2785                        let workflow_id = path_parts.get(4).ok_or_else(|| {
2786                            anyhow!("Failed to parse nexus link, no workflow id: {:?}", l)
2787                        })?;
2788                        let run_id = path_parts.get(5).ok_or_else(|| {
2789                            anyhow!("Failed to parse nexus link, no run id: {:?}", l)
2790                        })?;
2791                        if path_parts.get(6) != Some(&"history") {
2792                            bail!("Invalid path for nexus link, no history segment: {:?}", l);
2793                        }
2794                        let reference = if let Some(query) = path.query() {
2795                            let mut eventref = workflow_event::EventReference::default();
2796                            let query_parts = query.split('&').collect::<Vec<_>>();
2797                            for qp in query_parts {
2798                                let mut kv = qp.split('=');
2799                                let key = kv.next().ok_or_else(|| {
2800                                    anyhow!("Failed to parse nexus link query parameter: {:?}", l)
2801                                })?;
2802                                let val = kv.next().ok_or_else(|| {
2803                                    anyhow!("Failed to parse nexus link query parameter: {:?}", l)
2804                                })?;
2805                                match key {
2806                                    "eventID" => {
2807                                        eventref.event_id = val.parse().map_err(|_| {
2808                                            anyhow!("Failed to parse nexus link event id: {:?}", l)
2809                                        })?;
2810                                    }
2811                                    "eventType" => {
2812                                        eventref.event_type = EventType::from_str_name(val)
2813                                            .unwrap_or_else(|| {
2814                                                EventType::from_str_name(
2815                                                    &("EVENT_TYPE_".to_string()
2816                                                        + &camel_case_to_screaming_snake(val)),
2817                                                )
2818                                                .unwrap_or_default()
2819                                            })
2820                                            .into()
2821                                    }
2822                                    _ => continue,
2823                                }
2824                            }
2825                            Some(workflow_event::Reference::EventRef(eventref))
2826                        } else {
2827                            None
2828                        };
2829
2830                        Ok(common::v1::Link {
2831                            variant: Some(common::v1::link::Variant::WorkflowEvent(
2832                                WorkflowEvent {
2833                                    namespace: namespace.to_string(),
2834                                    workflow_id: workflow_id.to_string(),
2835                                    run_id: run_id.to_string(),
2836                                    reference,
2837                                },
2838                            )),
2839                        })
2840                    }
2841
2842                    #[cfg(feature = "serde_serialize")]
2843                    impl TryFrom<failure::v1::Failure> for Failure {
2844                        type Error = serde_json::Error;
2845
2846                        fn try_from(mut f: failure::v1::Failure) -> Result<Self, Self::Error> {
2847                            // 1. Remove message from failure
2848                            let message = std::mem::take(&mut f.message);
2849
2850                            // 2. Serialize Failure as JSON
2851                            let details = serde_json::to_vec(&f)?;
2852
2853                            // 3. Package Temporal Failure as Nexus Failure
2854                            Ok(Failure {
2855                                message,
2856                                stack_trace: f.stack_trace,
2857                                metadata: HashMap::from([(
2858                                    "type".to_string(),
2859                                    failure::v1::Failure::full_name().into(),
2860                                )]),
2861                                details,
2862                                cause: None,
2863                            })
2864                        }
2865                    }
2866                }
2867            }
2868        }
2869        pub mod nexusservices {
2870            pub mod workerservice {
2871                pub mod v1 {
2872                    tonic::include_proto!("temporal.api.nexusservices.workerservice.v1");
2873                }
2874            }
2875        }
2876        pub mod workflowservice {
2877            pub mod v1 {
2878                tonic::include_proto!("temporal.api.workflowservice.v1");
2879                pub use self::sdk_helpers::*;
2880                mod sdk_helpers {
2881                    use super::*;
2882                    use std::{
2883                        convert::TryInto,
2884                        fmt::{Display, Formatter},
2885                        time::{Duration, SystemTime},
2886                    };
2887
2888                    macro_rules! sched_to_start_impl {
2889                        ($sched_field:ident) => {
2890                            /// Return the duration of the task schedule time (current attempt) to its
2891                            /// start time if both are set and time went forward.
2892                            pub fn sched_to_start(&self) -> Option<Duration> {
2893                                if let Some((sch, st)) =
2894                                    self.$sched_field.clone().zip(self.started_time.clone())
2895                                {
2896                                    if let Some(value) = elapsed_between_prost_times(sch, st) {
2897                                        return value;
2898                                    }
2899                                }
2900                                None
2901                            }
2902                        };
2903                    }
2904
2905                    fn elapsed_between_prost_times(
2906                        from: prost_types::Timestamp,
2907                        to: prost_types::Timestamp,
2908                    ) -> Option<Option<Duration>> {
2909                        let from: Result<SystemTime, _> = from.try_into();
2910                        let to: Result<SystemTime, _> = to.try_into();
2911                        if let (Ok(from), Ok(to)) = (from, to) {
2912                            return Some(to.duration_since(from).ok());
2913                        }
2914                        None
2915                    }
2916
2917                    impl PollWorkflowTaskQueueResponse {
2918                        sched_to_start_impl!(scheduled_time);
2919                    }
2920
2921                    impl Display for PollWorkflowTaskQueueResponse {
2922                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2923                            let last_event = self
2924                                .history
2925                                .as_ref()
2926                                .and_then(|h| h.events.last().map(|he| he.event_id))
2927                                .unwrap_or(0);
2928                            write!(
2929                                f,
2930                                "PollWFTQResp(run_id: {}, attempt: {}, last_event: {})",
2931                                self.workflow_execution
2932                                    .as_ref()
2933                                    .map_or("", |we| we.run_id.as_str()),
2934                                self.attempt,
2935                                last_event
2936                            )
2937                        }
2938                    }
2939
2940                    /// Can be used while debugging to avoid filling up a whole screen with poll resps
2941                    pub struct CompactHist<'a>(pub &'a PollWorkflowTaskQueueResponse);
2942                    impl Display for CompactHist<'_> {
2943                        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2944                            writeln!(
2945                                f,
2946                                "PollWorkflowTaskQueueResponse (prev_started: {}, started: {})",
2947                                self.0.previous_started_event_id, self.0.started_event_id
2948                            )?;
2949                            if let Some(h) = self.0.history.as_ref() {
2950                                for event in &h.events {
2951                                    writeln!(f, "{}", event)?;
2952                                }
2953                            }
2954                            writeln!(f, "query: {:#?}", self.0.query)?;
2955                            writeln!(f, "queries: {:#?}", self.0.queries)
2956                        }
2957                    }
2958
2959                    impl PollActivityTaskQueueResponse {
2960                        sched_to_start_impl!(current_attempt_scheduled_time);
2961                    }
2962
2963                    impl PollNexusTaskQueueResponse {
2964                        pub fn sched_to_start(&self) -> Option<Duration> {
2965                            if let Some((sch, st)) = self
2966                                .request
2967                                .as_ref()
2968                                .and_then(|r| r.scheduled_time)
2969                                .clone()
2970                                .zip(SystemTime::now().try_into().ok())
2971                            {
2972                                if let Some(value) = elapsed_between_prost_times(sch, st) {
2973                                    return value;
2974                                }
2975                            }
2976                            None
2977                        }
2978                    }
2979
2980                    impl QueryWorkflowResponse {
2981                        /// Unwrap a successful response as vec of payloads
2982                        pub fn unwrap(
2983                            self,
2984                        ) -> Vec<crate::protos::temporal::api::common::v1::Payload>
2985                        {
2986                            self.query_result.unwrap().payloads
2987                        }
2988                    }
2989                }
2990            }
2991        }
2992    }
2993}
2994
2995#[allow(
2996    clippy::all,
2997    missing_docs,
2998    rustdoc::broken_intra_doc_links,
2999    rustdoc::bare_urls
3000)]
3001pub mod google {
3002    pub mod rpc {
3003        tonic::include_proto!("google.rpc");
3004    }
3005}
3006
3007#[allow(
3008    clippy::all,
3009    missing_docs,
3010    rustdoc::broken_intra_doc_links,
3011    rustdoc::bare_urls
3012)]
3013pub mod grpc {
3014    pub mod health {
3015        pub mod v1 {
3016            tonic::include_proto!("grpc.health.v1");
3017        }
3018    }
3019}
3020mod sdk_helpers {
3021    use std::time::Duration;
3022
3023    /// Case conversion, used for json -> proto enum string conversion
3024    pub fn camel_case_to_screaming_snake(val: &str) -> String {
3025        let mut out = String::new();
3026        let mut last_was_upper = true;
3027        for c in val.chars() {
3028            if c.is_uppercase() {
3029                if !last_was_upper {
3030                    out.push('_');
3031                }
3032                out.push(c.to_ascii_uppercase());
3033                last_was_upper = true;
3034            } else {
3035                out.push(c.to_ascii_uppercase());
3036                last_was_upper = false;
3037            }
3038        }
3039        out
3040    }
3041
3042    /// Convert a protobuf [`prost_types::Timestamp`] to a [`std::time::SystemTime`].
3043    pub fn proto_ts_to_system_time(ts: &prost_types::Timestamp) -> Option<std::time::SystemTime> {
3044        std::time::SystemTime::UNIX_EPOCH.checked_add(
3045            Duration::from_secs(ts.seconds as u64) + Duration::from_nanos(ts.nanos as u64),
3046        )
3047    }
3048
3049    #[cfg(test)]
3050    mod tests {
3051        use crate::protos::{
3052            coresdk::{activity_task, activity_task::ActivityTask},
3053            temporal::api::{
3054                failure::v1::Failure, workflowservice::v1::PollActivityTaskQueueResponse,
3055            },
3056        };
3057        use anyhow::anyhow;
3058
3059        #[test]
3060        fn start_from_poll_resp_standalone_activity_populates_run_id() {
3061            let resp = PollActivityTaskQueueResponse {
3062                task_token: vec![1, 2, 3],
3063                activity_run_id: "test-run-id-123".to_string(),
3064                activity_id: "my-activity".to_string(),
3065                ..Default::default()
3066            };
3067            let task = ActivityTask::start_from_poll_resp(resp);
3068            let start = match task.variant {
3069                Some(activity_task::activity_task::Variant::Start(s)) => s,
3070                _ => panic!("expected Start variant"),
3071            };
3072            assert_eq!(start.run_id, "test-run-id-123");
3073            assert!(!start.is_local);
3074        }
3075
3076        #[test]
3077        fn start_from_poll_resp_workflow_activity_has_empty_run_id() {
3078            use crate::protos::temporal::api::common::v1::WorkflowExecution;
3079            let resp = PollActivityTaskQueueResponse {
3080                task_token: vec![4, 5, 6],
3081                activity_id: "my-workflow-activity".to_string(),
3082                workflow_execution: Some(WorkflowExecution {
3083                    workflow_id: "wf-123".to_string(),
3084                    run_id: "wf-run-456".to_string(),
3085                }),
3086                // activity_run_id intentionally absent — this is a workflow-scheduled activity
3087                ..Default::default()
3088            };
3089            let task = ActivityTask::start_from_poll_resp(resp);
3090            let start = match task.variant {
3091                Some(activity_task::activity_task::Variant::Start(s)) => s,
3092                _ => panic!("expected Start variant"),
3093            };
3094            assert!(start.run_id.is_empty());
3095            // workflow_execution is preserved and distinct from run_id
3096            assert_eq!(start.workflow_execution.unwrap().run_id, "wf-run-456");
3097        }
3098
3099        #[test]
3100        fn anyhow_to_failure_conversion() {
3101            let no_causes: Failure = anyhow!("no causes").into();
3102            assert_eq!(no_causes.cause, None);
3103            assert_eq!(no_causes.message, "no causes");
3104            let orig = anyhow!("fail 1");
3105            let mid = orig.context("fail 2");
3106            let top = mid.context("fail 3");
3107            let as_fail: Failure = top.into();
3108            assert_eq!(as_fail.message, "fail 3");
3109            assert_eq!(as_fail.cause.as_ref().unwrap().message, "fail 2");
3110            assert_eq!(as_fail.cause.unwrap().cause.unwrap().message, "fail 1");
3111        }
3112    }
3113}
3114pub use self::sdk_helpers::*;