@@ -17,7 +17,134 @@ use std::sync::Arc;
1717// Re-export Pack types for convenient use throughout Theater
1818// Note: We use composite's internal abi module, not composite_abi crate directly,
1919// because that's what the runtime functions return.
20- pub use pack:: abi:: { FromValue , FromValueError , Value , ValueType } ;
20+ pub use pack:: abi:: { Value , ValueType } ;
21+
22+ // ============================================================================
23+ // Value Conversion Types
24+ // ============================================================================
25+
26+ /// Error type for Value conversions
27+ #[ derive( Debug , Clone ) ]
28+ pub enum ConversionError {
29+ /// Type mismatch during conversion
30+ TypeMismatch { expected : String , got : String } ,
31+ /// Missing field in record
32+ MissingField ( String ) ,
33+ /// Missing index in tuple/list
34+ MissingIndex ( usize ) ,
35+ /// Missing payload for variant
36+ MissingPayload ,
37+ /// Field conversion error
38+ FieldError ( String , Box < ConversionError > ) ,
39+ /// Index conversion error
40+ IndexError ( usize , Box < ConversionError > ) ,
41+ }
42+
43+ impl std:: fmt:: Display for ConversionError {
44+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
45+ match self {
46+ Self :: TypeMismatch { expected, got } => {
47+ write ! ( f, "type mismatch: expected {}, got {}" , expected, got)
48+ }
49+ Self :: MissingField ( name) => write ! ( f, "missing field: {}" , name) ,
50+ Self :: MissingIndex ( idx) => write ! ( f, "missing index: {}" , idx) ,
51+ Self :: MissingPayload => write ! ( f, "missing payload for variant" ) ,
52+ Self :: FieldError ( name, e) => write ! ( f, "field '{}': {}" , name, e) ,
53+ Self :: IndexError ( idx, e) => write ! ( f, "index {}: {}" , idx, e) ,
54+ }
55+ }
56+ }
57+
58+ impl std:: error:: Error for ConversionError { }
59+
60+ /// Trait for converting from a Pack Value.
61+ ///
62+ /// This is Theater's local version that works with pack::abi::Value.
63+ pub trait FromValue : Sized {
64+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > ;
65+ }
66+
67+ // Basic FromValue implementations
68+
69+ impl FromValue for ( ) {
70+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > {
71+ match v {
72+ Value :: Tuple ( items) if items. is_empty ( ) => Ok ( ( ) ) ,
73+ other => Err ( ConversionError :: TypeMismatch {
74+ expected : String :: from ( "()" ) ,
75+ got : format ! ( "{:?}" , other) ,
76+ } ) ,
77+ }
78+ }
79+ }
80+
81+ impl FromValue for String {
82+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > {
83+ match v {
84+ Value :: String ( s) => Ok ( s) ,
85+ other => Err ( ConversionError :: TypeMismatch {
86+ expected : String :: from ( "String" ) ,
87+ got : format ! ( "{:?}" , other) ,
88+ } ) ,
89+ }
90+ }
91+ }
92+
93+ impl FromValue for i64 {
94+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > {
95+ match v {
96+ Value :: S64 ( n) => Ok ( n) ,
97+ other => Err ( ConversionError :: TypeMismatch {
98+ expected : String :: from ( "i64" ) ,
99+ got : format ! ( "{:?}" , other) ,
100+ } ) ,
101+ }
102+ }
103+ }
104+
105+ impl FromValue for i32 {
106+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > {
107+ match v {
108+ Value :: S32 ( n) => Ok ( n) ,
109+ other => Err ( ConversionError :: TypeMismatch {
110+ expected : String :: from ( "i32" ) ,
111+ got : format ! ( "{:?}" , other) ,
112+ } ) ,
113+ }
114+ }
115+ }
116+
117+ impl FromValue for bool {
118+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > {
119+ match v {
120+ Value :: Bool ( b) => Ok ( b) ,
121+ other => Err ( ConversionError :: TypeMismatch {
122+ expected : String :: from ( "bool" ) ,
123+ got : format ! ( "{:?}" , other) ,
124+ } ) ,
125+ }
126+ }
127+ }
128+
129+ impl < T : FromValue > FromValue for Vec < T > {
130+ fn from_value ( v : Value ) -> std:: result:: Result < Self , ConversionError > {
131+ match v {
132+ Value :: List { items, .. } => {
133+ items. into_iter ( )
134+ . enumerate ( )
135+ . map ( |( i, item) | {
136+ T :: from_value ( item) . map_err ( |e| ConversionError :: IndexError ( i, Box :: new ( e) ) )
137+ } )
138+ . collect ( )
139+ }
140+ other => Err ( ConversionError :: TypeMismatch {
141+ expected : String :: from ( "List" ) ,
142+ got : format ! ( "{:?}" , other) ,
143+ } ) ,
144+ }
145+ }
146+ }
147+
21148pub use pack:: {
22149 AsyncCtx , AsyncInstance , AsyncRuntime , CallInterceptor , Ctx , HostFunctionProvider ,
23150 HostLinkerBuilder , InterfaceBuilder , LinkerError ,
@@ -529,7 +656,7 @@ pub struct ActorResult<T> {
529656}
530657
531658impl < T : FromValue > FromValue for ActorResult < T > {
532- fn from_value ( value : Value ) -> std:: result:: Result < Self , FromValueError > {
659+ fn from_value ( value : Value ) -> std:: result:: Result < Self , ConversionError > {
533660 match value {
534661 // Handle Value::Result (Pack's native result type)
535662 Value :: Result { value : Ok ( inner) , .. } => {
@@ -540,14 +667,17 @@ impl<T: FromValue> FromValue for ActorResult<T> {
540667 Value :: String ( s) => s,
541668 other => format ! ( "{:?}" , other) ,
542669 } ;
543- Err ( FromValueError :: Custom ( format ! ( "Actor error: {}" , error_msg) ) )
670+ Err ( ConversionError :: TypeMismatch {
671+ expected : String :: from ( "Ok result" ) ,
672+ got : format ! ( "Actor error: {}" , error_msg) ,
673+ } )
544674 }
545675 // Handle Value::Variant (alternative encoding)
546676 Value :: Variant { tag : 0 , payload, .. } if !payload. is_empty ( ) => {
547677 decode_actor_ok_payload ( payload. into_iter ( ) . next ( ) . unwrap ( ) )
548678 }
549679 Value :: Variant { tag : 0 , .. } => {
550- Err ( FromValueError :: Custom ( "Ok variant with empty payload" . to_string ( ) ) )
680+ Err ( ConversionError :: MissingPayload )
551681 }
552682 Value :: Variant { tag : 1 , payload, .. } => {
553683 let error_msg = payload. into_iter ( ) . next ( )
@@ -556,11 +686,14 @@ impl<T: FromValue> FromValue for ActorResult<T> {
556686 other => format ! ( "{:?}" , other) ,
557687 } )
558688 . unwrap_or_else ( || "Unknown error" . to_string ( ) ) ;
559- Err ( FromValueError :: Custom ( format ! ( "Actor error: {}" , error_msg) ) )
689+ Err ( ConversionError :: TypeMismatch {
690+ expected : String :: from ( "Ok result" ) ,
691+ got : format ! ( "Actor error: {}" , error_msg) ,
692+ } )
560693 }
561694 other => {
562- Err ( FromValueError :: TypeMismatch {
563- expected : "Result or Variant" ,
695+ Err ( ConversionError :: TypeMismatch {
696+ expected : String :: from ( "Result or Variant" ) ,
564697 got : format ! ( "{:?}" , other) ,
565698 } )
566699 }
@@ -569,7 +702,7 @@ impl<T: FromValue> FromValue for ActorResult<T> {
569702}
570703
571704/// Helper to decode the Ok payload of an actor result.
572- fn decode_actor_ok_payload < T : FromValue > ( value : Value ) -> std:: result:: Result < ActorResult < T > , FromValueError > {
705+ fn decode_actor_ok_payload < T : FromValue > ( value : Value ) -> std:: result:: Result < ActorResult < T > , ConversionError > {
573706 match value {
574707 Value :: Tuple ( mut items) if !items. is_empty ( ) => {
575708 // First element is state: option<list<u8>>
@@ -580,23 +713,23 @@ fn decode_actor_ok_payload<T: FromValue>(value: Value) -> std::result::Result<Ac
580713 let bytes: std:: result:: Result < Vec < u8 > , _ > = items. into_iter ( )
581714 . map ( |v| match v {
582715 Value :: U8 ( b) => Ok ( b) ,
583- other => Err ( FromValueError :: TypeMismatch {
584- expected : "U8" ,
716+ other => Err ( ConversionError :: TypeMismatch {
717+ expected : String :: from ( "U8" ) ,
585718 got : format ! ( "{:?}" , other) ,
586719 } ) ,
587720 } )
588721 . collect ( ) ;
589722 Some ( bytes?)
590723 }
591- other => return Err ( FromValueError :: TypeMismatch {
592- expected : "List<u8>" ,
724+ other => return Err ( ConversionError :: TypeMismatch {
725+ expected : String :: from ( "List<u8>" ) ,
593726 got : format ! ( "{:?}" , other) ,
594727 } ) ,
595728 }
596729 }
597730 Value :: Option { value : None , .. } => None ,
598- other => return Err ( FromValueError :: TypeMismatch {
599- expected : "Option" ,
731+ other => return Err ( ConversionError :: TypeMismatch {
732+ expected : String :: from ( "Option" ) ,
600733 got : format ! ( "{:?}" , other) ,
601734 } ) ,
602735 } ;
0 commit comments