@@ -84,13 +84,84 @@ impl Display for Sizing {
8484}
8585
8686#[ derive( Clone , Eq , Debug ) ]
87- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) , serde( crate = "serde_crate" ) ) ]
8887pub struct Variant {
8988 pub name : VariantName ,
9089 pub tag : u8 ,
9190}
9291impl_strict_struct ! ( Variant , STRICT_TYPES_LIB ; name, tag) ;
9392
93+ #[ cfg( feature = "serde" ) ]
94+ // The manual serde implementation is needed due to `Variant` bein used as a key in maps (like enum
95+ // or union fields), and serde text implementations such as JSON can't serialize map keys if they
96+ // are not strings. This solves the issue, by putting string serialization of `Variant` for
97+ // human-readable serializers
98+ mod _serde {
99+ use std:: str:: FromStr ;
100+
101+ use serde_crate:: ser:: SerializeStruct ;
102+ use serde_crate:: { Deserialize , Deserializer , Serialize , Serializer } ;
103+
104+ use super :: * ;
105+
106+ impl Serialize for Variant {
107+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
108+ where S : Serializer {
109+ if serializer. is_human_readable ( ) {
110+ serializer. serialize_str ( & format ! ( "{}:{}" , self . name, self . tag) )
111+ } else {
112+ let mut s = serializer. serialize_struct ( "Variant" , 2 ) ?;
113+ s. serialize_field ( "name" , & self . name ) ?;
114+ s. serialize_field ( "tag" , & self . tag ) ?;
115+ s. end ( )
116+ }
117+ }
118+ }
119+
120+ impl < ' de > Deserialize < ' de > for Variant {
121+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
122+ where D : Deserializer < ' de > {
123+ if deserializer. is_human_readable ( ) {
124+ let s = String :: deserialize ( deserializer) ?;
125+ let mut split = s. split ( ':' ) ;
126+ let ( name, tag) = ( split. next ( ) , split. next ( ) ) ;
127+ if split. next ( ) . is_some ( ) {
128+ return Err ( serde:: de:: Error :: custom ( format ! (
129+ "Invalid variant format: '{}'. Expected 'name:tag'" ,
130+ s
131+ ) ) ) ;
132+ }
133+ match ( name, tag) {
134+ ( Some ( name) , Some ( tag) ) => {
135+ let name = VariantName :: from_str ( name) . map_err ( |e| {
136+ serde:: de:: Error :: custom ( format ! ( "Invalid variant name: {}" , e) )
137+ } ) ?;
138+ let tag = tag. parse :: < u8 > ( ) . map_err ( |e| {
139+ serde:: de:: Error :: custom ( format ! ( "Invalid variant tag: {}" , e) )
140+ } ) ?;
141+ Ok ( Variant { name, tag } )
142+ }
143+ _ => Err ( serde:: de:: Error :: custom ( format ! (
144+ "Invalid variant format: '{}'. Expected 'name:tag'" ,
145+ s
146+ ) ) ) ,
147+ }
148+ } else {
149+ #[ cfg_attr(
150+ feature = "serde" ,
151+ derive( Deserialize ) ,
152+ serde( crate = "serde_crate" , rename = "Variant" )
153+ ) ]
154+ struct VariantFields {
155+ name : VariantName ,
156+ tag : u8 ,
157+ }
158+ let VariantFields { name, tag } = VariantFields :: deserialize ( deserializer) ?;
159+ Ok ( Variant { name, tag } )
160+ }
161+ }
162+ }
163+ }
164+
94165impl Variant {
95166 pub fn named ( tag : u8 , name : VariantName ) -> Variant { Variant { name, tag } }
96167
@@ -138,3 +209,34 @@ impl Display for Variant {
138209 Ok ( ( ) )
139210 }
140211}
212+
213+ #[ cfg( test) ]
214+ mod test {
215+ #![ allow( unused) ]
216+
217+ use std:: io:: Cursor ;
218+
219+ use crate :: * ;
220+
221+ #[ cfg( feature = "serde" ) ]
222+ #[ test]
223+ fn variant_serde_roundtrip ( ) {
224+ let variant_orig = Variant :: strict_dumb ( ) ;
225+
226+ // CBOR
227+ let mut buf = Vec :: new ( ) ;
228+ ciborium:: into_writer ( & variant_orig, & mut buf) . unwrap ( ) ;
229+ let variant_post: Variant = ciborium:: from_reader ( Cursor :: new ( & buf) ) . unwrap ( ) ;
230+ assert_eq ! ( variant_orig, variant_post) ;
231+
232+ // JSON
233+ let variant_str = serde_json:: to_string ( & variant_orig) . unwrap ( ) ;
234+ let variant_post: Variant = serde_json:: from_str ( & variant_str) . unwrap ( ) ;
235+ assert_eq ! ( variant_orig, variant_post) ;
236+
237+ // YAML
238+ let variant_str = serde_yaml:: to_string ( & variant_orig) . unwrap ( ) ;
239+ let variant_post: Variant = serde_yaml:: from_str ( & variant_str) . unwrap ( ) ;
240+ assert_eq ! ( variant_orig, variant_post) ;
241+ }
242+ }
0 commit comments