1use 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
33pub 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
43pub(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 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 #[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(); }
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}