Skip to main content

durable_execution_sdk/
traits.rs

1//! Trait aliases for common bounds in the AWS Durable Execution SDK.
2//!
3//! This module provides trait aliases that simplify common trait bound combinations
4//! used throughout the SDK. These aliases make function signatures more readable
5//! and maintainable while preserving full type safety.
6//!
7//! # Overview
8//!
9//! The SDK frequently requires types to implement multiple traits for serialization,
10//! thread safety, and lifetime requirements. Instead of repeating these bounds
11//! everywhere, this module provides convenient trait aliases.
12//!
13//! # Available Trait Aliases
14//!
15//! - [`DurableValue`]: For values that can be durably stored and retrieved
16//! - [`StepError`]: The boxed error type returned by step functions
17//! - [`StepFuture`]: Type alias for the future returned by async step functions
18//!
19//! # Example
20//!
21//! ```rust
22//! use durable_execution_sdk::traits::DurableValue;
23//!
24//! // Using DurableValue in a generic function
25//! fn process_value<T: DurableValue>(value: T) -> String {
26//!     // T is guaranteed to be Serialize + DeserializeOwned + Send
27//!     serde_json::to_string(&value).unwrap_or_default()
28//! }
29//! ```
30
31use serde::{de::DeserializeOwned, Serialize};
32
33/// The error type returned by step functions.
34pub type StepError = Box<dyn std::error::Error + Send + Sync>;
35
36/// Type alias for the future returned by async step functions.
37///
38/// This simplifies signatures that would otherwise need:
39/// ```text
40/// Fut: Future<Output = Result<T, Box<dyn std::error::Error + Send + Sync>>> + Send
41/// ```
42pub type StepFuture<T> =
43    std::pin::Pin<Box<dyn std::future::Future<Output = Result<T, StepError>> + Send>>;
44
45/// Trait alias for values that can be durably stored and retrieved.
46///
47/// This trait combines the necessary bounds for serialization, deserialization,
48/// and thread-safe sending across async boundaries. Any type implementing
49/// `DurableValue` can be:
50///
51/// - Serialized to JSON for checkpointing
52/// - Deserialized from JSON during replay
53/// - Safely sent between threads
54///
55/// # Equivalent Bounds
56///
57/// `DurableValue` is equivalent to:
58/// ```text
59/// Serialize + DeserializeOwned + Send
60/// ```
61///
62/// # Blanket Implementation
63///
64/// This trait is automatically implemented for all types that satisfy the bounds.
65/// You don't need to implement it manually.
66///
67/// # Example
68///
69/// ```rust
70/// use durable_execution_sdk::traits::DurableValue;
71/// use serde::{Deserialize, Serialize};
72///
73/// // This type automatically implements DurableValue
74/// #[derive(Debug, Clone, Serialize, Deserialize)]
75/// struct OrderResult {
76///     order_id: String,
77///     status: String,
78///     total: f64,
79/// }
80///
81/// // Use in generic functions
82/// fn store_result<T: DurableValue>(result: T) {
83///     let json = serde_json::to_string(&result).unwrap();
84///     println!("Storing: {}", json);
85/// }
86///
87/// let result = OrderResult {
88///     order_id: "ORD-123".to_string(),
89///     status: "completed".to_string(),
90///     total: 99.99,
91/// };
92/// store_result(result);
93/// ```
94pub trait DurableValue: Serialize + DeserializeOwned + Send {}
95
96/// Blanket implementation for all types meeting the bounds.
97impl<T> DurableValue for T where T: Serialize + DeserializeOwned + Send {}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use serde::{Deserialize, Serialize};
103
104    // Test that common types implement DurableValue
105    #[test]
106    fn test_durable_value_primitives() {
107        fn assert_durable_value<T: DurableValue>() {}
108
109        assert_durable_value::<i32>();
110        assert_durable_value::<i64>();
111        assert_durable_value::<u32>();
112        assert_durable_value::<u64>();
113        assert_durable_value::<f32>();
114        assert_durable_value::<f64>();
115        assert_durable_value::<bool>();
116        assert_durable_value::<String>();
117        assert_durable_value::<()>();
118    }
119
120    #[test]
121    fn test_durable_value_collections() {
122        fn assert_durable_value<T: DurableValue>() {}
123
124        assert_durable_value::<Vec<i32>>();
125        assert_durable_value::<Vec<String>>();
126        assert_durable_value::<std::collections::HashMap<String, i32>>();
127        assert_durable_value::<Option<String>>();
128    }
129
130    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
131    struct TestStruct {
132        id: String,
133        value: i32,
134    }
135
136    #[test]
137    fn test_durable_value_custom_struct() {
138        fn assert_durable_value<T: DurableValue>() {}
139        assert_durable_value::<TestStruct>();
140    }
141
142    #[test]
143    fn test_durable_value_serialization() {
144        fn serialize_value<T: DurableValue>(value: &T) -> String {
145            serde_json::to_string(value).unwrap()
146        }
147
148        fn deserialize_value<T: DurableValue>(json: &str) -> T {
149            serde_json::from_str(json).unwrap()
150        }
151
152        let original = TestStruct {
153            id: "test-123".to_string(),
154            value: 42,
155        };
156
157        let json = serialize_value(&original);
158        let restored: TestStruct = deserialize_value(&json);
159
160        assert_eq!(original, restored);
161    }
162}