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