Skip to main content

apache_avro/serde/ser_schema/
mod.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Logic for serde-compatible schema-aware serialization which writes directly to a writer.
19
20mod block;
21mod record;
22mod tuple;
23mod union;
24
25use std::{borrow::Borrow, collections::HashMap, io::Write};
26
27use block::BlockSerializer;
28use record::RecordSerializer;
29use serde::{Serialize, Serializer, ser::SerializeMap};
30use serde_json::Value::Bool;
31use tuple::{ManyTupleSerializer, TupleSerializer};
32use union::UnionSerializer;
33
34use crate::{
35    Error, Schema,
36    error::Details,
37    schema::{
38        DecimalSchema, InnerDecimalSchema, MapSchema, Name, RecordSchema, SchemaKind, UnionSchema,
39        UuidSchema,
40    },
41    util::{zig_i32, zig_i64},
42};
43
44pub struct Config<'s, S: Borrow<Schema>> {
45    /// Any references in the schema will be resolved using this map.
46    ///
47    /// This map is not allowed to contain any [`Schema::Ref`], the serializer is allowed to panic
48    /// in that case.
49    pub names: &'s HashMap<Name, S>,
50    /// At what block size to start a new block (for arrays and maps).
51    ///
52    /// This is a minimum value, the block size will always be larger than this except for the last
53    /// block.
54    ///
55    /// When set to `None` all values will be written in a single block. This can be faster as no
56    /// intermediate buffer is used, but seeking through written data will be slower.
57    pub target_block_size: Option<usize>,
58    /// Should `Serialize` implementations pick a human-readable format.
59    ///
60    /// It is recommended to set this to `false` as it results in compacter output.
61    pub human_readable: bool,
62}
63
64impl<'s, S: Borrow<Schema>> Config<'s, S> {
65    /// Get the schema for this name.
66    fn get_schema(&self, name: &Name) -> Result<&'s Schema, Error> {
67        self.names
68            .get(name)
69            .map(Borrow::borrow)
70            .ok_or_else(|| Details::SchemaResolutionError(name.clone()).into())
71    }
72}
73
74// This needs to be implemented manually as the derive puts a bound on `S`
75// which is unnecessary as a reference is always Copy.
76impl<'s, S: Borrow<Schema>> Copy for Config<'s, S> {}
77impl<'s, S: Borrow<Schema>> Clone for Config<'s, S> {
78    fn clone(&self) -> Self {
79        *self
80    }
81}
82
83pub struct SchemaAwareSerializer<'s, 'w, W: Write, S: Borrow<Schema>> {
84    writer: &'w mut W,
85    /// The schema of the data being serialized.
86    ///
87    /// This schema is guaranteed to not be a [`Schema::Ref`].
88    schema: &'s Schema,
89    config: Config<'s, S>,
90}
91
92impl<'s, 'w, W: Write, S: Borrow<Schema>> SchemaAwareSerializer<'s, 'w, W, S> {
93    pub fn new(
94        writer: &'w mut W,
95        schema: &'s Schema,
96        config: Config<'s, S>,
97    ) -> Result<Self, Error> {
98        let schema = if let Schema::Ref { name } = schema {
99            config.get_schema(name)?
100        } else {
101            schema
102        };
103        Ok(Self {
104            writer,
105            schema,
106            config,
107        })
108    }
109
110    fn error(&self, ty: &'static str, error: impl Into<String>) -> Error {
111        Error::new(Details::SerializeValueWithSchema {
112            value_type: ty,
113            value: error.into(),
114            schema: self.schema.clone(),
115        })
116    }
117
118    /// Create a new serializer with the existing writer and config.
119    ///
120    /// This will resolve the schema if it is a reference.
121    fn with_different_schema(mut self, schema: &'s Schema) -> Result<Self, Error> {
122        self.schema = if let Schema::Ref { name } = schema {
123            self.config.get_schema(name)?
124        } else {
125            schema
126        };
127        Ok(self)
128    }
129
130    /// Get the schema at the given index of the union, resolving references.
131    fn get_resolved_union_variant(
132        &self,
133        union: &'s UnionSchema,
134        index: u32,
135    ) -> Result<&'s Schema, Error> {
136        match union.get_variant(index as usize)? {
137            Schema::Ref { name } => self.config.get_schema(name),
138            schema => Ok(schema),
139        }
140    }
141
142    /// Write an integer to the writer.
143    ///
144    /// This will check that the current schema is [`Schema::Int`] or a logical type based on that.
145    /// This also handles [`Schema::Union`].
146    fn checked_write_int(self, original_ty: &'static str, v: i32) -> Result<usize, Error> {
147        match self.schema {
148            Schema::Int | Schema::Date | Schema::TimeMillis => zig_i32(v, self.writer),
149            Schema::Union(union) => UnionSerializer::new(self.writer, union, self.config)
150                .checked_write_int(original_ty, v),
151            _ => Err(self.error(
152                original_ty,
153                "Expected Schema::Int | Schema::Date | Schema::TimeMillis",
154            )),
155        }
156    }
157
158    /// Write a long to the writer.
159    ///
160    /// This will check that the current schema is [`Schema::Long`] or a logical type based on that.
161    /// This also handles [`Schema::Union`].
162    fn checked_write_long(self, original_ty: &'static str, v: i64) -> Result<usize, Error> {
163        match self.schema {
164            Schema::Long | Schema::TimeMicros | Schema::TimestampMillis | Schema::TimestampMicros
165            | Schema::TimestampNanos | Schema::LocalTimestampMillis | Schema::LocalTimestampMicros
166            | Schema::LocalTimestampNanos => {
167                zig_i64(v, self.writer)
168            }
169            Schema::Union(union) => UnionSerializer::new(self.writer, union, self.config).checked_write_long(original_ty, v),
170            _ => {
171                Err(self.error(original_ty, "Expected Schema::Long | Schema::TimeMicros | Schema::{,Local}Timestamp{Millis,Micros,Nanos}"))
172            }
173        }
174    }
175
176    /// Write bytes to the writer with preceding length header.
177    ///
178    /// This does not check the current schema.
179    fn write_bytes_with_len(&mut self, bytes: &[u8]) -> Result<usize, Error> {
180        let mut bytes_written = 0;
181        bytes_written += zig_i64(bytes.len() as i64, &mut *self.writer)?;
182        bytes_written += self.write_bytes(bytes)?;
183        Ok(bytes_written)
184    }
185
186    /// Write bytes to the writer.
187    ///
188    /// This does not check the current schema.
189    fn write_bytes(&mut self, bytes: &[u8]) -> Result<usize, Error> {
190        self.writer.write_all(bytes).map_err(Details::WriteBytes)?;
191        Ok(bytes.len())
192    }
193
194    /// Write an array of `n` bytes to the writer.
195    ///
196    /// This does not check the current schema.
197    fn write_array<const N: usize>(&mut self, bytes: [u8; N]) -> Result<usize, Error> {
198        self.write_bytes(&bytes)?;
199        Ok(N)
200    }
201}
202
203/// Indicate to the serializer that a record field default is being serialized.
204///
205/// This is needed because the serializer takes a `&'static str` for the enum name and variant name.
206/// When this value is encountered, the serializer will blindly trust the variant index.
207///
208/// To prevent users from abusing this fact, the string is compared by pointer value. Because the static
209/// is not public, there is no way for a user to obtain that value.
210static SERIALIZING_SCHEMA_DEFAULT: &str = "This value is compared by pointer value";
211
212impl<'s, 'w, W: Write, S: Borrow<Schema>> Serializer for SchemaAwareSerializer<'s, 'w, W, S> {
213    /// The amount of bytes written.
214    type Ok = usize;
215    type Error = Error;
216    type SerializeSeq = BlockSerializer<'s, 'w, W, S>;
217    type SerializeTuple = TupleSerializer<'s, 'w, W, S>;
218    type SerializeTupleStruct = ManyTupleSerializer<'s, 'w, W, S>;
219    type SerializeTupleVariant = ManyTupleSerializer<'s, 'w, W, S>;
220    type SerializeMap = MapOrRecordSerializer<'s, 'w, W, S>;
221    type SerializeStruct = RecordSerializer<'s, 'w, W, S>;
222    type SerializeStructVariant = RecordSerializer<'s, 'w, W, S>;
223
224    fn serialize_bool(mut self, v: bool) -> Result<Self::Ok, Self::Error> {
225        match self.schema {
226            Schema::Boolean => self.write_array([v as u8]),
227            Schema::Union(union) => {
228                UnionSerializer::new(self.writer, union, self.config).serialize_bool(v)
229            }
230            _ => Err(self.error("bool", "Expected Schema::Boolean")),
231        }
232    }
233
234    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
235        self.checked_write_int("i8", i32::from(v))
236    }
237
238    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
239        self.checked_write_int("i16", i32::from(v))
240    }
241
242    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
243        self.checked_write_int("i32", v)
244    }
245
246    fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
247        self.checked_write_long("i64", v)
248    }
249
250    fn serialize_i128(mut self, v: i128) -> Result<Self::Ok, Self::Error> {
251        match self.schema {
252            Schema::Fixed(fixed) if fixed.size == 16 && fixed.name.name() == "i128" => {
253                self.write_array(v.to_le_bytes())
254            }
255            Schema::Union(union) => {
256                UnionSerializer::new(self.writer, union, self.config).serialize_i128(v)
257            }
258            _ => Err(self.error("i128", r#"Expected Schema::Fixed(name: "i128", size: 16)"#)),
259        }
260    }
261
262    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
263        self.checked_write_int("u8", i32::from(v))
264    }
265
266    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
267        self.checked_write_int("u16", i32::from(v))
268    }
269
270    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
271        self.checked_write_long("u32", i64::from(v))
272    }
273
274    fn serialize_u64(mut self, v: u64) -> Result<Self::Ok, Self::Error> {
275        match self.schema {
276            Schema::Fixed(fixed) if fixed.size == 8 && fixed.name.name() == "u64" => {
277                self.write_array(v.to_le_bytes())
278            }
279            Schema::Union(union) => {
280                UnionSerializer::new(self.writer, union, self.config).serialize_u64(v)
281            }
282            _ => Err(self.error("u64", r#"Expected Schema::Fixed(name: "u64", size: 8)"#)),
283        }
284    }
285
286    fn serialize_u128(mut self, v: u128) -> Result<Self::Ok, Self::Error> {
287        match self.schema {
288            Schema::Fixed(fixed) if fixed.size == 16 && fixed.name.name() == "u128" => {
289                self.write_array(v.to_le_bytes())
290            }
291            Schema::Union(union) => {
292                UnionSerializer::new(self.writer, union, self.config).serialize_u128(v)
293            }
294            _ => Err(self.error("u128", r#"Expected Schema::Fixed(name: "u128", size: 16)"#)),
295        }
296    }
297
298    fn serialize_f32(mut self, v: f32) -> Result<Self::Ok, Self::Error> {
299        match self.schema {
300            Schema::Float => self.write_array(v.to_le_bytes()),
301            Schema::Union(union) => {
302                UnionSerializer::new(self.writer, union, self.config).serialize_f32(v)
303            }
304            _ => Err(self.error("f32", "Expected Schema::Float")),
305        }
306    }
307
308    fn serialize_f64(mut self, v: f64) -> Result<Self::Ok, Self::Error> {
309        match self.schema {
310            Schema::Double => self.write_array(v.to_le_bytes()),
311            Schema::Union(union) => {
312                UnionSerializer::new(self.writer, union, self.config).serialize_f64(v)
313            }
314            _ => Err(self.error("f64", "Expected Schema::Double")),
315        }
316    }
317
318    fn serialize_char(mut self, v: char) -> Result<Self::Ok, Self::Error> {
319        match self.schema {
320            // Convert the UTF-32 character to UTF-8
321            Schema::String => self.write_bytes_with_len(v.to_string().as_bytes()),
322            Schema::Union(union) => {
323                UnionSerializer::new(self.writer, union, self.config).serialize_char(v)
324            }
325            _ => Err(self.error("char", "Expected Schema::String")),
326        }
327    }
328
329    fn serialize_str(mut self, v: &str) -> Result<Self::Ok, Self::Error> {
330        match self.schema {
331            Schema::String | Schema::Uuid(UuidSchema::String) => {
332                self.write_bytes_with_len(v.as_bytes())
333            }
334            Schema::Union(union) => {
335                UnionSerializer::new(self.writer, union, self.config).serialize_str(v)
336            }
337            _ => Err(self.error("str", "Expected Schema::String | Schema::Uuid(String)")),
338        }
339    }
340
341    fn serialize_bytes(mut self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
342        match self.schema {
343            Schema::Bytes | Schema::BigDecimal | Schema::Decimal(DecimalSchema { inner: InnerDecimalSchema::Bytes, ..}) | Schema::Uuid(UuidSchema::Bytes) => {
344                self.write_bytes_with_len(v)
345            }
346            Schema::Fixed(fixed) | Schema::Decimal(DecimalSchema { inner: InnerDecimalSchema::Fixed(fixed), .. }) | Schema::Uuid(UuidSchema::Fixed(fixed)) | Schema::Duration(fixed) => {
347                if fixed.size != v.len() {
348                    Err(self.error("bytes", format!("Fixed size ({}) does not match bytes length ({})", fixed.size, v.len())))
349                } else {
350                    self.write_bytes(v)
351                }
352            }
353            Schema::Union(union) => {
354                UnionSerializer::new(self.writer, union, self.config).serialize_bytes(v)
355            }
356            _ => Err(self.error("bytes", "Expected Schema::Bytes | Schema::Fixed | Schema::BigDecimal | Schema::Decimal | Schema::Uuid(Bytes | Fixed) | Schema::Duration")),
357        }
358    }
359
360    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
361        if let Schema::Union(union) = self.schema
362            && union.variants().len() == 2
363            && let Some(null_index) = union.index_of_schema_kind(SchemaKind::Null)
364        {
365            zig_i32(null_index as i32, &mut *self.writer)
366        } else {
367            Err(self.error("none", "Expected Schema::Union([Schema::Null, _])"))
368        }
369    }
370
371    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
372    where
373        T: ?Sized + Serialize,
374    {
375        if let Schema::Union(union) = self.schema
376            && union.variants().len() == 2
377            && let Some(null_index) = union.index_of_schema_kind(SchemaKind::Null)
378        {
379            let some_index = (null_index + 1) & 1;
380            let mut bytes_written = zig_i32(some_index as i32, &mut *self.writer)?;
381            bytes_written +=
382                value.serialize(self.with_different_schema(&union.variants()[some_index])?)?;
383            Ok(bytes_written)
384        } else {
385            Err(self.error("some", "Expected Schema::Union([Schema::Null, _])"))
386        }
387    }
388
389    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
390        match self.schema {
391            Schema::Null => Ok(0),
392            Schema::Union(union) => {
393                UnionSerializer::new(self.writer, union, self.config).serialize_unit()
394            }
395            _ => Err(self.error("unit", "Expected Schema::Null")),
396        }
397    }
398
399    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
400        match self.schema {
401            Schema::Record(record) if record.fields.is_empty() && record.name.name() == name => {
402                Ok(0)
403            }
404            Schema::Union(union) => {
405                UnionSerializer::new(self.writer, union, self.config).serialize_unit_struct(name)
406            }
407            _ => Err(self.error(
408                "unit struct",
409                format!(r#"Expected Schema::Record(name: "{name}", fields: [])"#),
410            )),
411        }
412    }
413
414    fn serialize_unit_variant(
415        self,
416        _name: &'static str,
417        variant_index: u32,
418        variant: &'static str,
419    ) -> Result<Self::Ok, Self::Error> {
420        match self.schema {
421            Schema::Enum(enum_schema) => {
422                // Plain enum
423                if variant.as_ptr() == SERIALIZING_SCHEMA_DEFAULT.as_ptr() || enum_schema.symbols[variant_index as usize] == variant {
424                    zig_i32(variant_index as i32, &mut *self.writer)
425                } else {
426                    Err(self.error("unit variant", format!(r#"Expected symbol "{variant}" at index {variant_index} in enum"#)))
427                }
428            }
429            Schema::Union(union) => match self.get_resolved_union_variant(union, variant_index)? {
430                // Bare union
431                Schema::Null => zig_i32(variant_index as i32, &mut *self.writer),
432                Schema::Record(record) if record.fields.is_empty() && record.name.name() == variant => {
433                    // Union of records
434                    zig_i32(variant_index as i32, &mut *self.writer)
435                }
436                _ => Err(self.error("unit variant", format!("Expected Schema::Null | Schema::Record(name: {variant}, fields: []) at index {variant_index} in the union"))),
437            }
438            _ => Err(self.error("unit variant", format!("Expected Schema::Enum(symbols[{variant_index}] == {variant}) | Schema::Union(variants[{variant_index}] == Schema::Null | Schema::Record(name: {variant}, fields: []))"))),
439        }
440    }
441
442    fn serialize_newtype_struct<T>(
443        self,
444        name: &'static str,
445        value: &T,
446    ) -> Result<Self::Ok, Self::Error>
447    where
448        T: ?Sized + Serialize,
449    {
450        match self.schema {
451            Schema::Record(record) if record.fields.len() == 1 && record.name.name() == name => {
452                let schema = &record.fields[0].schema;
453                value.serialize(self.with_different_schema(schema)?)
454            }
455            Schema::Union(union) => UnionSerializer::new(self.writer, union, self.config)
456                .serialize_newtype_struct(name, value),
457            _ => Err(self.error(
458                "newtype struct",
459                format!("Expected Schema::Record(name: {name}, fields: [_])"),
460            )),
461        }
462    }
463
464    fn serialize_newtype_variant<T>(
465        self,
466        _name: &'static str,
467        variant_index: u32,
468        variant: &'static str,
469        value: &T,
470    ) -> Result<Self::Ok, Self::Error>
471    where
472        T: ?Sized + Serialize,
473    {
474        match self.schema {
475            Schema::Union(union) => match self.get_resolved_union_variant(union, variant_index)? {
476                Schema::Record(record)
477                    if record.fields.len() == 1
478                        && record.name.name() == variant
479                        && record
480                            .attributes
481                            .get("org.apache.avro.rust.union_of_records")
482                            == Some(&Bool(true)) =>
483                {
484                    // Union of records
485                    let mut bytes_written = zig_i32(variant_index as i32, &mut *self.writer)?;
486                    let schema = &record.fields[0].schema;
487                    bytes_written += value.serialize(self.with_different_schema(schema)?)?;
488                    Ok(bytes_written)
489                }
490                schema => {
491                    let mut bytes_written = zig_i32(variant_index as i32, &mut *self.writer)?;
492                    bytes_written += value.serialize(self.with_different_schema(schema)?)?;
493                    Ok(bytes_written)
494                }
495            },
496            _ => Err(self.error("newtype variant", "Expected Schema::Union")),
497        }
498    }
499
500    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
501        match self.schema {
502            Schema::Array(array) => {
503                BlockSerializer::array(self.writer, array, self.config, len, None)
504            }
505            Schema::Union(union) => {
506                UnionSerializer::new(self.writer, union, self.config).serialize_seq(len)
507            }
508            _ => Err(self.error("seq", "Expected Schema::Array")),
509        }
510    }
511
512    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
513        match self.schema {
514            Schema::Union(union) => {
515                // This needs to be matched first, otherwise the `schema if len == 1` will also
516                // match unions
517                UnionSerializer::new(self.writer, union, self.config).serialize_tuple(len)
518            }
519            // `len == 0` is not possible for derived Serialize implementations but users might use it.
520            // The derived Serialize implementations use `serialize_unit` instead
521            Schema::Null if len == 0 => Ok(TupleSerializer::unit(None)),
522            schema if len == 1 => Ok(TupleSerializer::one(self.writer, schema, self.config, None)),
523            Schema::Record(record) if record.fields.len() == len => Ok(TupleSerializer::many(
524                self.writer,
525                record,
526                self.config,
527                None,
528            )),
529            // This error case can only happen for len > 1
530            _ => Err(self.error(
531                "tuple",
532                format!("Expected Schema::Record(fields.len() == {len})"),
533            )),
534        }
535    }
536
537    fn serialize_tuple_struct(
538        self,
539        name: &'static str,
540        len: usize,
541    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
542        match self.schema {
543            Schema::Record(record) if record.fields.len() == len && record.name.name() == name => {
544                Ok(ManyTupleSerializer::new(
545                    self.writer,
546                    record,
547                    self.config,
548                    None,
549                ))
550            }
551            Schema::Union(union) => UnionSerializer::new(self.writer, union, self.config)
552                .serialize_tuple_struct(name, len),
553            _ => Err(self.error(
554                "tuple struct",
555                format!("Expected Schema::Record(name: {name}, fields.len() == {len})"),
556            )),
557        }
558    }
559
560    fn serialize_tuple_variant(
561        self,
562        _: &'static str,
563        variant_index: u32,
564        variant: &'static str,
565        len: usize,
566    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
567        if let Schema::Union(union) = self.schema
568            && let Schema::Record(record) = self.get_resolved_union_variant(union, variant_index)?
569            && record.fields.len() == len
570            && record.name.name() == variant
571        {
572            let bytes_written = zig_i32(variant_index as i32, &mut *self.writer)?;
573            Ok(ManyTupleSerializer::new(
574                self.writer,
575                record,
576                self.config,
577                Some(bytes_written),
578            ))
579        } else {
580            Err(self.error("tuple variant", format!("Expected Schema::Union(variants[{variant_index}] == Schema::Record(name: {variant}, fields.len() == {len}))")))
581        }
582    }
583
584    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
585        match self.schema {
586            Schema::Map(map) => Ok(MapOrRecordSerializer::map(
587                self.writer,
588                map,
589                self.config,
590                len,
591                None,
592            )?),
593            Schema::Record(record) => {
594                // Structs with flattened fields are serialized as a map
595                Ok(MapOrRecordSerializer::record(
596                    self.writer,
597                    record,
598                    self.config,
599                    len,
600                ))
601            }
602            Schema::Union(union) => {
603                UnionSerializer::new(self.writer, union, self.config).serialize_map(len)
604            }
605            _ => Err(self.error(
606                "map",
607                "Expected Schema::Map | Schema::Record for structs with flattened fields",
608            )),
609        }
610    }
611
612    fn serialize_struct(
613        self,
614        name: &'static str,
615        len: usize,
616    ) -> Result<Self::SerializeStruct, Self::Error> {
617        match self.schema {
618            // Serde is inconsistent with the `name` and `len` provided. When using internally tagged
619            // enums the name can be the name of the inner type of a newtype variant. The length can
620            // also change based on `serialize_if`.
621            Schema::Record(record) => Ok(RecordSerializer::new(
622                self.writer,
623                record,
624                self.config,
625                None,
626            )),
627            Schema::Union(union) => {
628                UnionSerializer::new(self.writer, union, self.config).serialize_struct(name, len)
629            }
630            _ => Err(self.error("struct", "Expected Schema::Record")),
631        }
632    }
633
634    fn serialize_struct_variant(
635        self,
636        _: &'static str,
637        variant_index: u32,
638        variant: &'static str,
639        len: usize,
640    ) -> Result<Self::SerializeStructVariant, Self::Error> {
641        if let Schema::Union(union) = self.schema
642            && let Schema::Record(record) = self.get_resolved_union_variant(union, variant_index)?
643            && record.fields.len() == len
644            && record.name.name() == variant
645        {
646            let bytes_written = zig_i32(variant_index as i32, &mut *self.writer)?;
647            Ok(RecordSerializer::new(
648                self.writer,
649                record,
650                self.config,
651                Some(bytes_written),
652            ))
653        } else {
654            Err(self.error("struct variant", format!("Expected Schema::Union(variants[{variant_index}] == Schema::Record(name: {variant}, fields.len() == {len}))")))
655        }
656    }
657
658    fn is_human_readable(&self) -> bool {
659        self.config.human_readable
660    }
661}
662
663pub enum MapOrRecordSerializer<'s, 'w, W: Write, S: Borrow<Schema>> {
664    Map(BlockSerializer<'s, 'w, W, S>),
665    Record(RecordSerializer<'s, 'w, W, S>),
666}
667
668impl<'s, 'w, W: Write, S: Borrow<Schema>> MapOrRecordSerializer<'s, 'w, W, S> {
669    pub fn record(
670        writer: &'w mut W,
671        schema: &'s RecordSchema,
672        config: Config<'s, S>,
673        bytes_written: Option<usize>,
674    ) -> Self {
675        Self::Record(RecordSerializer::new(writer, schema, config, bytes_written))
676    }
677
678    pub fn map(
679        writer: &'w mut W,
680        schema: &'s MapSchema,
681        config: Config<'s, S>,
682        len: Option<usize>,
683        bytes_written: Option<usize>,
684    ) -> Result<Self, Error> {
685        Ok(Self::Map(BlockSerializer::map(
686            writer,
687            schema,
688            config,
689            len,
690            bytes_written,
691        )?))
692    }
693}
694
695impl<'s, 'w, W: Write, S: Borrow<Schema>> SerializeMap for MapOrRecordSerializer<'s, 'w, W, S> {
696    type Ok = usize;
697    type Error = Error;
698
699    fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
700    where
701        T: ?Sized + Serialize,
702    {
703        match self {
704            MapOrRecordSerializer::Map(map) => map.serialize_key(key),
705            MapOrRecordSerializer::Record(record) => record.serialize_key(key),
706        }
707    }
708
709    fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
710    where
711        T: ?Sized + Serialize,
712    {
713        match self {
714            MapOrRecordSerializer::Map(map) => map.serialize_value(value),
715            MapOrRecordSerializer::Record(record) => record.serialize_value(value),
716        }
717    }
718
719    fn end(self) -> Result<Self::Ok, Self::Error> {
720        match self {
721            MapOrRecordSerializer::Map(map) => map.end(),
722            MapOrRecordSerializer::Record(record) => record.end(),
723        }
724    }
725}
726
727#[cfg(test)]
728mod tests {
729    use std::{
730        collections::{BTreeMap, HashMap},
731        marker::PhantomData,
732    };
733
734    use apache_avro_test_helper::TestResult;
735    use bigdecimal::BigDecimal;
736    use num_bigint::{BigInt, Sign};
737    use pretty_assertions::assert_eq;
738    use serde::{Deserialize, Serialize};
739    use serde_bytes::Bytes;
740    use uuid::Uuid;
741
742    use super::*;
743    use crate::{
744        Days, Duration, Millis, Months,
745        decimal::Decimal,
746        schema::{FixedSchema, ResolvedSchema},
747    };
748
749    #[track_caller]
750    fn assert_serialize_err<T: Serialize>(
751        t: T,
752        schema: &Schema,
753        names: &HashMap<Name, &Schema>,
754        expected: &str,
755    ) {
756        let config = Config {
757            names,
758            target_block_size: None,
759            human_readable: false,
760        };
761        let mut buffer = Vec::new();
762        let serializer = SchemaAwareSerializer::new(&mut buffer, schema, config).unwrap();
763        let error = t
764            .serialize(serializer)
765            .expect_err("This should not serialize");
766        assert_eq!(error.to_string(), expected);
767    }
768
769    #[track_caller]
770    fn assert_serialize<T: Serialize>(
771        t: T,
772        schema: &Schema,
773        names: &HashMap<Name, &Schema>,
774        expected: &[u8],
775    ) {
776        let config = Config {
777            names,
778            target_block_size: None,
779            human_readable: false,
780        };
781        let mut buffer = Vec::new();
782        let serializer = SchemaAwareSerializer::new(&mut buffer, schema, config).unwrap();
783        let bytes_written = t.serialize(serializer).expect("This should serialize");
784        assert_eq!(bytes_written, buffer.len());
785        assert_eq!(&buffer, expected);
786    }
787
788    #[test]
789    fn test_serialize_null() -> TestResult {
790        let schema = Schema::Null;
791        let names = HashMap::new();
792
793        assert_serialize((), &schema, &names, &[]);
794        assert_serialize_err(
795            None::<()>,
796            &schema,
797            &names,
798            "Failed to serialize value of type `none` using Schema::Null: Expected Schema::Union([Schema::Null, _])",
799        );
800        assert_serialize_err(
801            None::<i32>,
802            &schema,
803            &names,
804            "Failed to serialize value of type `none` using Schema::Null: Expected Schema::Union([Schema::Null, _])",
805        );
806        assert_serialize_err(
807            None::<String>,
808            &schema,
809            &names,
810            "Failed to serialize value of type `none` using Schema::Null: Expected Schema::Union([Schema::Null, _])",
811        );
812        assert_serialize_err(
813            "",
814            &schema,
815            &names,
816            "Failed to serialize value of type `str` using Schema::Null: Expected Schema::String | Schema::Uuid(String)",
817        );
818        assert_serialize_err(
819            Some(""),
820            &schema,
821            &names,
822            "Failed to serialize value of type `some` using Schema::Null: Expected Schema::Union([Schema::Null, _])",
823        );
824
825        Ok(())
826    }
827
828    #[test]
829    fn test_serialize_bool() -> TestResult {
830        let schema = Schema::Boolean;
831        let names = HashMap::new();
832
833        assert_serialize(true, &schema, &names, &[1]);
834        assert_serialize(false, &schema, &names, &[0]);
835        assert_serialize_err(
836            "",
837            &schema,
838            &names,
839            "Failed to serialize value of type `str` using Schema::Boolean: Expected Schema::String | Schema::Uuid(String)",
840        );
841        assert_serialize_err(
842            Some(""),
843            &schema,
844            &names,
845            "Failed to serialize value of type `some` using Schema::Boolean: Expected Schema::Union([Schema::Null, _])",
846        );
847
848        Ok(())
849    }
850
851    #[test]
852    fn test_serialize_int() -> TestResult {
853        let schema = Schema::Int;
854        let names = HashMap::new();
855
856        assert_serialize(4u8, &schema, &names, &[8]);
857        assert_serialize(31u16, &schema, &names, &[62]);
858        assert_serialize(7i8, &schema, &names, &[14]);
859        assert_serialize(-57i16, &schema, &names, &[113]);
860        assert_serialize(129i32, &schema, &names, &[130, 2]);
861        assert_serialize_err(
862            13u32,
863            &schema,
864            &names,
865            "Failed to serialize value of type `u32` using Schema::Int: Expected Schema::Long | Schema::TimeMicros | Schema::{,Local}Timestamp{Millis,Micros,Nanos}",
866        );
867        assert_serialize_err(
868            "",
869            &schema,
870            &names,
871            "Failed to serialize value of type `str` using Schema::Int: Expected Schema::String | Schema::Uuid(String)",
872        );
873        assert_serialize_err(
874            Some(""),
875            &schema,
876            &names,
877            "Failed to serialize value of type `some` using Schema::Int: Expected Schema::Union([Schema::Null, _])",
878        );
879
880        Ok(())
881    }
882
883    #[test]
884    fn test_serialize_long() -> TestResult {
885        let schema = Schema::Long;
886        let names = HashMap::new();
887
888        assert_serialize(13u32, &schema, &names, &[26]);
889        assert_serialize(-432i64, &schema, &names, &[223, 6]);
890        assert_serialize_err(
891            4u8,
892            &schema,
893            &names,
894            "Failed to serialize value of type `u8` using Schema::Long: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
895        );
896        assert_serialize_err(
897            31u16,
898            &schema,
899            &names,
900            "Failed to serialize value of type `u16` using Schema::Long: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
901        );
902        assert_serialize_err(
903            7i8,
904            &schema,
905            &names,
906            "Failed to serialize value of type `i8` using Schema::Long: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
907        );
908        assert_serialize_err(
909            -57i16,
910            &schema,
911            &names,
912            "Failed to serialize value of type `i16` using Schema::Long: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
913        );
914        assert_serialize_err(
915            129i32,
916            &schema,
917            &names,
918            "Failed to serialize value of type `i32` using Schema::Long: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
919        );
920        assert_serialize_err(
921            24u64,
922            &schema,
923            &names,
924            r#"Failed to serialize value of type `u64` using Schema::Long: Expected Schema::Fixed(name: "u64", size: 8)"#,
925        );
926        assert_serialize_err(
927            "",
928            &schema,
929            &names,
930            "Failed to serialize value of type `str` using Schema::Long: Expected Schema::String | Schema::Uuid(String)",
931        );
932        assert_serialize_err(
933            Some(""),
934            &schema,
935            &names,
936            "Failed to serialize value of type `some` using Schema::Long: Expected Schema::Union([Schema::Null, _])",
937        );
938
939        Ok(())
940    }
941
942    #[test]
943    fn test_serialize_float() -> TestResult {
944        let schema = Schema::Float;
945        let names = HashMap::new();
946
947        assert_serialize(4.7f32, &schema, &names, &[102, 102, 150, 64]);
948        assert_serialize_err(
949            -14.1f64,
950            &schema,
951            &names,
952            "Failed to serialize value of type `f64` using Schema::Float: Expected Schema::Double",
953        );
954        assert_serialize_err(
955            "",
956            &schema,
957            &names,
958            "Failed to serialize value of type `str` using Schema::Float: Expected Schema::String | Schema::Uuid(String)",
959        );
960        assert_serialize_err(
961            Some(""),
962            &schema,
963            &names,
964            "Failed to serialize value of type `some` using Schema::Float: Expected Schema::Union([Schema::Null, _])",
965        );
966
967        Ok(())
968    }
969
970    #[test]
971    fn test_serialize_double() -> TestResult {
972        let schema = Schema::Double;
973        let names = HashMap::new();
974
975        assert_serialize(
976            -14.1f64,
977            &schema,
978            &names,
979            &[51, 51, 51, 51, 51, 51, 44, 192],
980        );
981        assert_serialize_err(
982            4.7f32,
983            &schema,
984            &names,
985            "Failed to serialize value of type `f32` using Schema::Double: Expected Schema::Float",
986        );
987        assert_serialize_err(
988            "",
989            &schema,
990            &names,
991            "Failed to serialize value of type `str` using Schema::Double: Expected Schema::String | Schema::Uuid(String)",
992        );
993        assert_serialize_err(
994            Some(""),
995            &schema,
996            &names,
997            "Failed to serialize value of type `some` using Schema::Double: Expected Schema::Union([Schema::Null, _])",
998        );
999
1000        Ok(())
1001    }
1002
1003    #[test]
1004    fn test_serialize_bytes() -> TestResult {
1005        let schema = Schema::Bytes;
1006        let names = HashMap::new();
1007
1008        assert_serialize(
1009            Bytes::new(&[12, 3, 7, 91, 4]),
1010            &schema,
1011            &names,
1012            &[10, 12, 3, 7, 91, 4],
1013        );
1014        assert_serialize_err(
1015            'a',
1016            &schema,
1017            &names,
1018            "Failed to serialize value of type `char` using Schema::Bytes: Expected Schema::String",
1019        );
1020        assert_serialize_err(
1021            "test",
1022            &schema,
1023            &names,
1024            "Failed to serialize value of type `str` using Schema::Bytes: Expected Schema::String | Schema::Uuid(String)",
1025        );
1026        assert_serialize_err(
1027            (),
1028            &schema,
1029            &names,
1030            "Failed to serialize value of type `unit` using Schema::Bytes: Expected Schema::Null",
1031        );
1032        assert_serialize_err(
1033            PhantomData::<String>,
1034            &schema,
1035            &names,
1036            r#"Failed to serialize value of type `unit struct` using Schema::Bytes: Expected Schema::Record(name: "PhantomData", fields: [])"#,
1037        );
1038        assert_serialize_err(
1039            Some(""),
1040            &schema,
1041            &names,
1042            "Failed to serialize value of type `some` using Schema::Bytes: Expected Schema::Union([Schema::Null, _])",
1043        );
1044
1045        Ok(())
1046    }
1047
1048    #[test]
1049    fn test_serialize_string() -> TestResult {
1050        let schema = Schema::String;
1051        let names = HashMap::new();
1052
1053        assert_serialize('a', &schema, &names, &[2, b'a']);
1054        assert_serialize("test", &schema, &names, &[8, b't', b'e', b's', b't']);
1055        assert_serialize(
1056            BigDecimal::new(BigInt::new(Sign::Plus, vec![50024]), 2),
1057            &schema,
1058            &names,
1059            &[12, b'5', b'0', b'0', b'.', b'2', b'4'],
1060        );
1061        assert_serialize_err(
1062            Bytes::new(&[12, 3, 7, 91, 4]),
1063            &schema,
1064            &names,
1065            "Failed to serialize value of type `bytes` using Schema::String: Expected Schema::Bytes | Schema::Fixed | Schema::BigDecimal | Schema::Decimal | Schema::Uuid(Bytes | Fixed) | Schema::Duration",
1066        );
1067        assert_serialize_err(
1068            (),
1069            &schema,
1070            &names,
1071            "Failed to serialize value of type `unit` using Schema::String: Expected Schema::Null",
1072        );
1073        assert_serialize_err(
1074            PhantomData::<String>,
1075            &schema,
1076            &names,
1077            r#"Failed to serialize value of type `unit struct` using Schema::String: Expected Schema::Record(name: "PhantomData", fields: [])"#,
1078        );
1079        assert_serialize_err(
1080            Some(""),
1081            &schema,
1082            &names,
1083            "Failed to serialize value of type `some` using Schema::String: Expected Schema::Union([Schema::Null, _])",
1084        );
1085
1086        Ok(())
1087    }
1088
1089    #[test]
1090    fn test_serialize_record() -> TestResult {
1091        let schema = Schema::parse_str(
1092            r#"{
1093            "type": "record",
1094            "name": "TestRecord",
1095            "fields": [
1096                {"name": "stringField", "type": "string"},
1097                {"name": "intField", "type": "int"}
1098            ]
1099        }"#,
1100        )?;
1101
1102        #[derive(Serialize)]
1103        #[serde(rename_all = "camelCase", rename = "TestRecord")]
1104        struct GoodTestRecord {
1105            string_field: String,
1106            int_field: i32,
1107        }
1108
1109        #[derive(Serialize)]
1110        #[serde(rename_all = "camelCase", rename = "TestRecord")]
1111        struct BadTestRecord {
1112            foo_string_field: String,
1113            bar_int_field: i32,
1114        }
1115
1116        let names = HashMap::new();
1117
1118        let good_record = GoodTestRecord {
1119            string_field: String::from("test"),
1120            int_field: 10,
1121        };
1122        assert_serialize(
1123            good_record,
1124            &schema,
1125            &names,
1126            &[8, b't', b'e', b's', b't', 20],
1127        );
1128
1129        let bad_record = BadTestRecord {
1130            foo_string_field: String::from("test"),
1131            bar_int_field: 10,
1132        };
1133        assert_serialize_err(
1134            bad_record,
1135            &schema,
1136            &names,
1137            r#"Missing field in record: "fooStringField""#,
1138        );
1139        assert_serialize_err(
1140            "",
1141            &schema,
1142            &names,
1143            r#"Failed to serialize value of type `str` using Schema::Record(RecordSchema { name: Name { name: "TestRecord", .. }, fields: [RecordField { name: "stringField", schema: String, .. }, RecordField { name: "intField", schema: Int, .. }], .. }): Expected Schema::String | Schema::Uuid(String)"#,
1144        );
1145        assert_serialize_err(
1146            Some(""),
1147            &schema,
1148            &names,
1149            r#"Failed to serialize value of type `some` using Schema::Record(RecordSchema { name: Name { name: "TestRecord", .. }, fields: [RecordField { name: "stringField", schema: String, .. }, RecordField { name: "intField", schema: Int, .. }], .. }): Expected Schema::Union([Schema::Null, _])"#,
1150        );
1151
1152        Ok(())
1153    }
1154
1155    #[test]
1156    fn test_serialize_empty_record() -> TestResult {
1157        let schema = Schema::parse_str(
1158            r#"{
1159            "type": "record",
1160            "name": "EmptyRecord",
1161            "fields": []
1162        }"#,
1163        )?;
1164
1165        let names = HashMap::new();
1166
1167        #[derive(Serialize)]
1168        struct EmptyRecord;
1169        assert_serialize(EmptyRecord, &schema, &names, &[]);
1170
1171        #[derive(Serialize)]
1172        #[serde(rename = "EmptyRecord")]
1173        struct NonEmptyRecord {
1174            foo: String,
1175        }
1176        let record = NonEmptyRecord {
1177            foo: "bar".to_string(),
1178        };
1179        assert_serialize_err(record, &schema, &names, r#"Missing field in record: "foo""#);
1180        assert_serialize_err(
1181            (),
1182            &schema,
1183            &names,
1184            r#"Failed to serialize value of type `unit` using Schema::Record(RecordSchema { name: Name { name: "EmptyRecord", .. }, fields: [], .. }): Expected Schema::Null"#,
1185        );
1186        assert_serialize_err(
1187            "",
1188            &schema,
1189            &names,
1190            r#"Failed to serialize value of type `str` using Schema::Record(RecordSchema { name: Name { name: "EmptyRecord", .. }, fields: [], .. }): Expected Schema::String | Schema::Uuid(String)"#,
1191        );
1192        assert_serialize_err(
1193            PhantomData::<String>,
1194            &schema,
1195            &names,
1196            r#"Failed to serialize value of type `unit struct` using Schema::Record(RecordSchema { name: Name { name: "EmptyRecord", .. }, fields: [], .. }): Expected Schema::Record(name: "PhantomData", fields: [])"#,
1197        );
1198        assert_serialize_err(
1199            Some(""),
1200            &schema,
1201            &names,
1202            r#"Failed to serialize value of type `some` using Schema::Record(RecordSchema { name: Name { name: "EmptyRecord", .. }, fields: [], .. }): Expected Schema::Union([Schema::Null, _])"#,
1203        );
1204
1205        Ok(())
1206    }
1207
1208    #[test]
1209    fn test_serialize_enum() -> TestResult {
1210        let schema = Schema::parse_str(
1211            r#"{
1212            "type": "enum",
1213            "name": "Suit",
1214            "symbols": ["SPADES", "HEARTS", "DIAMONDS", "CLUBS"]
1215        }"#,
1216        )?;
1217
1218        #[derive(Serialize)]
1219        #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1220        enum Suit {
1221            Spades,
1222            Hearts,
1223            Diamonds,
1224            Clubs,
1225        }
1226
1227        let names = HashMap::new();
1228
1229        assert_serialize(Suit::Spades, &schema, &names, &[0]);
1230        assert_serialize(Suit::Hearts, &schema, &names, &[2]);
1231        assert_serialize(Suit::Diamonds, &schema, &names, &[4]);
1232        assert_serialize(Suit::Clubs, &schema, &names, &[6]);
1233        assert_serialize_err(
1234            None::<()>,
1235            &schema,
1236            &names,
1237            r#"Failed to serialize value of type `none` using Schema::Enum(EnumSchema { name: Name { name: "Suit", .. }, symbols: ["SPADES", "HEARTS", "DIAMONDS", "CLUBS"], .. }): Expected Schema::Union([Schema::Null, _])"#,
1238        );
1239
1240        Ok(())
1241    }
1242
1243    #[test]
1244    fn test_serialize_array() -> TestResult {
1245        let schema = Schema::parse_str(
1246            r#"{
1247            "type": "array",
1248            "items": "long"
1249        }"#,
1250        )?;
1251
1252        let names = HashMap::new();
1253
1254        assert_serialize(
1255            vec![10i64, 5, 400],
1256            &schema,
1257            &names,
1258            &[6, 20, 10, 160, 6, 0],
1259        );
1260        assert_serialize_err(
1261            vec![1_f32],
1262            &schema,
1263            &names,
1264            "Failed to serialize value of type `f32` using Schema::Long: Expected Schema::Float",
1265        );
1266
1267        Ok(())
1268    }
1269
1270    #[test]
1271    fn test_serialize_map() -> TestResult {
1272        let schema = Schema::parse_str(
1273            r#"{
1274            "type": "map",
1275            "values": "long"
1276        }"#,
1277        )?;
1278
1279        let names = HashMap::new();
1280
1281        let mut map: BTreeMap<String, i64> = BTreeMap::new();
1282        map.insert(String::from("item1"), 10);
1283        map.insert(String::from("item2"), 400);
1284
1285        assert_serialize(
1286            map,
1287            &schema,
1288            &names,
1289            &[
1290                4, 10, b'i', b't', b'e', b'm', b'1', 20, 10, b'i', b't', b'e', b'm', b'2', 160, 6,
1291                0,
1292            ],
1293        );
1294
1295        let mut map: BTreeMap<String, &str> = BTreeMap::new();
1296        map.insert(String::from("item1"), "value1");
1297        assert_serialize_err(
1298            map,
1299            &schema,
1300            &names,
1301            "Failed to serialize value of type `str` using Schema::Long: Expected Schema::String | Schema::Uuid(String)",
1302        );
1303
1304        Ok(())
1305    }
1306
1307    #[test]
1308    fn test_serialize_nullable_union() -> TestResult {
1309        let schema = Schema::parse_str(
1310            r#"{
1311            "type": ["null", "long"]
1312        }"#,
1313        )?;
1314
1315        #[derive(Serialize)]
1316        enum NullableLong {
1317            Null,
1318            Long(i64),
1319        }
1320
1321        let names = HashMap::new();
1322
1323        assert_serialize(Some(10i64), &schema, &names, &[2, 20]);
1324        assert_serialize(None::<i64>, &schema, &names, &[0]);
1325        assert_serialize(NullableLong::Long(400), &schema, &names, &[2, 160, 6]);
1326        assert_serialize(NullableLong::Null, &schema, &names, &[0]);
1327        assert_serialize(400i64, &schema, &names, &[2, 160, 6]);
1328        assert_serialize((), &schema, &names, &[0]);
1329        assert_serialize_err(
1330            "invalid",
1331            &schema,
1332            &names,
1333            "Failed to serialize value of type `str` using Schema::Union(UnionSchema { schemas: [Null, Long] }): Expected Schema::String in variants",
1334        );
1335
1336        Ok(())
1337    }
1338
1339    #[test]
1340    fn test_serialize_union() -> TestResult {
1341        let schema = Schema::parse_str(
1342            r#"{
1343            "type": ["null", "long", "string"]
1344        }"#,
1345        )?;
1346
1347        #[derive(Serialize)]
1348        enum LongOrString {
1349            Null,
1350            Long(i64),
1351            Str(String),
1352        }
1353
1354        let names = HashMap::new();
1355        assert_serialize(LongOrString::Null, &schema, &names, &[0]);
1356        assert_serialize(LongOrString::Long(400), &schema, &names, &[2, 160, 6]);
1357        assert_serialize(
1358            LongOrString::Str("test".into()),
1359            &schema,
1360            &names,
1361            &[4, 8, b't', b'e', b's', b't'],
1362        );
1363        assert_serialize((), &schema, &names, &[0]);
1364        assert_serialize(400i64, &schema, &names, &[2, 160, 6]);
1365        assert_serialize("test", &schema, &names, &[4, 8, b't', b'e', b's', b't']);
1366        assert_serialize_err(
1367            1f64,
1368            &schema,
1369            &names,
1370            "Failed to serialize value of type `f64` using Schema::Union(UnionSchema { schemas: [Null, Long, String] }): Expected Schema::Double in variants",
1371        );
1372
1373        Ok(())
1374    }
1375
1376    #[test]
1377    fn test_serialize_fixed() -> TestResult {
1378        let schema = Schema::parse_str(
1379            r#"{
1380            "type": "fixed",
1381            "size": 8,
1382            "name": "LongVal"
1383        }"#,
1384        )?;
1385
1386        let names = HashMap::new();
1387
1388        assert_serialize(
1389            Bytes::new(&[10, 124, 31, 97, 14, 201, 3, 88]),
1390            &schema,
1391            &names,
1392            &[10, 124, 31, 97, 14, 201, 3, 88],
1393        );
1394        assert_serialize_err(
1395            Bytes::new(&[123]),
1396            &schema,
1397            &names,
1398            r#"Failed to serialize value of type `bytes` using Schema::Fixed(FixedSchema { name: Name { name: "LongVal", .. }, size: 8, .. }): Fixed size (8) does not match bytes length (1)"#,
1399        );
1400        assert_serialize_err(
1401            [1u8; 8],
1402            &schema,
1403            &names,
1404            r#"Failed to serialize value of type `tuple` using Schema::Fixed(FixedSchema { name: Name { name: "LongVal", .. }, size: 8, .. }): Expected Schema::Record(fields.len() == 8)"#,
1405        );
1406        assert_serialize_err(
1407            [1u8, 2, 3, 4, 5, 6, 7, 8].as_slice(),
1408            &schema,
1409            &names,
1410            r#"Failed to serialize value of type `seq` using Schema::Fixed(FixedSchema { name: Name { name: "LongVal", .. }, size: 8, .. }): Expected Schema::Array"#,
1411        );
1412
1413        Ok(())
1414    }
1415
1416    #[test]
1417    fn test_serialize_decimal_bytes() -> TestResult {
1418        let schema = Schema::parse_str(
1419            r#"{
1420            "type": "bytes",
1421            "logicalType": "decimal",
1422            "precision": 16,
1423            "scale": 2
1424        }"#,
1425        )?;
1426
1427        let names = HashMap::new();
1428
1429        let val = Decimal::from(&[251, 155]);
1430        assert_serialize(val, &schema, &names, &[4, 251, 155]);
1431        assert_serialize_err(
1432            (),
1433            &schema,
1434            &names,
1435            "Failed to serialize value of type `unit` using Schema::Decimal(DecimalSchema { precision: 16, scale: 2, inner: Bytes }): Expected Schema::Null",
1436        );
1437
1438        Ok(())
1439    }
1440
1441    #[test]
1442    fn test_serialize_decimal_fixed() -> TestResult {
1443        let schema = Schema::parse_str(
1444            r#"{
1445            "type": "fixed",
1446            "name": "FixedDecimal",
1447            "size": 8,
1448            "logicalType": "decimal",
1449            "precision": 16,
1450            "scale": 2
1451        }"#,
1452        )?;
1453
1454        let names = HashMap::new();
1455
1456        let val = Decimal::from(&[0, 0, 0, 0, 0, 0, 251, 155]);
1457        assert_serialize(val, &schema, &names, &[0, 0, 0, 0, 0, 0, 251, 155]);
1458        assert_serialize_err(
1459            (),
1460            &schema,
1461            &names,
1462            r#"Failed to serialize value of type `unit` using Schema::Decimal(DecimalSchema { precision: 16, scale: 2, inner: Fixed(FixedSchema { name: Name { name: "FixedDecimal", .. }, size: 8, attributes: {"precision": Number(16), "scale": Number(2)}, .. }) }): Expected Schema::Null"#,
1463        );
1464
1465        Ok(())
1466    }
1467
1468    #[test]
1469    fn test_serialize_bigdecimal() -> TestResult {
1470        let schema = Schema::parse_str(
1471            r#"{
1472            "type": "bytes",
1473            "logicalType": "big-decimal"
1474        }"#,
1475        )?;
1476
1477        let names = HashMap::new();
1478
1479        #[derive(Serialize)]
1480        #[serde(transparent)]
1481        struct BigDecimalWrapper {
1482            // This is needed because the Serialize implementation of BigDecimal serializes to a string.
1483            // The with implementation serializes to bytes.
1484            #[serde(with = "crate::serde::bigdecimal")]
1485            value: BigDecimal,
1486        }
1487
1488        let val = BigDecimalWrapper {
1489            value: BigDecimal::new(BigInt::new(Sign::Plus, vec![50024]), 2),
1490        };
1491        assert_serialize(val, &schema, &names, &[10, 6, 0, 195, 104, 4]);
1492
1493        Ok(())
1494    }
1495
1496    #[test]
1497    fn test_serialize_uuid() -> TestResult {
1498        let schema = Schema::parse_str(
1499            r#"{
1500            "type": "fixed",
1501            "size": 16,
1502            "logicalType": "uuid",
1503            "name": "FixedUuid"
1504        }"#,
1505        )?;
1506
1507        // Uuid serialize implementation changes based on this value
1508        assert!(!crate::util::is_human_readable());
1509        let names = HashMap::new();
1510
1511        let uuid = "8c28da81-238c-4326-bddd-4e3d00cc5099".parse::<Uuid>()?;
1512
1513        assert_serialize(
1514            uuid,
1515            &schema,
1516            &names,
1517            &[
1518                140, 40, 218, 129, 35, 140, 67, 38, 189, 221, 78, 61, 0, 204, 80, 153,
1519            ],
1520        );
1521        assert_serialize_err(
1522            1u8,
1523            &schema,
1524            &names,
1525            r#"Failed to serialize value of type `u8` using Schema::Uuid(Fixed(FixedSchema { name: Name { name: "FixedUuid", .. }, size: 16, .. })): Expected Schema::Int | Schema::Date | Schema::TimeMillis"#,
1526        );
1527
1528        Ok(())
1529    }
1530
1531    #[test]
1532    fn test_serialize_date() -> TestResult {
1533        let schema = Schema::parse_str(
1534            r#"{
1535            "type": "int",
1536            "logicalType": "date"
1537        }"#,
1538        )?;
1539
1540        let names = HashMap::new();
1541
1542        assert_serialize(100u8, &schema, &names, &[200, 1]);
1543        assert_serialize(1000u16, &schema, &names, &[208, 15]);
1544        assert_serialize(1000i16, &schema, &names, &[208, 15]);
1545        assert_serialize(10000i32, &schema, &names, &[160, 156, 1]);
1546        assert_serialize_err(
1547            10000u32,
1548            &schema,
1549            &names,
1550            "Failed to serialize value of type `u32` using Schema::Date: Expected Schema::Long | Schema::TimeMicros | Schema::{,Local}Timestamp{Millis,Micros,Nanos}",
1551        );
1552        assert_serialize_err(
1553            10000f32,
1554            &schema,
1555            &names,
1556            "Failed to serialize value of type `f32` using Schema::Date: Expected Schema::Float",
1557        );
1558
1559        Ok(())
1560    }
1561
1562    #[test]
1563    fn test_serialize_time_millis() -> TestResult {
1564        let schema = Schema::parse_str(
1565            r#"{
1566            "type": "int",
1567            "logicalType": "time-millis"
1568        }"#,
1569        )?;
1570
1571        let names = HashMap::new();
1572
1573        assert_serialize(100u8, &schema, &names, &[200, 1]);
1574        assert_serialize(1000u16, &schema, &names, &[208, 15]);
1575        assert_serialize(1000i16, &schema, &names, &[208, 15]);
1576        assert_serialize(10000i32, &schema, &names, &[160, 156, 1]);
1577        assert_serialize_err(
1578            10000u32,
1579            &schema,
1580            &names,
1581            "Failed to serialize value of type `u32` using Schema::TimeMillis: Expected Schema::Long | Schema::TimeMicros | Schema::{,Local}Timestamp{Millis,Micros,Nanos}",
1582        );
1583        assert_serialize_err(
1584            10000f32,
1585            &schema,
1586            &names,
1587            "Failed to serialize value of type `f32` using Schema::TimeMillis: Expected Schema::Float",
1588        );
1589
1590        Ok(())
1591    }
1592
1593    #[test]
1594    fn test_serialize_time_micros() -> TestResult {
1595        let schema = Schema::parse_str(
1596            r#"{
1597            "type": "long",
1598            "logicalType": "time-micros"
1599        }"#,
1600        )?;
1601
1602        let names = HashMap::new();
1603
1604        assert_serialize(10000u32, &schema, &names, &[160, 156, 1]);
1605        assert_serialize(10000i64, &schema, &names, &[160, 156, 1]);
1606        assert_serialize_err(
1607            100u8,
1608            &schema,
1609            &names,
1610            "Failed to serialize value of type `u8` using Schema::TimeMicros: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
1611        );
1612        assert_serialize_err(
1613            1000u16,
1614            &schema,
1615            &names,
1616            "Failed to serialize value of type `u16` using Schema::TimeMicros: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
1617        );
1618        assert_serialize_err(
1619            1000i16,
1620            &schema,
1621            &names,
1622            "Failed to serialize value of type `i16` using Schema::TimeMicros: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
1623        );
1624        assert_serialize_err(
1625            10000i32,
1626            &schema,
1627            &names,
1628            "Failed to serialize value of type `i32` using Schema::TimeMicros: Expected Schema::Int | Schema::Date | Schema::TimeMillis",
1629        );
1630        assert_serialize_err(
1631            10000f32,
1632            &schema,
1633            &names,
1634            "Failed to serialize value of type `f32` using Schema::TimeMicros: Expected Schema::Float",
1635        );
1636
1637        Ok(())
1638    }
1639
1640    #[test]
1641    fn test_serialize_timestamp() -> TestResult {
1642        for (precision, error) in [
1643            ("millis", "Millis"),
1644            ("micros", "Micros"),
1645            ("nanos", "Nanos"),
1646        ] {
1647            let schema = Schema::parse_str(&format!(
1648                r#"{{
1649                "type": "long",
1650                "logicalType": "timestamp-{precision}"
1651            }}"#
1652            ))?;
1653
1654            let names = HashMap::new();
1655
1656            assert_serialize(10000u32, &schema, &names, &[160, 156, 1]);
1657            assert_serialize(10000i64, &schema, &names, &[160, 156, 1]);
1658            assert_serialize_err(
1659                100u8,
1660                &schema,
1661                &names,
1662                &format!(
1663                    "Failed to serialize value of type `u8` using Schema::Timestamp{error}: Expected Schema::Int | Schema::Date | Schema::TimeMillis"
1664                ),
1665            );
1666            assert_serialize_err(
1667                1000u16,
1668                &schema,
1669                &names,
1670                &format!(
1671                    "Failed to serialize value of type `u16` using Schema::Timestamp{error}: Expected Schema::Int | Schema::Date | Schema::TimeMillis"
1672                ),
1673            );
1674            assert_serialize_err(
1675                1000i16,
1676                &schema,
1677                &names,
1678                &format!(
1679                    "Failed to serialize value of type `i16` using Schema::Timestamp{error}: Expected Schema::Int | Schema::Date | Schema::TimeMillis"
1680                ),
1681            );
1682            assert_serialize_err(
1683                10000i32,
1684                &schema,
1685                &names,
1686                &format!(
1687                    "Failed to serialize value of type `i32` using Schema::Timestamp{error}: Expected Schema::Int | Schema::Date | Schema::TimeMillis"
1688                ),
1689            );
1690            assert_serialize_err(
1691                10000f32,
1692                &schema,
1693                &names,
1694                &format!(
1695                    "Failed to serialize value of type `f32` using Schema::Timestamp{error}: Expected Schema::Float"
1696                ),
1697            );
1698        }
1699
1700        Ok(())
1701    }
1702
1703    #[test]
1704    fn test_serialize_duration() -> TestResult {
1705        let schema = Schema::parse_str(
1706            r#"{
1707            "type": "fixed",
1708            "size": 12,
1709            "name": "duration",
1710            "logicalType": "duration"
1711        }"#,
1712        )?;
1713
1714        let names = HashMap::new();
1715
1716        let duration = Duration::new(Months::new(3), Days::new(2), Millis::new(1200));
1717        assert_serialize(
1718            duration,
1719            &schema,
1720            &names,
1721            &[3, 0, 0, 0, 2, 0, 0, 0, 176, 4, 0, 0],
1722        );
1723        assert_serialize_err(
1724            [0u8; 12],
1725            &schema,
1726            &names,
1727            r#"Failed to serialize value of type `tuple` using Schema::Duration(FixedSchema { name: Name { name: "duration", .. }, size: 12, .. }): Expected Schema::Record(fields.len() == 12)"#,
1728        );
1729
1730        Ok(())
1731    }
1732
1733    #[test]
1734    fn test_serialize_recursive_record() -> TestResult {
1735        let schema = Schema::parse_str(
1736            r#"{
1737            "type": "record",
1738            "name": "TestRecord",
1739            "fields": [
1740                {"name": "stringField", "type": "string"},
1741                {"name": "intField", "type": "int"},
1742                {"name": "uuidField", "type": {"name": "uuid", "type": "fixed", "size": 16, "logicalType": "uuid"}},
1743                {"name": "innerRecord", "type": ["null", "TestRecord"]}
1744            ]
1745        }"#,
1746        )?;
1747
1748        #[derive(Serialize)]
1749        #[serde(rename_all = "camelCase")]
1750        struct TestRecord {
1751            string_field: String,
1752            int_field: i32,
1753            uuid_field: Uuid,
1754            // #[serde(skip_serializing_if = "Option::is_none")] => Never ignore None!
1755            inner_record: Option<Box<TestRecord>>,
1756        }
1757
1758        assert!(!crate::util::is_human_readable());
1759        let rs = ResolvedSchema::try_from(&schema)?;
1760
1761        let good_record = TestRecord {
1762            string_field: String::from("test"),
1763            int_field: 10,
1764            uuid_field: "8c28da81-238c-4326-bddd-4e3d00cc5098".parse::<Uuid>()?,
1765            inner_record: Some(Box::new(TestRecord {
1766                string_field: String::from("inner_test"),
1767                int_field: 100,
1768                uuid_field: "8c28da81-238c-4326-bddd-4e3d00cc5099".parse::<Uuid>()?,
1769                inner_record: None,
1770            })),
1771        };
1772        assert_serialize(
1773            good_record,
1774            &schema,
1775            rs.get_names(),
1776            &[
1777                8, 116, 101, 115, 116, 20, 140, 40, 218, 129, 35, 140, 67, 38, 189, 221, 78, 61, 0,
1778                204, 80, 152, 2, 20, 105, 110, 110, 101, 114, 95, 116, 101, 115, 116, 200, 1, 140,
1779                40, 218, 129, 35, 140, 67, 38, 189, 221, 78, 61, 0, 204, 80, 153, 0,
1780            ],
1781        );
1782
1783        Ok(())
1784    }
1785
1786    #[test]
1787    fn avro_rs_337_serialize_union_record_variant() -> TestResult {
1788        let schema = Schema::parse_str(
1789            r#"{
1790            "type": "record",
1791            "name": "TestRecord",
1792            "fields": [{
1793                "name": "innerUnion", "type": [
1794                    {"type": "record", "name": "innerRecordFoo", "fields": [
1795                        {"name": "foo", "type": "string"}
1796                    ]},
1797                    {"type": "record", "name": "innerRecordBar", "fields": [
1798                        {"name": "bar", "type": "string"}
1799                    ]},
1800                    {"name": "intField", "type": "int"},
1801                    {"name": "stringField", "type": "string"}
1802                ]
1803            }]
1804        }"#,
1805        )?;
1806
1807        #[derive(Serialize)]
1808        #[serde(rename_all = "camelCase")]
1809        struct TestRecord {
1810            inner_union: InnerUnion,
1811        }
1812
1813        #[derive(Serialize)]
1814        #[serde(untagged)]
1815        enum InnerUnion {
1816            InnerVariantFoo(InnerRecordFoo),
1817            InnerVariantBar(InnerRecordBar),
1818            IntField(i32),
1819            StringField(String),
1820        }
1821
1822        #[derive(Serialize)]
1823        #[serde(rename = "innerRecordFoo")]
1824        struct InnerRecordFoo {
1825            foo: String,
1826        }
1827
1828        #[derive(Serialize)]
1829        #[serde(rename = "innerRecordBar")]
1830        struct InnerRecordBar {
1831            bar: String,
1832        }
1833
1834        let rs = ResolvedSchema::try_from(&schema)?;
1835
1836        let foo_record = TestRecord {
1837            inner_union: InnerUnion::InnerVariantFoo(InnerRecordFoo {
1838                foo: String::from("foo"),
1839            }),
1840        };
1841        assert_serialize(
1842            foo_record,
1843            &schema,
1844            rs.get_names(),
1845            &[0, 6, b'f', b'o', b'o'],
1846        );
1847        let bar_record = TestRecord {
1848            inner_union: InnerUnion::InnerVariantBar(InnerRecordBar {
1849                bar: String::from("bar"),
1850            }),
1851        };
1852        assert_serialize(
1853            bar_record,
1854            &schema,
1855            rs.get_names(),
1856            &[2, 6, b'b', b'a', b'r'],
1857        );
1858        let int_record = TestRecord {
1859            inner_union: InnerUnion::IntField(1),
1860        };
1861        assert_serialize(int_record, &schema, rs.get_names(), &[4, 2]);
1862        let string_record = TestRecord {
1863            inner_union: InnerUnion::StringField(String::from("string")),
1864        };
1865        assert_serialize(
1866            string_record,
1867            &schema,
1868            rs.get_names(),
1869            &[6, 12, b's', b't', b'r', b'i', b'n', b'g'],
1870        );
1871        Ok(())
1872    }
1873
1874    #[test]
1875    fn avro_rs_337_serialize_option_union_record_variant() -> TestResult {
1876        let schema = Schema::parse_str(
1877            r#"{
1878            "type": "record",
1879            "name": "TestRecord",
1880            "fields": [{
1881                "name": "innerUnion", "type": [
1882                    "null",
1883                    {"type": "record", "name": "innerRecordFoo", "fields": [
1884                        {"name": "foo", "type": "string"}
1885                    ]},
1886                    {"type": "record", "name": "innerRecordBar", "fields": [
1887                        {"name": "bar", "type": "string"}
1888                    ]},
1889                    {"name": "intField", "type": "int"},
1890                    {"name": "stringField", "type": "string"}
1891                ]
1892            }]
1893        }"#,
1894        )?;
1895
1896        #[derive(Serialize)]
1897        #[serde(rename_all = "camelCase")]
1898        struct TestRecord {
1899            inner_union: Option<InnerUnion>,
1900        }
1901
1902        #[derive(Serialize)]
1903        #[serde(untagged)]
1904        enum InnerUnion {
1905            IntField(i32),
1906        }
1907
1908        let rs = ResolvedSchema::try_from(&schema)?;
1909
1910        // Flattening a Option into the underlying union is NOT supported
1911        let null_record = TestRecord { inner_union: None };
1912        assert_serialize_err(
1913            null_record,
1914            &schema,
1915            rs.get_names(),
1916            r#"Failed to serialize field 'innerUnion' of record RecordSchema { name: Name { name: "TestRecord", .. }, fields: [RecordField { name: "innerUnion", schema: Union(UnionSchema { schemas: [Null, Record(RecordSchema { name: Name { name: "innerRecordFoo", .. }, fields: [RecordField { name: "foo", schema: String, .. }], .. }), Record(RecordSchema { name: Name { name: "innerRecordBar", .. }, fields: [RecordField { name: "bar", schema: String, .. }], .. }), Int, String] }), .. }], .. }: Failed to serialize value of type `none`: Expected Schema::Union([Schema::Null, _])"#,
1917        );
1918        let foo_record = TestRecord {
1919            inner_union: Some(InnerUnion::IntField(42)),
1920        };
1921        assert_serialize_err(
1922            foo_record,
1923            &schema,
1924            rs.get_names(),
1925            r#"Failed to serialize field 'innerUnion' of record RecordSchema { name: Name { name: "TestRecord", .. }, fields: [RecordField { name: "innerUnion", schema: Union(UnionSchema { schemas: [Null, Record(RecordSchema { name: Name { name: "innerRecordFoo", .. }, fields: [RecordField { name: "foo", schema: String, .. }], .. }), Record(RecordSchema { name: Name { name: "innerRecordBar", .. }, fields: [RecordField { name: "bar", schema: String, .. }], .. }), Int, String] }), .. }], .. }: Failed to serialize value of type `some`: Expected Schema::Union([Schema::Null, _])"#,
1926        );
1927        Ok(())
1928    }
1929
1930    #[test]
1931    fn avro_rs_351_different_field_order_serde_vs_schema() -> TestResult {
1932        #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1933        struct Foo {
1934            a: String,
1935            b: String,
1936            c: i64,
1937            d: f64,
1938            e: i64,
1939        }
1940        let schema = Schema::parse_str(
1941            r#"
1942        {
1943            "type":"record",
1944            "name":"Foo",
1945            "fields": [
1946                {
1947                    "name":"b",
1948                    "type":"string"
1949                },
1950                {
1951                    "name":"a",
1952                    "type":"string"
1953                },
1954                {
1955                    "name":"d",
1956                    "type":"double"
1957                },
1958                {
1959                    "name":"e",
1960                    "type":"long"
1961                },
1962                {
1963                    "name":"c",
1964                    "type":"long"
1965                }
1966            ]
1967        }
1968        "#,
1969        )?;
1970
1971        let names = HashMap::new();
1972        let foo = Foo {
1973            a: "Hello".into(),
1974            b: "World".into(),
1975            c: 42,
1976            d: std::f64::consts::PI,
1977            e: 5,
1978        };
1979
1980        assert_serialize(
1981            foo,
1982            &schema,
1983            &names,
1984            &[
1985                10, b'W', b'o', b'r', b'l', b'd', 10, b'H', b'e', b'l', b'l', b'o', 24, 45, 68, 84,
1986                251, 33, 9, 64, 10, 84,
1987            ],
1988        );
1989
1990        Ok(())
1991    }
1992
1993    #[test]
1994    fn avro_rs_414_serialize_char_as_string() -> TestResult {
1995        let schema = Schema::String;
1996        let names = HashMap::new();
1997
1998        assert_serialize('a', &schema, &names, &[2, b'a']);
1999
2000        Ok(())
2001    }
2002
2003    #[test]
2004    fn avro_rs_414_serialize_char_as_bytes() -> TestResult {
2005        let schema = Schema::Bytes;
2006        let names = HashMap::new();
2007
2008        assert_serialize_err(
2009            'a',
2010            &schema,
2011            &names,
2012            "Failed to serialize value of type `char` using Schema::Bytes: Expected Schema::String",
2013        );
2014
2015        Ok(())
2016    }
2017
2018    #[test]
2019    fn avro_rs_414_serialize_char_as_fixed() -> TestResult {
2020        let schema = Schema::Fixed(FixedSchema {
2021            name: Name::new("char")?,
2022            aliases: None,
2023            doc: None,
2024            size: 4,
2025            attributes: Default::default(),
2026        });
2027        let names = HashMap::new();
2028
2029        assert_serialize_err(
2030            'a',
2031            &schema,
2032            &names,
2033            r#"Failed to serialize value of type `char` using Schema::Fixed(FixedSchema { name: Name { name: "char", .. }, size: 4, .. }): Expected Schema::String"#,
2034        );
2035
2036        Ok(())
2037    }
2038
2039    #[test]
2040    fn avro_rs_414_serialize_emoji_char_as_string() -> TestResult {
2041        let schema = Schema::String;
2042        let names = HashMap::new();
2043
2044        assert_serialize('👹', &schema, &names, &[8, 240, 159, 145, 185]);
2045
2046        Ok(())
2047    }
2048
2049    #[test]
2050    fn avro_rs_414_serialize_i128_as_fixed() -> TestResult {
2051        let schema = Schema::Fixed(FixedSchema {
2052            name: Name::new("i128")?,
2053            aliases: None,
2054            doc: None,
2055            size: 16,
2056            attributes: Default::default(),
2057        });
2058        let names = HashMap::new();
2059
2060        assert_serialize(
2061            i128::MAX,
2062            &schema,
2063            &names,
2064            &[
2065                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2066                0xFF, 0x7F,
2067            ],
2068        );
2069
2070        Ok(())
2071    }
2072
2073    #[test]
2074    fn avro_rs_414_serialize_i128_as_fixed_wrong_name() -> TestResult {
2075        let schema = Schema::Fixed(FixedSchema {
2076            name: Name::new("onehundredtwentyeight")?,
2077            aliases: None,
2078            doc: None,
2079            size: 16,
2080            attributes: Default::default(),
2081        });
2082        let names = HashMap::new();
2083
2084        assert_serialize_err(
2085            i128::MAX,
2086            &schema,
2087            &names,
2088            r#"Failed to serialize value of type `i128` using Schema::Fixed(FixedSchema { name: Name { name: "onehundredtwentyeight", .. }, size: 16, .. }): Expected Schema::Fixed(name: "i128", size: 16)"#,
2089        );
2090
2091        Ok(())
2092    }
2093
2094    #[test]
2095    fn avro_rs_414_serialize_i128_as_fixed_wrong_size() -> TestResult {
2096        let schema = Schema::Fixed(FixedSchema {
2097            name: Name::new("i128")?,
2098            aliases: None,
2099            doc: None,
2100            size: 8,
2101            attributes: Default::default(),
2102        });
2103        let names = HashMap::new();
2104
2105        assert_serialize_err(
2106            i128::MAX,
2107            &schema,
2108            &names,
2109            r#"Failed to serialize value of type `i128` using Schema::Fixed(FixedSchema { name: Name { name: "i128", .. }, size: 8, .. }): Expected Schema::Fixed(name: "i128", size: 16)"#,
2110        );
2111
2112        Ok(())
2113    }
2114
2115    #[test]
2116    fn avro_rs_414_serialize_u128_as_fixed() -> TestResult {
2117        let schema = Schema::Fixed(FixedSchema {
2118            name: Name::new("u128")?,
2119            aliases: None,
2120            doc: None,
2121            size: 16,
2122            attributes: Default::default(),
2123        });
2124        let names = HashMap::new();
2125
2126        assert_serialize(
2127            u128::MAX,
2128            &schema,
2129            &names,
2130            &[
2131                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2132                0xFF, 0xFF,
2133            ],
2134        );
2135
2136        Ok(())
2137    }
2138
2139    #[test]
2140    fn avro_rs_414_serialize_u128_as_fixed_wrong_name() -> TestResult {
2141        let schema = Schema::Fixed(FixedSchema {
2142            name: Name::new("onehundredtwentyeight")?,
2143            aliases: None,
2144            doc: None,
2145            size: 16,
2146            attributes: Default::default(),
2147        });
2148        let names = HashMap::new();
2149
2150        assert_serialize_err(
2151            u128::MAX,
2152            &schema,
2153            &names,
2154            r#"Failed to serialize value of type `u128` using Schema::Fixed(FixedSchema { name: Name { name: "onehundredtwentyeight", .. }, size: 16, .. }): Expected Schema::Fixed(name: "u128", size: 16)"#,
2155        );
2156
2157        Ok(())
2158    }
2159
2160    #[test]
2161    fn avro_rs_414_serialize_u128_as_fixed_wrong_size() -> TestResult {
2162        let schema = Schema::Fixed(FixedSchema {
2163            name: Name::new("u128")?,
2164            aliases: None,
2165            doc: None,
2166            size: 8,
2167            attributes: Default::default(),
2168        });
2169        let names = HashMap::new();
2170
2171        assert_serialize_err(
2172            u128::MAX,
2173            &schema,
2174            &names,
2175            r#"Failed to serialize value of type `u128` using Schema::Fixed(FixedSchema { name: Name { name: "u128", .. }, size: 8, .. }): Expected Schema::Fixed(name: "u128", size: 16)"#,
2176        );
2177
2178        Ok(())
2179    }
2180
2181    #[test]
2182    fn avro_rs_421_serialize_bytes_union_of_fixed() -> TestResult {
2183        let schema = Schema::parse_str(
2184            r#"[
2185            { "name": "fixed4", "type": "fixed", "size": 4 },
2186            { "name": "fixed8", "type": "fixed", "size": 8 }
2187        ]"#,
2188        )?;
2189        let names = HashMap::new();
2190        assert_serialize(Bytes::new(&[0, 1, 2, 3]), &schema, &names, &[0, 0, 1, 2, 3]);
2191        assert_serialize(
2192            Bytes::new(&[4, 5, 6, 7, 8, 9, 10, 11]),
2193            &schema,
2194            &names,
2195            &[2, 4, 5, 6, 7, 8, 9, 10, 11],
2196        );
2197
2198        Ok(())
2199    }
2200}