Skip to main content

temporalio_workflow/
memo.rs

1use std::{collections::BTreeMap, rc::Rc};
2
3use temporalio_common_wasm::{
4    data_converters::{
5        GenericPayloadConverter, PayloadConversionError, PayloadConverter, SerializationContext,
6        SerializationContextData, TemporalSerializable,
7    },
8    protos::temporal::api::common::v1::Payload,
9};
10
11trait SerializableMemoValue {
12    fn to_payload(
13        &self,
14        payload_converter: &PayloadConverter,
15    ) -> Result<Payload, PayloadConversionError>;
16}
17
18impl<T> SerializableMemoValue for T
19where
20    T: TemporalSerializable + 'static,
21{
22    fn to_payload(
23        &self,
24        payload_converter: &PayloadConverter,
25    ) -> Result<Payload, PayloadConversionError> {
26        payload_converter.to_payload(
27            &SerializationContext {
28                data: &SerializationContextData::Workflow,
29                converter: payload_converter,
30            },
31            self,
32        )
33    }
34}
35
36/// A typed value used in a workflow memo update.
37#[derive(Clone, derive_more::Debug)]
38#[non_exhaustive]
39pub struct MemoValue {
40    #[debug(skip)]
41    value: Rc<dyn SerializableMemoValue>,
42}
43
44impl MemoValue {
45    /// Create a memo value that will be serialized with the workflow's data converter.
46    pub fn new<T: TemporalSerializable + 'static>(value: T) -> Self {
47        Self {
48            value: Rc::new(value),
49        }
50    }
51
52    pub(crate) fn to_payload(
53        &self,
54        payload_converter: &PayloadConverter,
55    ) -> Result<Payload, PayloadConversionError> {
56        self.value.to_payload(payload_converter)
57    }
58}
59
60/// A complete set of memo values for a new workflow execution.
61#[derive(Clone, Debug, Default)]
62#[non_exhaustive]
63pub struct MemoValues {
64    values: BTreeMap<String, MemoValue>,
65}
66
67impl MemoValues {
68    /// Create an empty set of memo values.
69    pub fn new() -> Self {
70        Self::default()
71    }
72
73    /// Add or replace a memo value.
74    pub fn insert<T>(&mut self, key: impl Into<String>, value: T) -> &mut Self
75    where
76        T: TemporalSerializable + 'static,
77    {
78        self.values.insert(key.into(), MemoValue::new(value));
79        self
80    }
81
82    pub(crate) fn encode(
83        &self,
84        payload_converter: &PayloadConverter,
85    ) -> Result<std::collections::HashMap<String, Payload>, PayloadConversionError> {
86        self.values
87            .iter()
88            .map(|(key, value)| {
89                value
90                    .to_payload(payload_converter)
91                    .map(|payload| (key.clone(), payload))
92            })
93            .collect()
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use temporalio_common_wasm::{Memo, protos::temporal::api::common::v1::Memo as ProtoMemo};
101
102    #[test]
103    fn memo_values_serialize_heterogeneous_values() {
104        let payload_converter = PayloadConverter::default();
105        let mut values = MemoValues::new();
106        values
107            .insert("count", 7_u32)
108            .insert("label", "hello".to_string());
109
110        let memo = Memo::from_raw(
111            Some(ProtoMemo {
112                fields: values.encode(&payload_converter).unwrap(),
113            }),
114            payload_converter,
115            SerializationContextData::Workflow,
116        );
117
118        assert_eq!(memo.get::<u32>("count").unwrap(), Some(7));
119        assert_eq!(
120            memo.get::<String>("label").unwrap(),
121            Some("hello".to_string())
122        );
123    }
124}