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