11//! Contains traits for and default implementations of data converters, codecs, and other
22//! serialization related functionality.
33
4- use crate :: protos:: temporal:: api:: { common:: v1:: Payload , failure:: v1:: Failure } ;
4+ mod failure_converter;
5+
6+ pub use failure_converter:: {
7+ ActivityExecutionDecodeHint , ChildWorkflowExecutionDecodeHint , ChildWorkflowSignalDecodeHint ,
8+ ChildWorkflowStartDecodeHint , DefaultFailureConverter , FailureConverter , FailureDecodeHint ,
9+ } ;
10+
11+ use crate :: protos:: temporal:: api:: common:: v1:: Payload ;
512use futures:: { FutureExt , future:: BoxFuture } ;
613use std:: { collections:: HashMap , sync:: Arc } ;
714
@@ -22,6 +29,7 @@ impl std::fmt::Debug for DataConverter {
2229 . finish_non_exhaustive ( )
2330 }
2431}
32+
2533impl DataConverter {
2634 /// Create a new DataConverter with the given payload converter, failure converter, and codec.
2735 pub fn new (
@@ -105,6 +113,34 @@ impl DataConverter {
105113 & self . payload_converter
106114 }
107115
116+ /// Returns the failure converter component of this data converter.
117+ pub fn failure_converter ( & self ) -> & ( dyn FailureConverter + Send + Sync ) {
118+ self . failure_converter . as_ref ( )
119+ }
120+
121+ /// Decode a Temporal failure into a caller-facing Rust error surface.
122+ pub fn to_error < H : FailureDecodeHint > (
123+ & self ,
124+ context : & SerializationContextData ,
125+ failure : crate :: protos:: temporal:: api:: failure:: v1:: Failure ,
126+ hint : H ,
127+ ) -> Result < H :: Output , PayloadConversionError > {
128+ let normalized =
129+ self . failure_converter
130+ . to_error ( failure, & self . payload_converter , context) ?;
131+ Ok ( hint. adapt ( normalized) )
132+ }
133+
134+ /// Encode a typed Rust error surface into a Temporal failure.
135+ pub fn to_failure (
136+ & self ,
137+ context : & SerializationContextData ,
138+ error : crate :: error:: OutgoingError ,
139+ ) -> crate :: protos:: temporal:: api:: failure:: v1:: Failure {
140+ self . failure_converter
141+ . to_failure ( error, & self . payload_converter , context)
142+ }
143+
108144 /// Returns the codec component of this data converter.
109145 pub fn codec ( & self ) -> & ( dyn PayloadCodec + Send + Sync ) {
110146 self . codec . as_ref ( )
@@ -196,26 +232,6 @@ impl std::error::Error for PayloadConversionError {
196232 }
197233}
198234
199- /// Converts between Rust errors and Temporal [`Failure`] protobufs.
200- pub trait FailureConverter {
201- /// Convert an error into a Temporal failure protobuf.
202- fn to_failure (
203- & self ,
204- error : Box < dyn std:: error:: Error > ,
205- payload_converter : & PayloadConverter ,
206- context : & SerializationContextData ,
207- ) -> Result < Failure , PayloadConversionError > ;
208-
209- /// Convert a Temporal failure protobuf back into a Rust error.
210- fn to_error (
211- & self ,
212- failure : Failure ,
213- payload_converter : & PayloadConverter ,
214- context : & SerializationContextData ,
215- ) -> Result < Box < dyn std:: error:: Error > , PayloadConversionError > ;
216- }
217- /// Default (currently unimplemented) failure converter.
218- pub struct DefaultFailureConverter ;
219235/// Encodes and decodes payloads, enabling encryption or compression.
220236pub trait PayloadCodec {
221237 /// Encode payloads before they are sent to the server.
@@ -307,6 +323,53 @@ pub trait TemporalDeserializable: Sized {
307323 }
308324}
309325
326+ /// A codec-decoded set of payloads that can be deserialized later with to a user provided type.
327+ #[ derive( Clone , Debug ) ]
328+ pub struct DecodablePayloads {
329+ payloads : Vec < Payload > ,
330+ payload_converter : PayloadConverter ,
331+ context : SerializationContextData ,
332+ }
333+
334+ impl DecodablePayloads {
335+ /// Create a new decodable payload set from raw payloads and the converter context needed to
336+ /// deserialize them later.
337+ pub fn new (
338+ payloads : Vec < Payload > ,
339+ payload_converter : PayloadConverter ,
340+ context : SerializationContextData ,
341+ ) -> Self {
342+ Self {
343+ payloads,
344+ payload_converter,
345+ context,
346+ }
347+ }
348+
349+ /// Deserialize these payloads into a typed value using the stored payload converter.
350+ pub fn deserialize < T : TemporalDeserializable + ' static > (
351+ & self ,
352+ ) -> Result < T , PayloadConversionError > {
353+ self . payload_converter . from_payloads (
354+ & SerializationContext {
355+ data : & self . context ,
356+ converter : & self . payload_converter ,
357+ } ,
358+ self . payloads . clone ( ) ,
359+ )
360+ }
361+
362+ /// Returns the underlying payloads.
363+ pub fn raw ( & self ) -> & [ Payload ] {
364+ & self . payloads
365+ }
366+
367+ /// Consume this value and return the underlying payloads as a [`RawValue`].
368+ pub fn into_raw ( self ) -> RawValue {
369+ RawValue :: new ( self . payloads )
370+ }
371+ }
372+
310373/// An unconverted set of payloads, used when the caller wants to defer deserialization.
311374#[ derive( Clone , Debug , Default ) ]
312375pub struct RawValue {
@@ -672,24 +735,6 @@ impl Default for DataConverter {
672735 )
673736 }
674737}
675- impl FailureConverter for DefaultFailureConverter {
676- fn to_failure (
677- & self ,
678- _: Box < dyn std:: error:: Error > ,
679- _: & PayloadConverter ,
680- _: & SerializationContextData ,
681- ) -> Result < Failure , PayloadConversionError > {
682- todo ! ( )
683- }
684- fn to_error (
685- & self ,
686- _: Failure ,
687- _: & PayloadConverter ,
688- _: & SerializationContextData ,
689- ) -> Result < Box < dyn std:: error:: Error > , PayloadConversionError > {
690- todo ! ( )
691- }
692- }
693738impl PayloadCodec for DefaultPayloadCodec {
694739 fn encode (
695740 & self ,
@@ -866,4 +911,53 @@ mod tests {
866911 let args: MultiArgs2 < String , i32 > = ( "hello" . to_string ( ) , 42i32 ) . into ( ) ;
867912 assert_eq ! ( args, MultiArgs2 ( "hello" . to_string( ) , 42 ) ) ;
868913 }
914+
915+ fn decodable_from_value < T : TemporalSerializable + ' static > ( value : & T ) -> DecodablePayloads {
916+ let converter = PayloadConverter :: default ( ) ;
917+ let payloads = converter
918+ . to_payloads (
919+ & SerializationContext {
920+ data : & SerializationContextData :: Workflow ,
921+ converter : & converter,
922+ } ,
923+ value,
924+ )
925+ . unwrap ( ) ;
926+ DecodablePayloads :: new ( payloads, converter, SerializationContextData :: Workflow )
927+ }
928+ #[ test]
929+ fn decodable_payloads_roundtrip_string ( ) {
930+ let payloads = decodable_from_value ( & "hello" . to_string ( ) ) ;
931+
932+ let result: String = payloads. deserialize ( ) . unwrap ( ) ;
933+
934+ assert_eq ! ( result, "hello" ) ;
935+ }
936+
937+ #[ test]
938+ fn decodable_payloads_roundtrip_option_string ( ) {
939+ let payloads = decodable_from_value ( & Some ( "hello" . to_string ( ) ) ) ;
940+
941+ let result: Option < String > = payloads. deserialize ( ) . unwrap ( ) ;
942+
943+ assert_eq ! ( result, Some ( "hello" . to_string( ) ) ) ;
944+ }
945+
946+ #[ test]
947+ fn decodable_payloads_roundtrip_unit ( ) {
948+ let payloads = decodable_from_value ( & ( ) ) ;
949+
950+ let result: ( ) = payloads. deserialize ( ) . unwrap ( ) ;
951+
952+ assert_eq ! ( result, ( ) ) ;
953+ }
954+
955+ #[ test]
956+ fn decodable_payloads_roundtrip_vec_string ( ) {
957+ let payloads = decodable_from_value ( & vec ! [ "hello" . to_string( ) , "world" . to_string( ) ] ) ;
958+
959+ let result: Vec < String > = payloads. deserialize ( ) . unwrap ( ) ;
960+
961+ assert_eq ! ( result, vec![ "hello" . to_string( ) , "world" . to_string( ) ] ) ;
962+ }
869963}
0 commit comments