apache_avro/
encode.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 crate::schema::{InnerDecimalSchema, UuidSchema};
19use crate::{
20    AvroResult,
21    bigdecimal::serialize_big_decimal,
22    error::Details,
23    schema::{
24        DecimalSchema, EnumSchema, FixedSchema, Name, Namespace, RecordSchema, ResolvedSchema,
25        Schema, SchemaKind, UnionSchema,
26    },
27    types::{Value, ValueKind},
28    util::{zig_i32, zig_i64},
29};
30use log::error;
31use std::{borrow::Borrow, collections::HashMap, io::Write};
32
33/// Encode a `Value` into avro format.
34///
35/// **NOTE** This will not perform schema validation. The value is assumed to
36/// be valid with regards to the schema. Schema are needed only to guide the
37/// encoding for complex type values.
38pub fn encode<W: Write>(value: &Value, schema: &Schema, writer: &mut W) -> AvroResult<usize> {
39    let rs = ResolvedSchema::try_from(schema)?;
40    encode_internal(value, schema, rs.get_names(), &None, writer)
41}
42
43/// Encode `s` as the _bytes_ primitive type.
44///
45/// This writes the length as the _long_ primitive and then the raw bytes.
46pub(crate) fn encode_bytes<B: AsRef<[u8]> + ?Sized, W: Write>(
47    s: &B,
48    mut writer: W,
49) -> AvroResult<usize> {
50    let bytes = s.as_ref();
51    encode_long(bytes.len() as i64, &mut writer)?;
52    writer
53        .write(bytes)
54        .map_err(|e| Details::WriteBytes(e).into())
55}
56
57pub(crate) fn encode_long<W: Write>(i: i64, writer: W) -> AvroResult<usize> {
58    zig_i64(i, writer)
59}
60
61pub(crate) fn encode_int<W: Write>(i: i32, writer: W) -> AvroResult<usize> {
62    zig_i32(i, writer)
63}
64
65pub(crate) fn encode_internal<W: Write, S: Borrow<Schema>>(
66    value: &Value,
67    schema: &Schema,
68    names: &HashMap<Name, S>,
69    enclosing_namespace: &Namespace,
70    writer: &mut W,
71) -> AvroResult<usize> {
72    if let Schema::Ref { name } = schema {
73        let fully_qualified_name = name.fully_qualified_name(enclosing_namespace);
74        let resolved = names
75            .get(&fully_qualified_name)
76            .ok_or(Details::SchemaResolutionError(fully_qualified_name))?;
77        return encode_internal(value, resolved.borrow(), names, enclosing_namespace, writer);
78    }
79
80    match value {
81        Value::Null => {
82            if let Schema::Union(union) = schema {
83                match union.schemas.iter().position(|sch| *sch == Schema::Null) {
84                    None => Err(Details::EncodeValueAsSchemaError {
85                        value_kind: ValueKind::Null,
86                        supported_schema: vec![SchemaKind::Null, SchemaKind::Union],
87                    }
88                    .into()),
89                    Some(p) => encode_long(p as i64, writer),
90                }
91            } else {
92                Ok(0)
93            }
94        }
95        Value::Boolean(b) => writer
96            .write(&[u8::from(*b)])
97            .map_err(|e| Details::WriteBytes(e).into()),
98        // Pattern | Pattern here to signify that these _must_ have the same encoding.
99        Value::Int(i) | Value::Date(i) | Value::TimeMillis(i) => encode_int(*i, writer),
100        Value::Long(i)
101        | Value::TimestampMillis(i)
102        | Value::TimestampMicros(i)
103        | Value::TimestampNanos(i)
104        | Value::LocalTimestampMillis(i)
105        | Value::LocalTimestampMicros(i)
106        | Value::LocalTimestampNanos(i)
107        | Value::TimeMicros(i) => encode_long(*i, writer),
108        Value::Float(x) => writer
109            .write(&x.to_le_bytes())
110            .map_err(|e| Details::WriteBytes(e).into()),
111        Value::Double(x) => writer
112            .write(&x.to_le_bytes())
113            .map_err(|e| Details::WriteBytes(e).into()),
114        Value::Decimal(decimal) => match schema {
115            Schema::Decimal(DecimalSchema { inner, .. }) => match inner {
116                InnerDecimalSchema::Fixed(fixed) => {
117                    let bytes = decimal.to_sign_extended_bytes_with_len(fixed.size)?;
118                    let num_bytes = bytes.len();
119                    if num_bytes != fixed.size {
120                        return Err(
121                            Details::EncodeDecimalAsFixedError(num_bytes, fixed.size).into()
122                        );
123                    }
124                    encode(
125                        &Value::Fixed(fixed.size, bytes),
126                        &Schema::Fixed(fixed.copy_only_size()),
127                        writer,
128                    )
129                }
130                InnerDecimalSchema::Bytes => {
131                    encode(&Value::Bytes(decimal.try_into()?), &Schema::Bytes, writer)
132                }
133            },
134            _ => Err(Details::EncodeValueAsSchemaError {
135                value_kind: ValueKind::Decimal,
136                supported_schema: vec![SchemaKind::Decimal],
137            }
138            .into()),
139        },
140        &Value::Duration(duration) => {
141            let slice: [u8; 12] = duration.into();
142            writer
143                .write(&slice)
144                .map_err(|e| Details::WriteBytes(e).into())
145        }
146        Value::Uuid(uuid) => match *schema {
147            Schema::Uuid(UuidSchema::String) | Schema::String => encode_bytes(
148                // we need the call .to_string() to properly convert ASCII to UTF-8
149                #[allow(clippy::unnecessary_to_owned)]
150                &uuid.to_string(),
151                writer,
152            ),
153            Schema::Uuid(UuidSchema::Bytes) | Schema::Bytes => {
154                let bytes = uuid.as_bytes();
155                encode_bytes(bytes, writer)
156            }
157            Schema::Uuid(UuidSchema::Fixed(FixedSchema { size, .. }))
158            | Schema::Fixed(FixedSchema { size, .. }) => {
159                if size != 16 {
160                    return Err(Details::ConvertFixedToUuid(size).into());
161                }
162
163                let bytes = uuid.as_bytes();
164                writer
165                    .write(bytes.as_slice())
166                    .map_err(|e| Details::WriteBytes(e).into())
167            }
168            _ => Err(Details::EncodeValueAsSchemaError {
169                value_kind: ValueKind::Uuid,
170                supported_schema: vec![
171                    SchemaKind::Uuid,
172                    SchemaKind::Fixed,
173                    SchemaKind::Bytes,
174                    SchemaKind::String,
175                ],
176            }
177            .into()),
178        },
179        Value::BigDecimal(bg) => {
180            let buf: Vec<u8> = serialize_big_decimal(bg)?;
181            writer
182                .write(buf.as_slice())
183                .map_err(|e| Details::WriteBytes(e).into())
184        }
185        Value::Bytes(bytes) => match *schema {
186            Schema::Bytes | Schema::Uuid(UuidSchema::Bytes) => encode_bytes(bytes, writer),
187            Schema::Fixed { .. } => writer
188                .write(bytes.as_slice())
189                .map_err(|e| Details::WriteBytes(e).into()),
190            _ => Err(Details::EncodeValueAsSchemaError {
191                value_kind: ValueKind::Bytes,
192                supported_schema: vec![SchemaKind::Bytes, SchemaKind::Fixed, SchemaKind::Uuid],
193            }
194            .into()),
195        },
196        Value::String(s) => match *schema {
197            Schema::String | Schema::Uuid(UuidSchema::String) => encode_bytes(s, writer),
198            Schema::Enum(EnumSchema { ref symbols, .. }) => {
199                if let Some(index) = symbols.iter().position(|item| item == s) {
200                    encode_int(index as i32, writer)
201                } else {
202                    error!("Invalid symbol string {:?}.", &s[..]);
203                    Err(Details::GetEnumSymbol(s.clone()).into())
204                }
205            }
206            _ => Err(Details::EncodeValueAsSchemaError {
207                value_kind: ValueKind::String,
208                supported_schema: vec![SchemaKind::String, SchemaKind::Enum],
209            }
210            .into()),
211        },
212        Value::Fixed(_, bytes) => writer
213            .write(bytes.as_slice())
214            .map_err(|e| Details::WriteBytes(e).into()),
215        Value::Enum(i, _) => encode_int(*i as i32, writer),
216        Value::Union(idx, item) => {
217            if let Schema::Union(ref inner) = *schema {
218                let inner_schema = inner
219                    .schemas
220                    .get(*idx as usize)
221                    .expect("Invalid Union validation occurred");
222                encode_long(*idx as i64, &mut *writer)?;
223                encode_internal(item, inner_schema, names, enclosing_namespace, &mut *writer)
224            } else {
225                error!("invalid schema type for Union: {schema:?}");
226                Err(Details::EncodeValueAsSchemaError {
227                    value_kind: ValueKind::Union,
228                    supported_schema: vec![SchemaKind::Union],
229                }
230                .into())
231            }
232        }
233        Value::Array(items) => {
234            if let Schema::Array(ref inner) = *schema {
235                if !items.is_empty() {
236                    encode_long(items.len() as i64, &mut *writer)?;
237                    for item in items.iter() {
238                        encode_internal(
239                            item,
240                            &inner.items,
241                            names,
242                            enclosing_namespace,
243                            &mut *writer,
244                        )?;
245                    }
246                }
247                writer
248                    .write(&[0u8])
249                    .map_err(|e| Details::WriteBytes(e).into())
250            } else {
251                error!("invalid schema type for Array: {schema:?}");
252                Err(Details::EncodeValueAsSchemaError {
253                    value_kind: ValueKind::Array,
254                    supported_schema: vec![SchemaKind::Array],
255                }
256                .into())
257            }
258        }
259        Value::Map(items) => {
260            if let Schema::Map(ref inner) = *schema {
261                if !items.is_empty() {
262                    encode_long(items.len() as i64, &mut *writer)?;
263                    for (key, value) in items {
264                        encode_bytes(key, &mut *writer)?;
265                        encode_internal(
266                            value,
267                            &inner.types,
268                            names,
269                            enclosing_namespace,
270                            &mut *writer,
271                        )?;
272                    }
273                }
274                writer
275                    .write(&[0u8])
276                    .map_err(|e| Details::WriteBytes(e).into())
277            } else {
278                error!("invalid schema type for Map: {schema:?}");
279                Err(Details::EncodeValueAsSchemaError {
280                    value_kind: ValueKind::Map,
281                    supported_schema: vec![SchemaKind::Map],
282                }
283                .into())
284            }
285        }
286        Value::Record(value_fields) => {
287            if let Schema::Record(RecordSchema {
288                ref name,
289                fields: ref schema_fields,
290                ..
291            }) = *schema
292            {
293                let record_namespace = name.fully_qualified_name(enclosing_namespace).namespace;
294
295                let mut lookup = HashMap::new();
296                value_fields.iter().for_each(|(name, field)| {
297                    lookup.insert(name, field);
298                });
299
300                let mut written_bytes = 0;
301                for schema_field in schema_fields.iter() {
302                    let name = &schema_field.name;
303                    let value_opt = lookup.get(name).or_else(|| {
304                        if let Some(aliases) = &schema_field.aliases {
305                            aliases.iter().find_map(|alias| lookup.get(alias))
306                        } else {
307                            None
308                        }
309                    });
310
311                    if let Some(value) = value_opt {
312                        written_bytes += encode_internal(
313                            value,
314                            &schema_field.schema,
315                            names,
316                            &record_namespace,
317                            writer,
318                        )?;
319                    } else {
320                        return Err(Details::NoEntryInLookupTable(
321                            name.clone(),
322                            format!("{lookup:?}"),
323                        )
324                        .into());
325                    }
326                }
327                Ok(written_bytes)
328            } else if let Schema::Union(UnionSchema { schemas, .. }) = schema {
329                let mut union_buffer: Vec<u8> = Vec::new();
330                for (index, schema) in schemas.iter().enumerate() {
331                    encode_long(index as i64, &mut union_buffer)?;
332                    let encode_res = encode_internal(
333                        value,
334                        schema,
335                        names,
336                        enclosing_namespace,
337                        &mut union_buffer,
338                    );
339                    match encode_res {
340                        Ok(_) => {
341                            return writer
342                                .write(union_buffer.as_slice())
343                                .map_err(|e| Details::WriteBytes(e).into());
344                        }
345                        Err(_) => {
346                            union_buffer.clear(); //undo any partial encoding
347                        }
348                    }
349                }
350                Err(Details::EncodeValueAsSchemaError {
351                    value_kind: ValueKind::Record,
352                    supported_schema: vec![SchemaKind::Record, SchemaKind::Union],
353                }
354                .into())
355            } else {
356                error!("invalid schema type for Record: {schema:?}");
357                Err(Details::EncodeValueAsSchemaError {
358                    value_kind: ValueKind::Record,
359                    supported_schema: vec![SchemaKind::Record, SchemaKind::Union],
360                }
361                .into())
362            }
363        }
364    }
365}
366
367pub fn encode_to_vec(value: &Value, schema: &Schema) -> AvroResult<Vec<u8>> {
368    let mut buffer = Vec::new();
369    encode(value, schema, &mut buffer)?;
370    Ok(buffer)
371}
372
373#[cfg(test)]
374#[allow(clippy::expect_fun_call)]
375pub(crate) mod tests {
376    use super::*;
377    use crate::error::{Details, Error};
378    use apache_avro_test_helper::TestResult;
379    use pretty_assertions::assert_eq;
380    use uuid::Uuid;
381
382    pub(crate) fn success(value: &Value, schema: &Schema) -> String {
383        format!(
384            "Value: {:?}\n should encode with schema:\n{:?}",
385            &value, &schema
386        )
387    }
388
389    #[test]
390    fn test_encode_empty_array() {
391        let mut buf = Vec::new();
392        let empty: Vec<Value> = Vec::new();
393        encode(
394            &Value::Array(empty.clone()),
395            &Schema::array(Schema::Int),
396            &mut buf,
397        )
398        .expect(&success(&Value::Array(empty), &Schema::array(Schema::Int)));
399        assert_eq!(vec![0u8], buf);
400    }
401
402    #[test]
403    fn test_encode_empty_map() {
404        let mut buf = Vec::new();
405        let empty: HashMap<String, Value> = HashMap::new();
406        encode(
407            &Value::Map(empty.clone()),
408            &Schema::map(Schema::Int),
409            &mut buf,
410        )
411        .expect(&success(&Value::Map(empty), &Schema::map(Schema::Int)));
412        assert_eq!(vec![0u8], buf);
413    }
414
415    #[test]
416    fn test_avro_3433_recursive_definition_encode_record() {
417        let mut buf = Vec::new();
418        let schema = Schema::parse_str(
419            r#"
420            {
421                "type":"record",
422                "name":"TestStruct",
423                "fields": [
424                    {
425                        "name":"a",
426                        "type":{
427                            "type":"record",
428                            "name": "Inner",
429                            "fields": [ {
430                                "name":"z",
431                                "type":"int"
432                            }]
433                        }
434                    },
435                    {
436                        "name":"b",
437                        "type":"Inner"
438                    }
439                ]
440            }"#,
441        )
442        .unwrap();
443
444        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
445        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
446        let outer_value =
447            Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
448        encode(&outer_value, &schema, &mut buf).expect(&success(&outer_value, &schema));
449        assert!(!buf.is_empty());
450    }
451
452    #[test]
453    fn test_avro_3433_recursive_definition_encode_array() {
454        let mut buf = Vec::new();
455        let schema = Schema::parse_str(
456            r#"
457            {
458                "type":"record",
459                "name":"TestStruct",
460                "fields": [
461                    {
462                        "name":"a",
463                        "type":{
464                            "type":"array",
465                            "items": {
466                                "type":"record",
467                                "name": "Inner",
468                                "fields": [ {
469                                    "name":"z",
470                                    "type":"int"
471                                }]
472                            }
473                        }
474                    },
475                    {
476                        "name":"b",
477                        "type": {
478                            "type":"map",
479                            "values":"Inner"
480                        }
481                    }
482                ]
483            }"#,
484        )
485        .unwrap();
486
487        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
488        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
489        let outer_value = Value::Record(vec![
490            ("a".into(), Value::Array(vec![inner_value1])),
491            (
492                "b".into(),
493                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
494            ),
495        ]);
496        encode(&outer_value, &schema, &mut buf).expect(&success(&outer_value, &schema));
497        assert!(!buf.is_empty());
498    }
499
500    #[test]
501    fn test_avro_3433_recursive_definition_encode_map() {
502        let mut buf = Vec::new();
503        let schema = Schema::parse_str(
504            r#"
505            {
506                "type":"record",
507                "name":"TestStruct",
508                "fields": [
509                {
510                    "name":"a",
511                    "type":{
512                        "type":"record",
513                        "name": "Inner",
514                        "fields": [ {
515                            "name":"z",
516                            "type":"int"
517                        }]
518                    }
519                },
520                {
521                    "name":"b",
522                    "type": {
523                        "type":"map",
524                        "values":"Inner"
525                    }
526                }
527            ]
528        }"#,
529        )
530        .unwrap();
531
532        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
533        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
534        let outer_value = Value::Record(vec![
535            ("a".into(), inner_value1),
536            (
537                "b".into(),
538                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
539            ),
540        ]);
541        encode(&outer_value, &schema, &mut buf).expect(&success(&outer_value, &schema));
542        assert!(!buf.is_empty());
543    }
544
545    #[test]
546    fn test_avro_3433_recursive_definition_encode_record_wrapper() {
547        let mut buf = Vec::new();
548        let schema = Schema::parse_str(
549            r#"
550        {
551            "type":"record",
552            "name":"TestStruct",
553            "fields": [
554                {
555                    "name":"a",
556                    "type":{
557                        "type":"record",
558                        "name": "Inner",
559                        "fields": [ {
560                            "name":"z",
561                            "type":"int"
562                        }]
563                    }
564                },
565                {
566                    "name":"b",
567                    "type": {
568                        "type":"record",
569                        "name": "InnerWrapper",
570                        "fields": [ {
571                            "name":"j",
572                            "type":"Inner"
573                        }]
574                    }
575                }
576            ]
577        }"#,
578        )
579        .unwrap();
580
581        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
582        let inner_value2 = Value::Record(vec![(
583            "j".into(),
584            Value::Record(vec![("z".into(), Value::Int(6))]),
585        )]);
586        let outer_value =
587            Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
588        encode(&outer_value, &schema, &mut buf).expect(&success(&outer_value, &schema));
589        assert!(!buf.is_empty());
590    }
591
592    #[test]
593    fn test_avro_3433_recursive_definition_encode_map_and_array() {
594        let mut buf = Vec::new();
595        let schema = Schema::parse_str(
596            r#"
597        {
598            "type":"record",
599            "name":"TestStruct",
600            "fields": [
601                {
602                    "name":"a",
603                    "type":{
604                        "type":"map",
605                        "values": {
606                            "type":"record",
607                            "name": "Inner",
608                            "fields": [ {
609                                "name":"z",
610                                "type":"int"
611                            }]
612                        }
613                    }
614                },
615                {
616                    "name":"b",
617                    "type": {
618                        "type":"array",
619                        "items":"Inner"
620                    }
621                }
622            ]
623        }"#,
624        )
625        .unwrap();
626
627        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
628        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
629        let outer_value = Value::Record(vec![
630            (
631                "a".into(),
632                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
633            ),
634            ("b".into(), Value::Array(vec![inner_value1])),
635        ]);
636        encode(&outer_value, &schema, &mut buf).expect(&success(&outer_value, &schema));
637        assert!(!buf.is_empty());
638    }
639
640    #[test]
641    fn test_avro_3433_recursive_definition_encode_union() {
642        let mut buf = Vec::new();
643        let schema = Schema::parse_str(
644            r#"
645        {
646            "type":"record",
647            "name":"TestStruct",
648            "fields": [
649                {
650                    "name":"a",
651                    "type":["null", {
652                        "type":"record",
653                        "name": "Inner",
654                        "fields": [ {
655                            "name":"z",
656                            "type":"int"
657                        }]
658                    }]
659                },
660                {
661                    "name":"b",
662                    "type":"Inner"
663                }
664            ]
665        }"#,
666        )
667        .unwrap();
668
669        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
670        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
671        let outer_value1 = Value::Record(vec![
672            ("a".into(), Value::Union(1, Box::new(inner_value1))),
673            ("b".into(), inner_value2.clone()),
674        ]);
675        encode(&outer_value1, &schema, &mut buf).expect(&success(&outer_value1, &schema));
676        assert!(!buf.is_empty());
677
678        buf.drain(..);
679        let outer_value2 = Value::Record(vec![
680            ("a".into(), Value::Union(0, Box::new(Value::Null))),
681            ("b".into(), inner_value2),
682        ]);
683        encode(&outer_value2, &schema, &mut buf).expect(&success(&outer_value1, &schema));
684        assert!(!buf.is_empty());
685    }
686
687    #[test]
688    fn test_avro_3448_proper_multi_level_encoding_outer_namespace() {
689        let schema = r#"
690        {
691          "name": "record_name",
692          "namespace": "space",
693          "type": "record",
694          "fields": [
695            {
696              "name": "outer_field_1",
697              "type": [
698                        "null",
699                        {
700                            "type": "record",
701                            "name": "middle_record_name",
702                            "fields":[
703                                {
704                                    "name":"middle_field_1",
705                                    "type":[
706                                        "null",
707                                        {
708                                            "type":"record",
709                                            "name":"inner_record_name",
710                                            "fields":[
711                                                {
712                                                    "name":"inner_field_1",
713                                                    "type":"double"
714                                                }
715                                            ]
716                                        }
717                                    ]
718                                }
719                            ]
720                        }
721                    ]
722            },
723            {
724                "name": "outer_field_2",
725                "type" : "space.inner_record_name"
726            }
727          ]
728        }
729        "#;
730        let schema = Schema::parse_str(schema).unwrap();
731        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
732        let middle_record_variation_1 = Value::Record(vec![(
733            "middle_field_1".into(),
734            Value::Union(0, Box::new(Value::Null)),
735        )]);
736        let middle_record_variation_2 = Value::Record(vec![(
737            "middle_field_1".into(),
738            Value::Union(1, Box::new(inner_record.clone())),
739        )]);
740        let outer_record_variation_1 = Value::Record(vec![
741            (
742                "outer_field_1".into(),
743                Value::Union(0, Box::new(Value::Null)),
744            ),
745            ("outer_field_2".into(), inner_record.clone()),
746        ]);
747        let outer_record_variation_2 = Value::Record(vec![
748            (
749                "outer_field_1".into(),
750                Value::Union(1, Box::new(middle_record_variation_1)),
751            ),
752            ("outer_field_2".into(), inner_record.clone()),
753        ]);
754        let outer_record_variation_3 = Value::Record(vec![
755            (
756                "outer_field_1".into(),
757                Value::Union(1, Box::new(middle_record_variation_2)),
758            ),
759            ("outer_field_2".into(), inner_record),
760        ]);
761
762        let mut buf = Vec::new();
763        encode(&outer_record_variation_1, &schema, &mut buf)
764            .expect(&success(&outer_record_variation_1, &schema));
765        assert!(!buf.is_empty());
766        buf.drain(..);
767        encode(&outer_record_variation_2, &schema, &mut buf)
768            .expect(&success(&outer_record_variation_2, &schema));
769        assert!(!buf.is_empty());
770        buf.drain(..);
771        encode(&outer_record_variation_3, &schema, &mut buf)
772            .expect(&success(&outer_record_variation_3, &schema));
773        assert!(!buf.is_empty());
774    }
775
776    #[test]
777    fn test_avro_3448_proper_multi_level_encoding_middle_namespace() {
778        let schema = r#"
779        {
780          "name": "record_name",
781          "namespace": "space",
782          "type": "record",
783          "fields": [
784            {
785              "name": "outer_field_1",
786              "type": [
787                        "null",
788                        {
789                            "type": "record",
790                            "name": "middle_record_name",
791                            "namespace":"middle_namespace",
792                            "fields":[
793                                {
794                                    "name":"middle_field_1",
795                                    "type":[
796                                        "null",
797                                        {
798                                            "type":"record",
799                                            "name":"inner_record_name",
800                                            "fields":[
801                                                {
802                                                    "name":"inner_field_1",
803                                                    "type":"double"
804                                                }
805                                            ]
806                                        }
807                                    ]
808                                }
809                            ]
810                        }
811                    ]
812            },
813            {
814                "name": "outer_field_2",
815                "type" : "middle_namespace.inner_record_name"
816            }
817          ]
818        }
819        "#;
820        let schema = Schema::parse_str(schema).unwrap();
821        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
822        let middle_record_variation_1 = Value::Record(vec![(
823            "middle_field_1".into(),
824            Value::Union(0, Box::new(Value::Null)),
825        )]);
826        let middle_record_variation_2 = Value::Record(vec![(
827            "middle_field_1".into(),
828            Value::Union(1, Box::new(inner_record.clone())),
829        )]);
830        let outer_record_variation_1 = Value::Record(vec![
831            (
832                "outer_field_1".into(),
833                Value::Union(0, Box::new(Value::Null)),
834            ),
835            ("outer_field_2".into(), inner_record.clone()),
836        ]);
837        let outer_record_variation_2 = Value::Record(vec![
838            (
839                "outer_field_1".into(),
840                Value::Union(1, Box::new(middle_record_variation_1)),
841            ),
842            ("outer_field_2".into(), inner_record.clone()),
843        ]);
844        let outer_record_variation_3 = Value::Record(vec![
845            (
846                "outer_field_1".into(),
847                Value::Union(1, Box::new(middle_record_variation_2)),
848            ),
849            ("outer_field_2".into(), inner_record),
850        ]);
851
852        let mut buf = Vec::new();
853        encode(&outer_record_variation_1, &schema, &mut buf)
854            .expect(&success(&outer_record_variation_1, &schema));
855        assert!(!buf.is_empty());
856        buf.drain(..);
857        encode(&outer_record_variation_2, &schema, &mut buf)
858            .expect(&success(&outer_record_variation_2, &schema));
859        assert!(!buf.is_empty());
860        buf.drain(..);
861        encode(&outer_record_variation_3, &schema, &mut buf)
862            .expect(&success(&outer_record_variation_3, &schema));
863        assert!(!buf.is_empty());
864    }
865
866    #[test]
867    fn test_avro_3448_proper_multi_level_encoding_inner_namespace() {
868        let schema = r#"
869        {
870          "name": "record_name",
871          "namespace": "space",
872          "type": "record",
873          "fields": [
874            {
875              "name": "outer_field_1",
876              "type": [
877                        "null",
878                        {
879                            "type": "record",
880                            "name": "middle_record_name",
881                            "namespace":"middle_namespace",
882                            "fields":[
883                                {
884                                    "name":"middle_field_1",
885                                    "type":[
886                                        "null",
887                                        {
888                                            "type":"record",
889                                            "name":"inner_record_name",
890                                            "namespace":"inner_namespace",
891                                            "fields":[
892                                                {
893                                                    "name":"inner_field_1",
894                                                    "type":"double"
895                                                }
896                                            ]
897                                        }
898                                    ]
899                                }
900                            ]
901                        }
902                    ]
903            },
904            {
905                "name": "outer_field_2",
906                "type" : "inner_namespace.inner_record_name"
907            }
908          ]
909        }
910        "#;
911        let schema = Schema::parse_str(schema).unwrap();
912        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
913        let middle_record_variation_1 = Value::Record(vec![(
914            "middle_field_1".into(),
915            Value::Union(0, Box::new(Value::Null)),
916        )]);
917        let middle_record_variation_2 = Value::Record(vec![(
918            "middle_field_1".into(),
919            Value::Union(1, Box::new(inner_record.clone())),
920        )]);
921        let outer_record_variation_1 = Value::Record(vec![
922            (
923                "outer_field_1".into(),
924                Value::Union(0, Box::new(Value::Null)),
925            ),
926            ("outer_field_2".into(), inner_record.clone()),
927        ]);
928        let outer_record_variation_2 = Value::Record(vec![
929            (
930                "outer_field_1".into(),
931                Value::Union(1, Box::new(middle_record_variation_1)),
932            ),
933            ("outer_field_2".into(), inner_record.clone()),
934        ]);
935        let outer_record_variation_3 = Value::Record(vec![
936            (
937                "outer_field_1".into(),
938                Value::Union(1, Box::new(middle_record_variation_2)),
939            ),
940            ("outer_field_2".into(), inner_record),
941        ]);
942
943        let mut buf = Vec::new();
944        encode(&outer_record_variation_1, &schema, &mut buf)
945            .expect(&success(&outer_record_variation_1, &schema));
946        assert!(!buf.is_empty());
947        buf.drain(..);
948        encode(&outer_record_variation_2, &schema, &mut buf)
949            .expect(&success(&outer_record_variation_2, &schema));
950        assert!(!buf.is_empty());
951        buf.drain(..);
952        encode(&outer_record_variation_3, &schema, &mut buf)
953            .expect(&success(&outer_record_variation_3, &schema));
954        assert!(!buf.is_empty());
955    }
956
957    #[test]
958    fn test_avro_3585_encode_uuids() {
959        let value = Value::String(String::from("00000000-0000-0000-0000-000000000000"));
960        let schema = Schema::Uuid(UuidSchema::String);
961        let mut buffer = Vec::new();
962        let encoded = encode(&value, &schema, &mut buffer);
963        assert!(encoded.is_ok());
964        assert!(!buffer.is_empty());
965    }
966
967    #[test]
968    fn avro_3926_encode_decode_uuid_to_fixed_wrong_schema_size() -> TestResult {
969        let schema = Schema::Fixed(FixedSchema {
970            size: 15,
971            name: "uuid".try_into()?,
972            aliases: None,
973            doc: None,
974            default: None,
975            attributes: Default::default(),
976        });
977        let value = Value::Uuid(Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")?);
978
979        let mut buffer = Vec::new();
980        match encode(&value, &schema, &mut buffer).map_err(Error::into_details) {
981            Err(Details::ConvertFixedToUuid(actual)) => {
982                assert_eq!(actual, 15);
983            }
984            _ => panic!("Expected Details::ConvertFixedToUuid"),
985        }
986
987        Ok(())
988    }
989}