1use std::sync::Arc;
2
3pub struct WorkflowContext<C, M> {
9 pub workflow_id: Arc<str>,
11 pub codec: Arc<C>,
13 pub metadata: Arc<M>,
15}
16
17impl<C, M> Clone for WorkflowContext<C, M> {
18 fn clone(&self) -> Self {
19 Self {
20 workflow_id: Arc::clone(&self.workflow_id),
21 codec: Arc::clone(&self.codec),
22 metadata: Arc::clone(&self.metadata),
23 }
24 }
25}
26
27impl<C, M> WorkflowContext<C, M> {
28 pub fn new(workflow_id: impl Into<Arc<str>>, codec: Arc<C>, metadata: Arc<M>) -> Self {
30 Self {
31 workflow_id: workflow_id.into(),
32 codec,
33 metadata,
34 }
35 }
36
37 #[must_use]
38 pub fn workflow_id(&self) -> &str {
39 &self.workflow_id
40 }
41
42 #[must_use]
43 pub fn codec(&self) -> Arc<C> {
44 self.codec.clone()
45 }
46
47 #[must_use]
48 pub fn metadata(&self) -> Arc<M> {
49 self.metadata.clone()
50 }
51}
52
53#[cfg(feature = "tokio")]
56mod task_local_ctx {
57 use super::{Arc, WorkflowContext};
58 use crate::codec::Codec;
59
60 struct ErasedContext {
62 inner: Arc<dyn std::any::Any + Send + Sync>,
63 }
64
65 impl ErasedContext {
66 fn new<C, M>(ctx: WorkflowContext<C, M>) -> Self
67 where
68 C: Codec + 'static,
69 M: Send + Sync + 'static,
70 {
71 Self {
72 inner: Arc::new(ctx) as Arc<dyn std::any::Any + Send + Sync>,
73 }
74 }
75
76 fn downcast<C, M>(&self) -> Option<WorkflowContext<C, M>>
77 where
78 C: Codec + 'static,
79 M: Send + Sync + 'static,
80 {
81 self.inner
82 .clone()
83 .downcast::<WorkflowContext<C, M>>()
84 .ok()
85 .map(|arc| {
86 WorkflowContext::new(
87 Arc::clone(&arc.workflow_id),
88 Arc::clone(&arc.codec),
89 Arc::clone(&arc.metadata),
90 )
91 })
92 }
93 }
94
95 tokio::task_local! {
96 static WORKFLOW_CTX: Option<ErasedContext>;
98 }
99
100 pub async fn with_context<C, M, F, Fut>(ctx: WorkflowContext<C, M>, f: F) -> Fut::Output
104 where
105 C: Codec + 'static,
106 M: Send + Sync + 'static,
107 F: FnOnce() -> Fut,
108 Fut: std::future::Future,
109 {
110 WORKFLOW_CTX.scope(Some(ErasedContext::new(ctx)), f()).await
111 }
112
113 #[must_use]
117 pub fn get_context<C, M>() -> Option<WorkflowContext<C, M>>
118 where
119 C: Codec + 'static,
120 M: Send + Sync + 'static,
121 {
122 WORKFLOW_CTX
123 .try_with(|ctx_opt| ctx_opt.as_ref()?.downcast())
124 .ok()
125 .flatten()
126 }
127}
128
129#[cfg(feature = "tokio")]
130pub use task_local_ctx::{get_context, with_context};
131
132#[cfg(feature = "tokio")]
145#[macro_export]
146macro_rules! sayiir_ctx {
147 () => {
148 $crate::context::get_context()
149 };
150}