@@ -6,7 +6,7 @@ use std::u8;
66use failure:: Error ;
77use serde_json:: Value as JsonValue ;
88
9- use crate :: schema:: { RecordField , Schema , SchemaKind , UnionSchema } ;
9+ use crate :: schema:: { RecordField , Schema , UnionSchema } ;
1010
1111/// Describes errors happened while performing schema resolution on Avro data.
1212#[ derive( Fail , Debug ) ]
@@ -54,7 +54,7 @@ pub enum Value {
5454 /// reading values.
5555 Enum ( i32 , String ) ,
5656 /// An `union` Avro value.
57- Union ( Box < Value > ) ,
57+ Union ( usize , Box < Value > ) ,
5858 /// An `array` Avro value.
5959 Array ( Vec < Value > ) ,
6060 /// A `map` Avro value.
@@ -121,11 +121,18 @@ where
121121 T : ToAvro ,
122122{
123123 fn avro ( self ) -> Value {
124- let v = match self {
125- Some ( v) => T :: avro ( v) ,
126- None => Value :: Null ,
124+ let ( i , v ) = match self {
125+ Some ( v) => ( 1 , T :: avro ( v) ) ,
126+ None => ( 0 , Value :: Null ) ,
127127 } ;
128- Value :: Union ( Box :: new ( v) )
128+ /*
129+ * https://avro.apache.org/docs/current/spec.html#Unions
130+ * | Thus, for unions containing "null", the "null" is usually listed first, since the default value of such unions is typically null
131+ *
132+ * Although that is not a guarantee (that the schema will be defined as ["null", {"type": ...}]: null-first),
133+ * this can be used as a guideline to choose variant-index=0 for the None value.
134+ */
135+ Value :: Union ( i, Box :: new ( v) )
129136 }
130137}
131138
@@ -271,8 +278,14 @@ impl Value {
271278 . map ( |ref symbol| symbol == & s)
272279 . unwrap_or ( false ) ,
273280 // (&Value::Union(None), &Schema::Union(_)) => true,
274- ( & Value :: Union ( ref value) , & Schema :: Union ( ref inner) ) => {
275- inner. find_schema ( value) . is_some ( )
281+ ( & Value :: Union ( variant_idx, ref variant_value) , & Schema :: Union ( ref inner) ) => {
282+ match inner. variant_schema ( variant_idx) {
283+ None =>
284+ // Is an invalid variant-index a schema validation error or a failure worth panicking?
285+ false ,
286+ Some ( variant_schema) =>
287+ variant_value. validate ( variant_schema) ,
288+ }
276289 } ,
277290 ( & Value :: Array ( ref items) , & Schema :: Array ( ref inner) ) => {
278291 items. iter ( ) . all ( |item| item. validate ( inner) )
@@ -297,8 +310,14 @@ impl Value {
297310 /// See [Schema Resolution](https://avro.apache.org/docs/current/spec.html#Schema+Resolution)
298311 /// in the Avro specification for the full set of rules of schema
299312 /// resolution.
300- pub fn resolve ( mut self , schema : & Schema ) -> Result < Self , Error > {
301- // Check if this schema is a union, and if the reader schema is not.
313+ pub fn resolve ( /*mut */ self , schema : & Schema ) -> Result < Self , Error > {
314+ /*
315+ // RGafiyatullin:
316+ // I am convinced that a VariantValue does not conform UnionSchema(vec![ VariantSchema ]) under any circumstances;
317+ // Union(0, VariantValue) on the other hand does.
318+ // Therefore there is no need to extract inner-value of a Union
319+ // ---
320+ // // Check if this schema is a union, and if the reader schema is not.
302321 if SchemaKind::from(&self) == SchemaKind::Union
303322 && SchemaKind::from(schema) != SchemaKind::Union
304323 {
@@ -309,6 +328,7 @@ impl Value {
309328 };
310329 self = v;
311330 }
331+ */
312332 match * schema {
313333 Schema :: Null => self . resolve_null ( ) ,
314334 Schema :: Boolean => self . resolve_boolean ( ) ,
@@ -462,17 +482,22 @@ impl Value {
462482 }
463483
464484 fn resolve_union ( self , schema : & UnionSchema ) -> Result < Self , Error > {
465- let v = match self {
466- // Both are unions case.
467- Value :: Union ( v) => * v,
468- // Reader is a union, but writer is not.
469- v => v,
470- } ;
471- // Find the first match in the reader schema.
472- let ( _, inner) = schema
473- . find_schema ( & v)
474- . ok_or_else ( || SchemaResolutionError :: new ( "Could not find matching type in union" ) ) ?;
475- v. resolve ( inner)
485+ match self {
486+ Value :: Union ( variant_index, v) => {
487+ let variant_value = * v;
488+ let variant_schema =
489+ schema
490+ . variant_schema ( variant_index)
491+ . ok_or_else (
492+ || SchemaResolutionError :: new (
493+ format ! ( "Invalid variant index: {:?}" , variant_index) )
494+ ) ?;
495+ variant_value. resolve ( variant_schema)
496+ } ,
497+ _ =>
498+ Err ( SchemaResolutionError :: new (
499+ "Attempt to resolve schema for non-union type via UnionSchema" ) ) ?
500+ }
476501 }
477502
478503 fn resolve_array ( self , schema : & Schema ) -> Result < Self , Error > {
@@ -570,22 +595,22 @@ mod tests {
570595 ( Value :: Int ( 42 ) , Schema :: Int , true ) ,
571596 ( Value :: Int ( 42 ) , Schema :: Boolean , false ) ,
572597 (
573- Value :: Union ( Box :: new( Value :: Null ) ) ,
598+ Value :: Union ( 0 , Box :: new( Value :: Null ) ) ,
574599 Schema :: Union ( UnionSchema :: new( vec![ Schema :: Null , Schema :: Int ] ) . unwrap( ) ) ,
575600 true ,
576601 ) ,
577602 (
578- Value :: Union ( Box :: new( Value :: Int ( 42 ) ) ) ,
603+ Value :: Union ( 1 , Box :: new( Value :: Int ( 42 ) ) ) ,
579604 Schema :: Union ( UnionSchema :: new( vec![ Schema :: Null , Schema :: Int ] ) . unwrap( ) ) ,
580605 true ,
581606 ) ,
582607 (
583- Value :: Union ( Box :: new( Value :: Null ) ) ,
608+ Value :: Union ( 0 , Box :: new( Value :: Null ) ) ,
584609 Schema :: Union ( UnionSchema :: new( vec![ Schema :: Double , Schema :: Int ] ) . unwrap( ) ) ,
585610 false ,
586611 ) ,
587612 (
588- Value :: Union ( Box :: new( Value :: Int ( 42 ) ) ) ,
613+ Value :: Union ( 3 , Box :: new( Value :: Int ( 42 ) ) ) ,
589614 Schema :: Union (
590615 UnionSchema :: new( vec![
591616 Schema :: Null ,
0 commit comments