@@ -5,14 +5,22 @@ use crate::{define_rb_intern, err, error, not_implemented};
5
5
use magnus:: exception:: type_error;
6
6
use magnus:: rb_sys:: AsRawValue ;
7
7
use magnus:: value:: { IntoId , Lazy , ReprValue } ;
8
- use magnus:: { prelude:: * , value, Error , IntoValue , RArray , RClass , RHash , RString , Ruby , Value } ;
8
+ use magnus:: {
9
+ prelude:: * , try_convert, value, Error , IntoValue , RArray , RClass , RHash , RString , Ruby , Value ,
10
+ } ;
9
11
use wasmtime:: component:: { Type , Val } ;
10
12
11
13
define_rb_intern ! (
14
+ // For Component::Result
12
15
OK => "ok" ,
13
16
ERROR => "error" ,
14
17
IS_ERROR => "error?" ,
15
18
IS_OK => "ok?" ,
19
+
20
+ // For Component::Variant
21
+ NEW => "new" ,
22
+ NAME => "name" ,
23
+ VALUE => "value" ,
16
24
) ;
17
25
18
26
pub ( crate ) fn component_val_to_rb ( val : Val , _store : & StoreContextValue ) -> Result < Value , Error > {
@@ -54,7 +62,18 @@ pub(crate) fn component_val_to_rb(val: Val, _store: &StoreContextValue) -> Resul
54
62
}
55
63
Ok ( array. into_value ( ) )
56
64
}
57
- Val :: Variant ( _kind, _val) => not_implemented ! ( "Variant not implemented" ) ,
65
+ Val :: Variant ( kind, val) => {
66
+ let ruby = Ruby :: get ( ) . unwrap ( ) ;
67
+ let payload = match val {
68
+ Some ( val) => component_val_to_rb ( * val, _store) ?,
69
+ None => ruby. qnil ( ) . into_value ( ) ,
70
+ } ;
71
+
72
+ variant_class ( & ruby) . funcall (
73
+ NEW . into_id_with ( & ruby) ,
74
+ ( kind. into_value_with ( & ruby) , payload) ,
75
+ )
76
+ }
58
77
Val :: Enum ( kind) => Ok ( kind. as_str ( ) . into_value ( ) ) ,
59
78
Val :: Option ( val) => match val {
60
79
Some ( val) => Ok ( component_val_to_rb ( * val, _store) ?) ,
@@ -72,7 +91,7 @@ pub(crate) fn component_val_to_rb(val: Val, _store: &StoreContextValue) -> Resul
72
91
} ;
73
92
result_class ( & ruby) . funcall ( ruby_method, ( ruby_argument, ) )
74
93
}
75
- Val :: Flags ( _vec ) => not_implemented ! ( "Flags not implemented" ) ,
94
+ Val :: Flags ( vec ) => Ok ( vec . into_value ( ) ) ,
76
95
Val :: Resource ( _resource_any) => not_implemented ! ( "Resource not implemented" ) ,
77
96
}
78
97
}
@@ -168,8 +187,46 @@ pub(crate) fn rb_to_component_val(
168
187
169
188
Ok ( Val :: Tuple ( vals) )
170
189
}
171
- Type :: Variant ( _variant) => not_implemented ! ( "Variant not implemented" ) ,
172
- Type :: Enum ( _enum) => not_implemented ! ( "Enum not implementend" ) ,
190
+ Type :: Variant ( variant) => {
191
+ let ruby = Ruby :: get ( ) . unwrap ( ) ;
192
+
193
+ let name: RString = value. funcall ( NAME . into_id_with ( & ruby) , ( ) ) ?;
194
+ let name = name. to_string ( ) ?;
195
+
196
+ let case = variant
197
+ . cases ( )
198
+ . find ( |case| case. name == name. as_str ( ) )
199
+ . ok_or_else ( || {
200
+ error ! (
201
+ "invalid variant case \" {}\" , valid cases: {:?}" ,
202
+ name,
203
+ RArray :: from_iter( variant. cases( ) . map( |c| c. name) )
204
+ )
205
+ } ) ?;
206
+
207
+ let payload_rb: Value = value. funcall ( VALUE . into_id_with ( & ruby) , ( ) ) ?;
208
+ let payload_val = match ( & case. ty , payload_rb. is_nil ( ) ) {
209
+ ( Some ( ty) , _) => rb_to_component_val ( payload_rb, _store, ty)
210
+ . map ( |val| Some ( Box :: new ( val) ) )
211
+ . map_err ( |e| e. append ( format ! ( " (variant value for \" {}\" )" , & name) ) ) ,
212
+
213
+ // case doesn't have payload and Variant#value *is nil*
214
+ ( None , true ) => Ok ( None ) ,
215
+
216
+ // case doesn't have payload and Variant#value *is not nil*
217
+ ( None , false ) => err ! (
218
+ "expected no value for variant case \" {}\" , got {}" ,
219
+ & name,
220
+ payload_rb. inspect( )
221
+ ) ,
222
+ } ?;
223
+
224
+ Ok ( Val :: Variant ( name, payload_val) )
225
+ }
226
+ Type :: Enum ( _) => {
227
+ let rstring = RString :: try_convert ( value) ?;
228
+ rstring. to_string ( ) . map ( Val :: Enum )
229
+ }
173
230
Type :: Option ( option_type) => {
174
231
if value. is_nil ( ) {
175
232
Ok ( Val :: Option ( None ) )
@@ -220,7 +277,7 @@ pub(crate) fn rb_to_component_val(
220
277
}
221
278
}
222
279
}
223
- Type :: Flags ( _flags ) => not_implemented ! ( " Flags not implemented" ) ,
280
+ Type :: Flags ( _ ) => Vec :: < String > :: try_convert ( value ) . map ( Val :: Flags ) ,
224
281
Type :: Own ( _resource_type) => not_implemented ! ( "Resource not implemented" ) ,
225
282
Type :: Borrow ( _resource_type) => not_implemented ! ( "Resource not implemented" ) ,
226
283
}
@@ -232,6 +289,12 @@ fn result_class(ruby: &Ruby) -> RClass {
232
289
ruby. get_inner ( & RESULT_CLASS )
233
290
}
234
291
292
+ fn variant_class ( ruby : & Ruby ) -> RClass {
293
+ static VARIANT_CLASS : Lazy < RClass > =
294
+ Lazy :: new ( |ruby| component_namespace ( ruby) . const_get ( "Variant" ) . unwrap ( ) ) ;
295
+ ruby. get_inner ( & VARIANT_CLASS )
296
+ }
297
+
235
298
pub fn init ( ruby : & Ruby ) -> Result < ( ) , Error > {
236
299
// Warm up
237
300
let _ = result_class ( ruby) ;
@@ -240,5 +303,10 @@ pub fn init(ruby: &Ruby) -> Result<(), Error> {
240
303
let _ = IS_ERROR ;
241
304
let _ = IS_OK ;
242
305
306
+ let _ = result_class ( ruby) ;
307
+ let _ = NEW ;
308
+ let _ = NAME ;
309
+ let _ = VALUE ;
310
+
243
311
Ok ( ( ) )
244
312
}
0 commit comments