Skip to content

Commit a4a430f

Browse files
committed
fix: Union serialization
1 parent c0fef92 commit a4a430f

File tree

4 files changed

+281
-111
lines changed

4 files changed

+281
-111
lines changed

avro/src/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,14 @@ pub enum Details {
274274
#[error("Could not find matching type in {schema:?} for {value:?}")]
275275
FindUnionVariant { schema: UnionSchema, value: Value },
276276

277+
#[error("Union index {index} out of bounds: {num_variants} in {schema:?} for {value:?}")]
278+
UnionIndexOutOfBounds {
279+
schema: UnionSchema,
280+
value: Value,
281+
index: usize,
282+
num_variants: usize,
283+
},
284+
277285
#[error("Union type should not be empty")]
278286
EmptyUnion,
279287

avro/src/serde/ser.rs

Lines changed: 43 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ pub struct SeqSerializer {
3131
items: Vec<Value>,
3232
}
3333

34-
pub struct SeqVariantSerializer<'a> {
34+
pub struct SeqVariantSerializer {
3535
index: u32,
36-
variant: &'a str,
3736
items: Vec<Value>,
3837
}
3938

@@ -46,9 +45,8 @@ pub struct StructSerializer {
4645
fields: Vec<(String, Value)>,
4746
}
4847

49-
pub struct StructVariantSerializer<'a> {
48+
pub struct StructVariantSerializer {
5049
index: u32,
51-
variant: &'a str,
5250
fields: Vec<(String, Value)>,
5351
}
5452

@@ -63,17 +61,13 @@ impl SeqSerializer {
6361
}
6462
}
6563

66-
impl<'a> SeqVariantSerializer<'a> {
67-
pub fn new(index: u32, variant: &'a str, len: Option<usize>) -> SeqVariantSerializer<'a> {
64+
impl SeqVariantSerializer {
65+
pub fn new(index: u32, len: Option<usize>) -> SeqVariantSerializer {
6866
let items = match len {
6967
Some(len) => Vec::with_capacity(len),
7068
None => Vec::new(),
7169
};
72-
SeqVariantSerializer {
73-
index,
74-
variant,
75-
items,
76-
}
70+
SeqVariantSerializer { index, items }
7771
}
7872
}
7973

@@ -96,26 +90,25 @@ impl StructSerializer {
9690
}
9791
}
9892

99-
impl<'a> StructVariantSerializer<'a> {
100-
pub fn new(index: u32, variant: &'a str, len: usize) -> StructVariantSerializer<'a> {
93+
impl StructVariantSerializer {
94+
pub fn new(index: u32, len: usize) -> StructVariantSerializer {
10195
StructVariantSerializer {
10296
index,
103-
variant,
10497
fields: Vec::with_capacity(len),
10598
}
10699
}
107100
}
108101

109-
impl<'b> ser::Serializer for &'b mut Serializer {
102+
impl ser::Serializer for &mut Serializer {
110103
type Ok = Value;
111104
type Error = Error;
112105
type SerializeSeq = SeqSerializer;
113106
type SerializeTuple = SeqSerializer;
114107
type SerializeTupleStruct = SeqSerializer;
115-
type SerializeTupleVariant = SeqVariantSerializer<'b>;
108+
type SerializeTupleVariant = SeqVariantSerializer;
116109
type SerializeMap = MapSerializer;
117110
type SerializeStruct = StructSerializer;
118-
type SerializeStructVariant = StructVariantSerializer<'b>;
111+
type SerializeStructVariant = StructVariantSerializer;
119112

120113
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
121114
Ok(Value::Boolean(v))
@@ -226,21 +219,15 @@ impl<'b> ser::Serializer for &'b mut Serializer {
226219

227220
fn serialize_newtype_variant<T>(
228221
self,
229-
_: &'static str,
222+
_name: &'static str,
230223
index: u32,
231-
variant: &'static str,
224+
_variant: &'static str,
232225
value: &T,
233226
) -> Result<Self::Ok, Self::Error>
234227
where
235228
T: Serialize + ?Sized,
236229
{
237-
Ok(Value::Record(vec![
238-
("type".to_owned(), Value::Enum(index, variant.to_owned())),
239-
(
240-
"value".to_owned(),
241-
Value::Union(index, Box::new(value.serialize(self)?)),
242-
),
243-
]))
230+
Ok(Value::Union(index, Box::new(value.serialize(self)?)))
244231
}
245232

246233
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
@@ -261,12 +248,12 @@ impl<'b> ser::Serializer for &'b mut Serializer {
261248

262249
fn serialize_tuple_variant(
263250
self,
264-
_: &'static str,
251+
_name: &'static str,
265252
index: u32,
266-
variant: &'static str,
253+
_variant: &'static str,
267254
len: usize,
268255
) -> Result<Self::SerializeTupleVariant, Self::Error> {
269-
Ok(SeqVariantSerializer::new(index, variant, Some(len)))
256+
Ok(SeqVariantSerializer::new(index, Some(len)))
270257
}
271258

272259
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
@@ -283,12 +270,12 @@ impl<'b> ser::Serializer for &'b mut Serializer {
283270

284271
fn serialize_struct_variant(
285272
self,
286-
_: &'static str,
273+
_name: &'static str,
287274
index: u32,
288-
variant: &'static str,
275+
_variant: &'static str,
289276
len: usize,
290277
) -> Result<Self::SerializeStructVariant, Self::Error> {
291-
Ok(StructVariantSerializer::new(index, variant, len))
278+
Ok(StructVariantSerializer::new(index, len))
292279
}
293280

294281
fn is_human_readable(&self) -> bool {
@@ -346,11 +333,11 @@ impl ser::SerializeTupleStruct for SeqSerializer {
346333
}
347334
}
348335

349-
impl ser::SerializeSeq for SeqVariantSerializer<'_> {
336+
impl ser::SerializeTupleVariant for SeqVariantSerializer {
350337
type Ok = Value;
351338
type Error = Error;
352339

353-
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
340+
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
354341
where
355342
T: Serialize + ?Sized,
356343
{
@@ -362,29 +349,7 @@ impl ser::SerializeSeq for SeqVariantSerializer<'_> {
362349
}
363350

364351
fn end(self) -> Result<Self::Ok, Self::Error> {
365-
Ok(Value::Record(vec![
366-
(
367-
"type".to_owned(),
368-
Value::Enum(self.index, self.variant.to_owned()),
369-
),
370-
("value".to_owned(), Value::Array(self.items)),
371-
]))
372-
}
373-
}
374-
375-
impl ser::SerializeTupleVariant for SeqVariantSerializer<'_> {
376-
type Ok = Value;
377-
type Error = Error;
378-
379-
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
380-
where
381-
T: Serialize + ?Sized,
382-
{
383-
ser::SerializeSeq::serialize_element(self, value)
384-
}
385-
386-
fn end(self) -> Result<Self::Ok, Self::Error> {
387-
ser::SerializeSeq::end(self)
352+
Ok(Value::Union(self.index, Box::new(Value::Array(self.items))))
388353
}
389354
}
390355

@@ -447,7 +412,7 @@ impl ser::SerializeStruct for StructSerializer {
447412
}
448413
}
449414

450-
impl ser::SerializeStructVariant for StructVariantSerializer<'_> {
415+
impl ser::SerializeStructVariant for StructVariantSerializer {
451416
type Ok = Value;
452417
type Error = Error;
453418

@@ -463,16 +428,10 @@ impl ser::SerializeStructVariant for StructVariantSerializer<'_> {
463428
}
464429

465430
fn end(self) -> Result<Self::Ok, Self::Error> {
466-
Ok(Value::Record(vec![
467-
(
468-
"type".to_owned(),
469-
Value::Enum(self.index, self.variant.to_owned()),
470-
),
471-
(
472-
"value".to_owned(),
473-
Value::Union(self.index, Box::new(Value::Record(self.fields))),
474-
),
475-
]))
431+
Ok(Value::Union(
432+
self.index,
433+
Box::new(Value::Record(self.fields)),
434+
))
476435
}
477436
}
478437

@@ -789,13 +748,7 @@ mod tests {
789748

790749
let expected = Value::Record(vec![(
791750
"a".to_owned(),
792-
Value::Record(vec![
793-
("type".to_owned(), Value::Enum(0, "Double".to_owned())),
794-
(
795-
"value".to_owned(),
796-
Value::Union(0, Box::new(Value::Double(64.0))),
797-
),
798-
]),
751+
Value::Union(0, Box::new(Value::Double(64.0))),
799752
)]);
800753

801754
assert_eq!(
@@ -851,19 +804,13 @@ mod tests {
851804
};
852805
let expected = Value::Record(vec![(
853806
"a".to_owned(),
854-
Value::Record(vec![
855-
("type".to_owned(), Value::Enum(0, "Val1".to_owned())),
856-
(
857-
"value".to_owned(),
858-
Value::Union(
859-
0,
860-
Box::new(Value::Record(vec![
861-
("x".to_owned(), Value::Float(1.0)),
862-
("y".to_owned(), Value::Float(2.0)),
863-
])),
864-
),
865-
),
866-
]),
807+
Value::Union(
808+
0,
809+
Box::new(Value::Record(vec![
810+
("x".to_owned(), Value::Float(1.0)),
811+
("y".to_owned(), Value::Float(2.0)),
812+
])),
813+
),
867814
)]);
868815

869816
assert_eq!(
@@ -965,17 +912,14 @@ mod tests {
965912

966913
let expected = Value::Record(vec![(
967914
"a".to_owned(),
968-
Value::Record(vec![
969-
("type".to_owned(), Value::Enum(1, "Val2".to_owned())),
970-
(
971-
"value".to_owned(),
972-
Value::Array(vec![
973-
Value::Union(1, Box::new(Value::Float(1.0))),
974-
Value::Union(1, Box::new(Value::Float(2.0))),
975-
Value::Union(1, Box::new(Value::Float(3.0))),
976-
]),
977-
),
978-
]),
915+
Value::Union(
916+
1,
917+
Box::new(Value::Array(vec![
918+
Value::Union(1, Box::new(Value::Float(1.0))),
919+
Value::Union(1, Box::new(Value::Float(2.0))),
920+
Value::Union(1, Box::new(Value::Float(3.0))),
921+
])),
922+
),
979923
)]);
980924

981925
assert_eq!(

avro/src/types.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,18 +1024,34 @@ impl Value {
10241024
enclosing_namespace: &Namespace,
10251025
field_default: &Option<JsonValue>,
10261026
) -> Result<Self, Error> {
1027-
let v = match self {
1028-
// Both are unions case.
1029-
Value::Union(_i, v) => *v,
1030-
// Reader is a union, but writer is not.
1031-
v => v,
1032-
};
1033-
let (i, inner) = schema
1034-
.find_schema_with_known_schemata(&v, Some(names), enclosing_namespace)
1035-
.ok_or_else(|| Details::FindUnionVariant {
1036-
schema: schema.clone(),
1037-
value: v.clone(),
1038-
})?;
1027+
let (i, inner, v) =
1028+
match self {
1029+
// Both are unions case.
1030+
Value::Union(i, v) => {
1031+
let index = i as usize;
1032+
let inner = schema.schemas.get(index).ok_or_else(|| {
1033+
Details::UnionIndexOutOfBounds {
1034+
schema: schema.clone(),
1035+
value: *v.clone(),
1036+
index,
1037+
num_variants: schema.schemas.len(),
1038+
}
1039+
})?;
1040+
1041+
(index, inner, *v)
1042+
}
1043+
// Reader is a union, but writer is not.
1044+
v => {
1045+
let (i, inner) = schema
1046+
.find_schema_with_known_schemata(&v, Some(names), enclosing_namespace)
1047+
.ok_or_else(|| Details::FindUnionVariant {
1048+
schema: schema.clone(),
1049+
value: v.clone(),
1050+
})?;
1051+
1052+
(i, inner, v)
1053+
}
1054+
};
10391055

10401056
Ok(Value::Union(
10411057
i as u32,

0 commit comments

Comments
 (0)