@@ -688,14 +688,70 @@ godot_test!(
688
688
assert!( v_m1. try_to_f64( ) . is_none( ) ) ;
689
689
assert!( v_m1. try_to_array( ) . is_none( ) ) ;
690
690
}
691
+
692
+ test_variant_bool {
693
+ let v_true = Variant :: from_bool( true ) ;
694
+ assert_eq!( v_true. get_type( ) , VariantType :: Bool ) ;
695
+
696
+ assert!( !v_true. is_nil( ) ) ;
697
+ assert_eq!( v_true. try_to_bool( ) , Some ( true ) ) ;
698
+ assert!( v_true. try_to_f64( ) . is_none( ) ) ;
699
+ assert!( v_true. try_to_array( ) . is_none( ) ) ;
700
+
701
+ let v_false = Variant :: from_bool( false ) ;
702
+ assert_eq!( v_false. get_type( ) , VariantType :: Bool ) ;
703
+
704
+ assert!( !v_false. is_nil( ) ) ;
705
+ assert_eq!( v_false. try_to_bool( ) , Some ( false ) ) ;
706
+ assert!( v_false. try_to_f64( ) . is_none( ) ) ;
707
+ assert!( v_false. try_to_array( ) . is_none( ) ) ;
708
+
709
+ }
691
710
) ;
692
711
693
712
/// Types that can be converted to a `Variant`.
713
+ ///
714
+ /// ## Wrappers and collections
715
+ ///
716
+ /// Implementations are provided for a few common Rust wrappers and collections:
717
+ ///
718
+ /// - `Option<T>` is unwrapped to inner value, or `Nil` if `None`
719
+ /// - `Result<T, E>` is represented as an externally tagged `Dictionary` (see below).
720
+ /// - `PhantomData<T>` is represented as `Nil`.
721
+ /// - `&[T]` and `Vec<T>` are represented as `VariantArray`s. `FromVariant` is only implemented
722
+ /// for `Vec<T>`.
723
+ ///
724
+ /// ## Deriving `ToVariant`
725
+ ///
726
+ /// The derive macro does the following mapping between Rust structures and Godot types:
727
+ ///
728
+ /// - `Newtype(inner)` is unwrapped to `inner`
729
+ /// - `Tuple(a, b, c)` is represented as a `VariantArray` (`[a, b, c]`)
730
+ /// - `Struct { a, b, c }` is represented as a `Dictionary` (`{ "a": a, "b": b, "c": c }`)
731
+ /// - `Unit` is represented as an empty `Dictionary` (`{}`)
732
+ /// - `Enum::Variant(a, b, c)` is represented as an externally tagged `Dictionary`
733
+ /// (`{ "Variant": [a, b, c] }`)
694
734
pub trait ToVariant {
695
735
fn to_variant ( & self ) -> Variant ;
696
736
}
697
737
698
738
/// Types that can be converted from a `Variant`.
739
+ ///
740
+ /// ## `Option<T>` and `MaybeNot<T>`
741
+ ///
742
+ /// `Option<T>` requires the Variant to be `T` or `Nil`, in that order. For looser semantics,
743
+ /// use `MaybeNot<T>`, which will catch all variant values that are not `T` as well.
744
+ ///
745
+ /// ## `Vec<T>`
746
+ ///
747
+ /// The `FromVariant` implementation for `Vec<T>` only allow homogeneous arrays. If you want to
748
+ /// manually handle potentially heterogeneous values e.g. for error reporting, use `VariantArray`
749
+ /// directly or compose with an appropriate wrapper: `Vec<Option<T>>` or `Vec<MaybeNot<T>>`.
750
+ ///
751
+ /// ## Deriving `FromVariant`
752
+ ///
753
+ /// The derive macro provides implementation consistent with derived `ToVariant`. See `ToVariant`
754
+ /// for detailed documentation.
699
755
pub trait FromVariant : Sized {
700
756
fn from_variant ( variant : & Variant ) -> Option < Self > ;
701
757
}
@@ -884,4 +940,221 @@ impl FromVariant for Variant {
884
940
fn from_variant ( variant : & Variant ) -> Option < Self > {
885
941
Some ( variant. clone ( ) )
886
942
}
887
- }
943
+ }
944
+
945
+ impl < T > ToVariant for std:: marker:: PhantomData < T > {
946
+ fn to_variant ( & self ) -> Variant {
947
+ Variant :: new ( )
948
+ }
949
+ }
950
+
951
+ impl < T > FromVariant for std:: marker:: PhantomData < T > {
952
+ fn from_variant ( variant : & Variant ) -> Option < Self > {
953
+ if variant. is_nil ( ) {
954
+ Some ( std:: marker:: PhantomData )
955
+ }
956
+ else {
957
+ None
958
+ }
959
+ }
960
+ }
961
+
962
+ impl < T : ToVariant > ToVariant for Option < T > {
963
+ fn to_variant ( & self ) -> Variant {
964
+ match & self {
965
+ Some ( thing) => thing. to_variant ( ) ,
966
+ None => Variant :: new ( ) ,
967
+ }
968
+ }
969
+ }
970
+
971
+ impl < T : FromVariant > FromVariant for Option < T > {
972
+ fn from_variant ( variant : & Variant ) -> Option < Self > {
973
+ T :: from_variant ( variant) . map ( Some ) . or_else ( || {
974
+ if variant. is_nil ( ) {
975
+ Some ( None )
976
+ }
977
+ else {
978
+ None
979
+ }
980
+ } )
981
+ }
982
+ }
983
+
984
+ /// Wrapper type around a `FromVariant` result that may not be a success
985
+ #[ derive( Clone , Debug ) ]
986
+ pub struct MaybeNot < T > ( Result < T , Variant > ) ;
987
+
988
+ impl < T : FromVariant > FromVariant for MaybeNot < T > {
989
+ fn from_variant ( variant : & Variant ) -> Option < Self > {
990
+ Some ( MaybeNot ( T :: from_variant ( variant) . ok_or_else ( || variant. clone ( ) ) ) )
991
+ }
992
+ }
993
+
994
+ impl < T > MaybeNot < T > {
995
+ pub fn into_result ( self ) -> Result < T , Variant > {
996
+ self . 0
997
+ }
998
+
999
+ pub fn as_ref ( & self ) -> Result < & T , & Variant > {
1000
+ self . 0 . as_ref ( )
1001
+ }
1002
+
1003
+ pub fn as_mut ( & mut self ) -> Result < & mut T , & mut Variant > {
1004
+ self . 0 . as_mut ( )
1005
+ }
1006
+
1007
+ pub fn cloned ( & self ) -> Result < T , Variant >
1008
+ where
1009
+ T : Clone ,
1010
+ {
1011
+ self . 0 . clone ( )
1012
+ }
1013
+
1014
+ pub fn ok ( self ) -> Option < T > {
1015
+ self . 0 . ok ( )
1016
+ }
1017
+ }
1018
+
1019
+ impl < T : ToVariant , E : ToVariant > ToVariant for Result < T , E > {
1020
+ fn to_variant ( & self ) -> Variant {
1021
+ let mut dict = Dictionary :: new ( ) ;
1022
+ match & self {
1023
+ Ok ( val) => dict. set ( & "Ok" . into ( ) , & val. to_variant ( ) ) ,
1024
+ Err ( err) => dict. set ( & "Err" . into ( ) , & err. to_variant ( ) ) ,
1025
+ }
1026
+ dict. to_variant ( )
1027
+ }
1028
+ }
1029
+
1030
+ impl < T : FromVariant , E : FromVariant > FromVariant for Result < T , E > {
1031
+ fn from_variant ( variant : & Variant ) -> Option < Self > {
1032
+ let dict = variant. try_to_dictionary ( ) ?;
1033
+ if dict. len ( ) != 1 {
1034
+ return None ;
1035
+ }
1036
+ let keys = dict. keys ( ) ;
1037
+ let key_variant = keys. get_ref ( 0 ) ;
1038
+ let key = key_variant. try_to_string ( ) ?;
1039
+ match key. as_str ( ) {
1040
+ "Ok" => {
1041
+ let val = T :: from_variant ( dict. get_ref ( key_variant) ) ?;
1042
+ Some ( Ok ( val) )
1043
+ } ,
1044
+ "Err" => {
1045
+ let err = E :: from_variant ( dict. get_ref ( key_variant) ) ?;
1046
+ Some ( Err ( err) )
1047
+ } ,
1048
+ _ => None ,
1049
+ }
1050
+ }
1051
+ }
1052
+
1053
+ impl < T : ToVariant > ToVariant for & [ T ] {
1054
+ fn to_variant ( & self ) -> Variant {
1055
+ let mut array = VariantArray :: new ( ) ;
1056
+ for val in self . iter ( ) {
1057
+ // there is no real way to avoid CoW allocations right now, as ptrw isn't exposed
1058
+ array. push ( & val. to_variant ( ) ) ;
1059
+ }
1060
+ array. to_variant ( )
1061
+ }
1062
+ }
1063
+
1064
+ impl < T : ToVariant > ToVariant for Vec < T > {
1065
+ fn to_variant ( & self ) -> Variant {
1066
+ self . as_slice ( ) . to_variant ( )
1067
+ }
1068
+ }
1069
+
1070
+ impl < T : FromVariant > FromVariant for Vec < T > {
1071
+ fn from_variant ( variant : & Variant ) -> Option < Self > {
1072
+ use std:: convert:: TryInto ;
1073
+
1074
+ let arr = variant. try_to_array ( ) ?;
1075
+ let len: usize = arr. len ( ) . try_into ( ) . ok ( ) ?;
1076
+ let mut vec = Vec :: with_capacity ( len) ;
1077
+ for idx in 0 ..len as i32 {
1078
+ let item = T :: from_variant ( arr. get_ref ( idx) ) ?;
1079
+ vec. push ( item) ;
1080
+ }
1081
+ Some ( vec)
1082
+ }
1083
+ }
1084
+
1085
+ godot_test ! (
1086
+ test_variant_option {
1087
+ use std:: marker:: PhantomData ;
1088
+
1089
+ let variant = Some ( 42 as i64 ) . to_variant( ) ;
1090
+ assert_eq!( Some ( 42 ) , variant. try_to_i64( ) ) ;
1091
+
1092
+ let variant = Option :: <bool >:: None . to_variant( ) ;
1093
+ assert!( variant. is_nil( ) ) ;
1094
+
1095
+ let variant = Variant :: new( ) ;
1096
+ assert_eq!( Some ( None ) , Option :: <i64 >:: from_variant( & variant) ) ;
1097
+ assert_eq!( Some ( None ) , Option :: <bool >:: from_variant( & variant) ) ;
1098
+ assert_eq!( Some ( None ) , Option :: <String >:: from_variant( & variant) ) ;
1099
+
1100
+ let variant = Variant :: from_i64( 42 ) ;
1101
+ assert_eq!( Some ( Some ( 42 ) ) , Option :: <i64 >:: from_variant( & variant) ) ;
1102
+ assert_eq!( None , Option :: <bool >:: from_variant( & variant) ) ;
1103
+ assert_eq!( None , Option :: <String >:: from_variant( & variant) ) ;
1104
+
1105
+ let variant = Variant :: new( ) ;
1106
+ assert_eq!( Some ( Some ( ( ) ) ) , Option :: <( ) >:: from_variant( & variant) ) ;
1107
+ assert_eq!( Some ( Some ( PhantomData ) ) , Option :: <PhantomData <* const u8 >>:: from_variant( & variant) ) ;
1108
+
1109
+ let variant = Variant :: from_i64( 42 ) ;
1110
+ assert_eq!( None , Option :: <PhantomData <* const u8 >>:: from_variant( & variant) ) ;
1111
+ }
1112
+
1113
+ test_variant_result {
1114
+ let variant = Result :: <i64 , ( ) >:: Ok ( 42 as i64 ) . to_variant( ) ;
1115
+ let dict = variant. try_to_dictionary( ) . expect( "should be dic" ) ;
1116
+ assert_eq!( Some ( 42 ) , dict. get_ref( & "Ok" . into( ) ) . try_to_i64( ) ) ;
1117
+
1118
+ let variant = Result :: <( ) , i64 >:: Err ( 54 as i64 ) . to_variant( ) ;
1119
+ let dict = variant. try_to_dictionary( ) . expect( "should be dic" ) ;
1120
+ assert_eq!( Some ( 54 ) , dict. get_ref( & "Err" . into( ) ) . try_to_i64( ) ) ;
1121
+
1122
+ let variant = Variant :: from_bool( true ) ;
1123
+ assert_eq!( None , Result :: <( ) , i64 >:: from_variant( & variant) ) ;
1124
+
1125
+ let mut dict = Dictionary :: new( ) ;
1126
+ dict. set( & "Ok" . into( ) , & Variant :: from_i64( 42 ) ) ;
1127
+ assert_eq!( Some ( Ok ( 42 ) ) , Result :: <i64 , i64 >:: from_variant( & dict. to_variant( ) ) ) ;
1128
+
1129
+ let mut dict = Dictionary :: new( ) ;
1130
+ dict. set( & "Err" . into( ) , & Variant :: from_i64( 54 ) ) ;
1131
+ assert_eq!( Some ( Err ( 54 ) ) , Result :: <i64 , i64 >:: from_variant( & dict. to_variant( ) ) ) ;
1132
+ }
1133
+
1134
+ test_to_variant_iter {
1135
+ let slice: & [ i64 ] = & [ 0 , 1 , 2 , 3 , 4 ] ;
1136
+ let variant = slice. to_variant( ) ;
1137
+ let array = variant. try_to_array( ) . expect( "should be array" ) ;
1138
+ assert_eq!( 5 , array. len( ) ) ;
1139
+ for i in 0 ..5 {
1140
+ assert_eq!( Some ( i) , array. get_ref( i as i32 ) . try_to_i64( ) ) ;
1141
+ }
1142
+
1143
+ let vec = Vec :: <i64 >:: from_variant( & variant) . expect( "should succeed" ) ;
1144
+ assert_eq!( slice, vec. as_slice( ) ) ;
1145
+
1146
+ let mut het_array = VariantArray :: new( ) ;
1147
+ het_array. push( & Variant :: from_i64( 42 ) ) ;
1148
+ het_array. push( & Variant :: new( ) ) ;
1149
+ assert_eq!( None , Vec :: <i64 >:: from_variant( & het_array. to_variant( ) ) ) ;
1150
+ assert_eq!( Some ( vec![ Some ( 42 ) , None ] ) , Vec :: <Option <i64 >>:: from_variant( & het_array. to_variant( ) ) ) ;
1151
+
1152
+ het_array. push( & f64 :: to_variant( & 54.0 ) ) ;
1153
+ assert_eq!( None , Vec :: <Option <i64 >>:: from_variant( & het_array. to_variant( ) ) ) ;
1154
+ let vec_maybe = Vec :: <MaybeNot <i64 >>:: from_variant( & het_array. to_variant( ) ) . expect( "should succeed" ) ;
1155
+ assert_eq!( 3 , vec_maybe. len( ) ) ;
1156
+ assert_eq!( Some ( & 42 ) , vec_maybe[ 0 ] . as_ref( ) . ok( ) ) ;
1157
+ assert_eq!( Some ( & Variant :: new( ) ) , vec_maybe[ 1 ] . as_ref( ) . err( ) ) ;
1158
+ assert_eq!( Some ( & f64 :: to_variant( & 54.0 ) ) , vec_maybe[ 2 ] . as_ref( ) . err( ) ) ;
1159
+ }
1160
+ ) ;
0 commit comments