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