apache_avro/serde/
with.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
18use std::cell::Cell;
19
20thread_local! {
21    /// A thread local that is used to decide how to serialize Rust bytes into an Avro
22    /// `types::Value` of type bytes.
23    ///
24    /// Relies on the fact that serde's serialization process is single-threaded.
25    pub(crate) static SER_BYTES_TYPE: Cell<BytesType> = const { Cell::new(BytesType::Bytes) };
26
27    /// A thread local that is used to decide how to deserialize an Avro `types::Value`
28    /// of type bytes into Rust bytes.
29    ///
30    /// Relies on the fact that serde's deserialization process is single-threaded.
31    pub(crate) static DE_BYTES_BORROWED: Cell<bool> = const { Cell::new(false) };
32}
33
34#[derive(Debug, Clone, Copy)]
35pub(crate) enum BytesType {
36    Bytes,
37    Fixed,
38}
39
40struct BytesTypeGuard(BytesType);
41impl BytesTypeGuard {
42    fn set(temp: BytesType) -> Self {
43        let prev = SER_BYTES_TYPE.get();
44        SER_BYTES_TYPE.set(temp);
45        Self(prev)
46    }
47}
48
49impl Drop for BytesTypeGuard {
50    fn drop(&mut self) {
51        SER_BYTES_TYPE.set(self.0);
52    }
53}
54
55struct BorrowedGuard(bool);
56impl BorrowedGuard {
57    fn set(temp: bool) -> Self {
58        let prev = DE_BYTES_BORROWED.get();
59        DE_BYTES_BORROWED.set(temp);
60        Self(prev)
61    }
62}
63
64impl Drop for BorrowedGuard {
65    fn drop(&mut self) {
66        DE_BYTES_BORROWED.set(self.0);
67    }
68}
69
70/// Efficient (de)serialization of Avro bytes values.
71///
72/// This module is intended to be used through the Serde `with` attribute.
73/// Use [`apache_avro::serde::bytes_opt`] for optional bytes.
74///
75/// See usage with below example:
76/// ```
77/// # use apache_avro::AvroSchema;
78/// # use serde::{Deserialize, Serialize};
79///
80/// #[derive(AvroSchema, Serialize, Deserialize)]
81/// struct StructWithBytes {
82///     #[avro(with)]
83///     #[serde(with = "apache_avro::serde::bytes")]
84///     vec_field: Vec<u8>,
85///
86///     #[avro(with = apache_avro::serde::fixed::get_schema_in_ctxt::<6>)]
87///     #[serde(with = "apache_avro::serde::fixed")]
88///     fixed_field: [u8; 6],
89/// }
90/// ```
91///
92/// [`apache_avro::serde::bytes_opt`]: bytes_opt
93pub mod bytes {
94    use serde::{Deserializer, Serializer};
95
96    use crate::{
97        Schema,
98        schema::{Names, Namespace},
99    };
100
101    /// Returns [`Schema::Bytes`]
102    pub fn get_schema_in_ctxt(_names: &mut Names, _enclosing_namespace: &Namespace) -> Schema {
103        Schema::Bytes
104    }
105
106    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
107    where
108        S: Serializer,
109    {
110        serde_bytes::serialize(bytes, serializer)
111    }
112
113    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
114    where
115        D: Deserializer<'de>,
116    {
117        serde_bytes::deserialize(deserializer)
118    }
119}
120
121/// Efficient (de)serialization of optional Avro bytes values.
122///
123/// This module is intended to be used through the Serde `with` attribute.
124/// Use [`apache_avro::serde::bytes`] for non-optional bytes.
125///
126/// See usage with below example:
127/// ```
128/// # use apache_avro::AvroSchema;
129/// # use serde::{Deserialize, Serialize};
130///
131/// #[derive(AvroSchema, Serialize, Deserialize)]
132/// struct StructWithBytes {
133///     #[avro(with)]
134///     #[serde(with = "apache_avro::serde::bytes_opt")]
135///     vec_field: Option<Vec<u8>>,
136///
137///     #[avro(with = apache_avro::serde::fixed_opt::get_schema_in_ctxt::<6>)]
138///     #[serde(with = "apache_avro::serde::fixed_opt")]
139///     fixed_field: Option<[u8; 6]>,
140/// }
141/// ```
142///
143/// [`apache_avro::serde::bytes`]: bytes
144pub mod bytes_opt {
145    use serde::{Deserializer, Serializer};
146    use std::borrow::Borrow;
147
148    use crate::{
149        Schema,
150        schema::{Names, Namespace, UnionSchema},
151    };
152
153    /// Returns `Schema::Union(Schema::Null, Schema::Bytes)`
154    pub fn get_schema_in_ctxt(_names: &mut Names, _enclosing_namespace: &Namespace) -> Schema {
155        Schema::Union(
156            UnionSchema::new(vec![Schema::Null, Schema::Bytes]).expect("This is a valid union"),
157        )
158    }
159
160    pub fn serialize<S, B>(bytes: &Option<B>, serializer: S) -> Result<S::Ok, S::Error>
161    where
162        S: Serializer,
163        B: Borrow<[u8]> + serde_bytes::Serialize,
164    {
165        serde_bytes::serialize(bytes, serializer)
166    }
167
168    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
169    where
170        D: Deserializer<'de>,
171    {
172        serde_bytes::deserialize(deserializer)
173    }
174}
175
176/// Efficient (de)serialization of Avro fixed values.
177///
178/// This module is intended to be used through the Serde `with` attribute.
179/// Use [`apache_avro::serde::fixed_opt`] for optional fixed values.
180///
181/// See usage with below example:
182/// ```
183/// # use apache_avro::AvroSchema;
184/// # use serde::{Deserialize, Serialize};
185///
186/// #[derive(AvroSchema, Serialize, Deserialize)]
187/// struct StructWithBytes {
188///     #[avro(with)]
189///     #[serde(with = "apache_avro::serde::bytes")]
190///     vec_field: Vec<u8>,
191///
192///     #[avro(with = apache_avro::serde::fixed::get_schema_in_ctxt::<6>)]
193///     #[serde(with = "apache_avro::serde::fixed")]
194///     fixed_field: [u8; 6],
195/// }
196/// ```
197///
198/// [`apache_avro::serde::fixed_opt`]: fixed_opt
199pub mod fixed {
200    use super::BytesType;
201    use serde::{Deserializer, Serializer};
202
203    use crate::{
204        Schema,
205        schema::{FixedSchema, Name, Names, Namespace},
206    };
207
208    /// Returns `Schema::Fixed(N)` named `serde_avro_fixed_{N}`
209    #[expect(clippy::map_entry, reason = "We don't use the value from the map")]
210    pub fn get_schema_in_ctxt<const N: usize>(
211        named_schemas: &mut Names,
212        enclosing_namespace: &Namespace,
213    ) -> Schema {
214        let name = Name::new(&format!("serde_avro_fixed_{N}"))
215            .expect("Name is valid")
216            .fully_qualified_name(enclosing_namespace);
217        if named_schemas.contains_key(&name) {
218            Schema::Ref { name }
219        } else {
220            let schema = Schema::Fixed(FixedSchema::builder().name(name.clone()).size(N).build());
221            named_schemas.insert(name, schema.clone());
222            schema
223        }
224    }
225
226    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
227    where
228        S: Serializer,
229    {
230        let _guard = super::BytesTypeGuard::set(BytesType::Fixed);
231        serde_bytes::serialize(bytes, serializer)
232    }
233
234    pub fn deserialize<'de, D, const N: usize>(deserializer: D) -> Result<[u8; N], D::Error>
235    where
236        D: Deserializer<'de>,
237    {
238        serde_bytes::deserialize(deserializer)
239    }
240}
241
242/// Efficient (de)serialization of optional Avro fixed values.
243///
244/// This module is intended to be used through the Serde `with` attribute.
245/// Use [`apache_avro::serde::fixed`] for non-optional fixed values.
246///
247/// See usage with below example:
248/// ```
249/// # use apache_avro::AvroSchema;
250/// # use serde::{Deserialize, Serialize};
251///
252/// #[derive(AvroSchema, Serialize, Deserialize)]
253/// struct StructWithBytes {
254///     #[avro(with)]
255///     #[serde(with = "apache_avro::serde::bytes_opt")]
256///     vec_field: Option<Vec<u8>>,
257///
258///     #[avro(with = apache_avro::serde::fixed_opt::get_schema_in_ctxt::<6>)]
259///     #[serde(with = "apache_avro::serde::fixed_opt")]
260///     fixed_field: Option<[u8; 6]>,
261/// }
262/// ```
263///
264/// [`apache_avro::serde::fixed`]: fixed
265pub mod fixed_opt {
266    use super::BytesType;
267    use serde::{Deserializer, Serializer};
268    use std::borrow::Borrow;
269
270    use crate::{
271        Schema,
272        schema::{Names, Namespace, UnionSchema},
273    };
274
275    /// Returns `Schema::Union(Schema::Null, Schema::Fixed(N))` where the fixed schema is named `serde_avro_fixed_{N}`
276    pub fn get_schema_in_ctxt<const N: usize>(
277        named_schemas: &mut Names,
278        enclosing_namespace: &Namespace,
279    ) -> Schema {
280        Schema::Union(
281            UnionSchema::new(vec![
282                Schema::Null,
283                super::fixed::get_schema_in_ctxt::<N>(named_schemas, enclosing_namespace),
284            ])
285            .expect("This is a valid union"),
286        )
287    }
288
289    pub fn serialize<S, B>(bytes: &Option<B>, serializer: S) -> Result<S::Ok, S::Error>
290    where
291        S: Serializer,
292        B: Borrow<[u8]> + serde_bytes::Serialize,
293    {
294        let _guard = super::BytesTypeGuard::set(BytesType::Fixed);
295        serde_bytes::serialize(bytes, serializer)
296    }
297
298    pub fn deserialize<'de, D, const N: usize>(deserializer: D) -> Result<Option<[u8; N]>, D::Error>
299    where
300        D: Deserializer<'de>,
301    {
302        serde_bytes::deserialize(deserializer)
303    }
304}
305
306/// Efficient (de)serialization of Avro bytes/fixed borrowed values.
307///
308/// This module is intended to be used through the Serde `with` attribute.
309///
310/// Note that `&[u8]` are always serialized as [`Value::Bytes`]. However,
311/// both [`Value::Bytes`] and [`Value::Fixed`] can be deserialized as `&[u8]`.
312///
313/// Use [`apache_avro::serde::slice_opt`] for optional bytes/fixed borrowed values.
314///
315/// See usage with below example:
316/// ```rust
317/// # use apache_avro::AvroSchema;
318/// # use serde::{Deserialize, Serialize};
319///
320/// #[derive(AvroSchema, Serialize, Deserialize)]
321/// struct StructWithBytes<'a> {
322///     #[avro(with)]
323///     #[serde(with = "apache_avro::serde::slice")]
324///     slice_field: &'a [u8],
325/// }
326/// ```
327///
328/// [`Value::Bytes`]: crate::types::Value::Bytes
329/// [`Value::Fixed`]: crate::types::Value::Fixed
330/// [`apache_avro::serde::slice_opt`]: slice_opt
331pub mod slice {
332    use serde::{Deserializer, Serializer};
333
334    use crate::{
335        Schema,
336        schema::{Names, Namespace},
337    };
338
339    /// Returns [`Schema::Bytes`]
340    pub fn get_schema_in_ctxt(_names: &mut Names, _enclosing_namespace: &Namespace) -> Schema {
341        Schema::Bytes
342    }
343
344    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
345    where
346        S: Serializer,
347    {
348        serde_bytes::serialize(bytes, serializer)
349    }
350
351    pub fn deserialize<'de, D>(deserializer: D) -> Result<&'de [u8], D::Error>
352    where
353        D: Deserializer<'de>,
354    {
355        let _guard = super::BorrowedGuard::set(true);
356        serde_bytes::deserialize(deserializer)
357    }
358}
359
360/// Efficient (de)serialization of optional Avro bytes/fixed borrowed values.
361///
362/// This module is intended to be used through the Serde `with` attribute.
363///
364/// Note that `&[u8]` are always serialized as [`Value::Bytes`]. However,
365/// both [`Value::Bytes`] and [`Value::Fixed`] can be deserialized as `&[u8]`.
366///
367/// Use [`apache_avro::serde::slice`] for non-optional bytes/fixed borrowed values.
368///
369/// See usage with below example:
370/// ```
371/// # use apache_avro::AvroSchema;
372/// # use serde::{Deserialize, Serialize};
373///
374/// #[derive(AvroSchema, Serialize, Deserialize)]
375/// struct StructWithBytes<'a> {
376///     #[avro(with)]
377///     #[serde(with = "apache_avro::serde::slice_opt")]
378///     slice_field: Option<&'a [u8]>,
379/// }
380/// ```
381///
382/// [`Value::Bytes`]: crate::types::Value::Bytes
383/// [`Value::Fixed`]: crate::types::Value::Fixed
384/// [`apache_avro::serde::slice`]: mod@slice
385pub mod slice_opt {
386    use serde::{Deserializer, Serializer};
387    use std::borrow::Borrow;
388
389    use crate::{
390        Schema,
391        schema::{Names, Namespace, UnionSchema},
392    };
393
394    /// Returns `Schema::Union(Schema::Null, Schema::Bytes)`
395    pub fn get_schema_in_ctxt(_names: &mut Names, _enclosing_namespace: &Namespace) -> Schema {
396        Schema::Union(
397            UnionSchema::new(vec![Schema::Null, Schema::Bytes]).expect("This is a valid union"),
398        )
399    }
400
401    pub fn serialize<S, B>(bytes: &Option<B>, serializer: S) -> Result<S::Ok, S::Error>
402    where
403        S: Serializer,
404        B: Borrow<[u8]> + serde_bytes::Serialize,
405    {
406        serde_bytes::serialize(&bytes, serializer)
407    }
408
409    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<&'de [u8]>, D::Error>
410    where
411        D: Deserializer<'de>,
412    {
413        let _guard = super::BorrowedGuard::set(true);
414        serde_bytes::deserialize(deserializer)
415    }
416}
417
418#[cfg(test)]
419mod tests {
420    use crate::{Schema, from_value, to_value, types::Value};
421    use serde::{Deserialize, Serialize};
422
423    #[test]
424    fn avro_3631_validate_schema_for_struct_with_byte_types() {
425        #[derive(Debug, Serialize)]
426        struct TestStructWithBytes<'a> {
427            #[serde(with = "crate::serde::bytes")]
428            vec_field: Vec<u8>,
429            #[serde(with = "crate::serde::bytes_opt")]
430            vec_field_opt: Option<Vec<u8>>,
431
432            #[serde(with = "crate::serde::fixed")]
433            fixed_field: [u8; 6],
434            #[serde(with = "crate::serde::fixed_opt")]
435            fixed_field_opt: Option<[u8; 7]>,
436
437            #[serde(with = "crate::serde::slice")]
438            slice_field: &'a [u8],
439            #[serde(with = "crate::serde::slice_opt")]
440            slice_field_opt: Option<&'a [u8]>,
441        }
442
443        let test = TestStructWithBytes {
444            vec_field: vec![2, 3, 4],
445            vec_field_opt: Some(vec![2, 3, 4]),
446            fixed_field: [1; 6],
447            fixed_field_opt: Some([1; 7]),
448            slice_field: &[1, 2, 3],
449            slice_field_opt: Some(&[1, 2, 3]),
450        };
451        let value: Value = to_value(test).unwrap();
452        let schema = Schema::parse_str(
453            r#"
454            {
455              "type": "record",
456              "name": "TestStructWithBytes",
457              "fields": [ {
458                "name": "vec_field",
459                "type": "bytes"
460              }, {
461                "name": "vec_field_opt",
462                "type": ["null", "bytes"]
463              }, {
464                "name": "fixed_field",
465                "type": {
466                  "name": "ByteData",
467                  "type": "fixed",
468                  "size": 6
469                }
470              }, {
471                "name": "fixed_field_opt",
472                "type": ["null", {
473                  "name": "ByteData2",
474                  "type": "fixed",
475                  "size": 7
476                } ]
477              }, {
478                "name": "slice_field",
479                "type": "bytes"
480              }, {
481                "name": "slice_field_opt",
482                "type": ["null", "bytes"]
483              } ]
484            }"#,
485        )
486        .unwrap();
487        assert!(value.validate(&schema));
488    }
489
490    #[test]
491    fn avro_3631_deserialize_value_to_struct_with_byte_types() {
492        #[derive(Debug, Deserialize, PartialEq)]
493        struct TestStructWithBytes<'a> {
494            #[serde(with = "crate::serde::bytes")]
495            vec_field: Vec<u8>,
496            #[serde(with = "crate::serde::bytes_opt")]
497            vec_field_opt: Option<Vec<u8>>,
498            #[serde(with = "crate::serde::bytes_opt")]
499            vec_field_opt2: Option<Vec<u8>>,
500
501            #[serde(with = "crate::serde::fixed")]
502            fixed_field: [u8; 6],
503            #[serde(with = "crate::serde::fixed_opt")]
504            fixed_field_opt: Option<[u8; 7]>,
505            #[serde(with = "crate::serde::fixed_opt")]
506            fixed_field_opt2: Option<[u8; 8]>,
507
508            #[serde(with = "crate::serde::slice")]
509            slice_bytes_field: &'a [u8],
510            #[serde(with = "crate::serde::slice_opt")]
511            slice_bytes_field_opt: Option<&'a [u8]>,
512            #[serde(with = "crate::serde::slice_opt")]
513            slice_bytes_field_opt2: Option<&'a [u8]>,
514
515            #[serde(with = "crate::serde::slice")]
516            slice_fixed_field: &'a [u8],
517            #[serde(with = "crate::serde::slice_opt")]
518            slice_fixed_field_opt: Option<&'a [u8]>,
519            #[serde(with = "crate::serde::slice_opt")]
520            slice_fixed_field_opt2: Option<&'a [u8]>,
521        }
522
523        let expected = TestStructWithBytes {
524            vec_field: vec![3, 33],
525            vec_field_opt: Some(vec![4, 44]),
526            vec_field_opt2: None,
527            fixed_field: [1; 6],
528            fixed_field_opt: Some([7; 7]),
529            fixed_field_opt2: None,
530            slice_bytes_field: &[1, 11, 111],
531            slice_bytes_field_opt: Some(&[5, 5, 5, 5, 5]),
532            slice_bytes_field_opt2: None,
533            slice_fixed_field: &[2, 22, 222],
534            slice_fixed_field_opt: Some(&[3, 3, 3]),
535            slice_fixed_field_opt2: None,
536        };
537
538        let value = Value::Record(vec![
539            (
540                "vec_field".to_owned(),
541                Value::Bytes(expected.vec_field.clone()),
542            ),
543            (
544                "vec_field_opt".to_owned(),
545                Value::Union(
546                    1,
547                    Box::new(Value::Bytes(
548                        expected.vec_field_opt.as_ref().unwrap().clone(),
549                    )),
550                ),
551            ),
552            (
553                "vec_field_opt2".to_owned(),
554                Value::Union(0, Box::new(Value::Null)),
555            ),
556            (
557                "fixed_field".to_owned(),
558                Value::Fixed(expected.fixed_field.len(), expected.fixed_field.to_vec()),
559            ),
560            (
561                "fixed_field_opt".to_owned(),
562                Value::Union(
563                    1,
564                    Box::new(Value::Fixed(
565                        expected.fixed_field_opt.as_ref().unwrap().len(),
566                        expected.fixed_field_opt.as_ref().unwrap().to_vec(),
567                    )),
568                ),
569            ),
570            (
571                "fixed_field_opt2".to_owned(),
572                Value::Union(0, Box::new(Value::Null)),
573            ),
574            (
575                "slice_bytes_field".to_owned(),
576                Value::Bytes(expected.slice_bytes_field.to_vec()),
577            ),
578            (
579                "slice_bytes_field_opt".to_owned(),
580                Value::Union(
581                    1,
582                    Box::new(Value::Bytes(
583                        expected.slice_bytes_field_opt.as_ref().unwrap().to_vec(),
584                    )),
585                ),
586            ),
587            (
588                "slice_bytes_field_opt2".to_owned(),
589                Value::Union(0, Box::new(Value::Null)),
590            ),
591            (
592                "slice_fixed_field".to_owned(),
593                Value::Fixed(
594                    expected.slice_fixed_field.len(),
595                    expected.slice_fixed_field.to_vec(),
596                ),
597            ),
598            (
599                "slice_fixed_field_opt".to_owned(),
600                Value::Union(
601                    1,
602                    Box::new(Value::Fixed(
603                        expected.slice_fixed_field_opt.as_ref().unwrap().len(),
604                        expected.slice_fixed_field_opt.as_ref().unwrap().to_vec(),
605                    )),
606                ),
607            ),
608            (
609                "slice_fixed_field_opt2".to_owned(),
610                Value::Union(1, Box::new(Value::Null)),
611            ),
612        ]);
613        assert_eq!(expected, from_value(&value).unwrap());
614    }
615
616    #[test]
617    fn avro_3631_serialize_struct_to_value_with_byte_types() {
618        #[derive(Debug, Serialize)]
619        struct TestStructWithBytes<'a> {
620            array_field: &'a [u8],
621            vec_field: Vec<u8>,
622
623            #[serde(with = "crate::serde::fixed")]
624            vec_field2: Vec<u8>,
625            #[serde(with = "crate::serde::fixed_opt")]
626            vec_field2_opt: Option<Vec<u8>>,
627            #[serde(with = "crate::serde::fixed_opt")]
628            vec_field2_opt2: Option<Vec<u8>>,
629
630            #[serde(with = "crate::serde::bytes")]
631            vec_field3: Vec<u8>,
632            #[serde(with = "crate::serde::bytes_opt")]
633            vec_field3_opt: Option<Vec<u8>>,
634            #[serde(with = "crate::serde::bytes_opt")]
635            vec_field3_opt2: Option<Vec<u8>>,
636
637            #[serde(with = "crate::serde::fixed")]
638            fixed_field: [u8; 6],
639            #[serde(with = "crate::serde::fixed_opt")]
640            fixed_field_opt: Option<[u8; 5]>,
641            #[serde(with = "crate::serde::fixed_opt")]
642            fixed_field_opt2: Option<[u8; 4]>,
643
644            #[serde(with = "crate::serde::fixed")]
645            fixed_field2: &'a [u8],
646            #[serde(with = "crate::serde::fixed_opt")]
647            fixed_field2_opt: Option<&'a [u8]>,
648            #[serde(with = "crate::serde::fixed_opt")]
649            fixed_field2_opt2: Option<&'a [u8]>,
650
651            #[serde(with = "crate::serde::bytes")]
652            bytes_field: &'a [u8],
653            #[serde(with = "crate::serde::bytes_opt")]
654            bytes_field_opt: Option<&'a [u8]>,
655            #[serde(with = "crate::serde::bytes_opt")]
656            bytes_field_opt2: Option<&'a [u8]>,
657
658            #[serde(with = "crate::serde::bytes")]
659            bytes_field2: [u8; 6],
660            #[serde(with = "crate::serde::bytes_opt")]
661            bytes_field2_opt: Option<[u8; 7]>,
662            #[serde(with = "crate::serde::bytes_opt")]
663            bytes_field2_opt2: Option<[u8; 8]>,
664        }
665
666        let test = TestStructWithBytes {
667            array_field: &[1, 11, 111],
668            vec_field: vec![3, 33],
669            vec_field2: vec![4, 44],
670            vec_field2_opt: Some(vec![14, 144]),
671            vec_field2_opt2: None,
672            vec_field3: vec![5, 55],
673            vec_field3_opt: Some(vec![15, 155]),
674            vec_field3_opt2: None,
675            fixed_field: [1; 6],
676            fixed_field_opt: Some([6; 5]),
677            fixed_field_opt2: None,
678            fixed_field2: &[6, 66],
679            fixed_field2_opt: Some(&[7, 77]),
680            fixed_field2_opt2: None,
681            bytes_field: &[2, 22, 222],
682            bytes_field_opt: Some(&[3, 33, 233]),
683            bytes_field_opt2: None,
684            bytes_field2: [2; 6],
685            bytes_field2_opt: Some([2; 7]),
686            bytes_field2_opt2: None,
687        };
688        let expected = Value::Record(vec![
689            (
690                "array_field".to_owned(),
691                Value::Array(
692                    test.array_field
693                        .iter()
694                        .map(|&i| Value::Int(i as i32))
695                        .collect(),
696                ),
697            ),
698            (
699                "vec_field".to_owned(),
700                Value::Array(
701                    test.vec_field
702                        .iter()
703                        .map(|&i| Value::Int(i as i32))
704                        .collect(),
705                ),
706            ),
707            (
708                "vec_field2".to_owned(),
709                Value::Fixed(test.vec_field2.len(), test.vec_field2.clone()),
710            ),
711            (
712                "vec_field2_opt".to_owned(),
713                Value::Union(
714                    1,
715                    Box::new(Value::Fixed(
716                        test.vec_field2_opt.as_ref().unwrap().len(),
717                        test.vec_field2_opt.as_ref().unwrap().to_vec(),
718                    )),
719                ),
720            ),
721            (
722                "vec_field2_opt2".to_owned(),
723                Value::Union(0, Box::new(Value::Null)),
724            ),
725            (
726                "vec_field3".to_owned(),
727                Value::Bytes(test.vec_field3.clone()),
728            ),
729            (
730                "vec_field3_opt".to_owned(),
731                Value::Union(
732                    1,
733                    Box::new(Value::Bytes(test.vec_field3_opt.as_ref().unwrap().clone())),
734                ),
735            ),
736            (
737                "vec_field3_opt2".to_owned(),
738                Value::Union(0, Box::new(Value::Null)),
739            ),
740            (
741                "fixed_field".to_owned(),
742                Value::Fixed(test.fixed_field.len(), test.fixed_field.to_vec()),
743            ),
744            (
745                "fixed_field_opt".to_owned(),
746                Value::Union(
747                    1,
748                    Box::new(Value::Fixed(
749                        test.fixed_field_opt.as_ref().unwrap().len(),
750                        test.fixed_field_opt.as_ref().unwrap().to_vec(),
751                    )),
752                ),
753            ),
754            (
755                "fixed_field_opt2".to_owned(),
756                Value::Union(0, Box::new(Value::Null)),
757            ),
758            (
759                "fixed_field2".to_owned(),
760                Value::Fixed(test.fixed_field2.len(), test.fixed_field2.to_vec()),
761            ),
762            (
763                "fixed_field2_opt".to_owned(),
764                Value::Union(
765                    1,
766                    Box::new(Value::Fixed(
767                        test.fixed_field2_opt.as_ref().unwrap().len(),
768                        test.fixed_field2_opt.as_ref().unwrap().to_vec(),
769                    )),
770                ),
771            ),
772            (
773                "fixed_field2_opt2".to_owned(),
774                Value::Union(0, Box::new(Value::Null)),
775            ),
776            (
777                "bytes_field".to_owned(),
778                Value::Bytes(test.bytes_field.to_vec()),
779            ),
780            (
781                "bytes_field_opt".to_owned(),
782                Value::Union(
783                    1,
784                    Box::new(Value::Bytes(
785                        test.bytes_field_opt.as_ref().unwrap().to_vec(),
786                    )),
787                ),
788            ),
789            (
790                "bytes_field_opt2".to_owned(),
791                Value::Union(0, Box::new(Value::Null)),
792            ),
793            (
794                "bytes_field2".to_owned(),
795                Value::Bytes(test.bytes_field2.to_vec()),
796            ),
797            (
798                "bytes_field2_opt".to_owned(),
799                Value::Union(
800                    1,
801                    Box::new(Value::Bytes(
802                        test.bytes_field2_opt.as_ref().unwrap().to_vec(),
803                    )),
804                ),
805            ),
806            (
807                "bytes_field2_opt2".to_owned(),
808                Value::Union(0, Box::new(Value::Null)),
809            ),
810        ]);
811        assert_eq!(expected, to_value(test).unwrap());
812    }
813}