Skip to main content

apache_avro/
types.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
18//! Logic handling the intermediate representation of Avro values.
19use crate::schema::{InnerDecimalSchema, NamespaceRef, UuidSchema};
20use crate::{
21    AvroResult, Error,
22    bigdecimal::{deserialize_big_decimal, serialize_big_decimal},
23    decimal::Decimal,
24    duration::Duration,
25    error::Details,
26    schema::{
27        DecimalSchema, EnumSchema, FixedSchema, Name, Precision, RecordField, RecordSchema,
28        ResolvedSchema, Scale, Schema, SchemaKind, UnionSchema,
29    },
30};
31use bigdecimal::BigDecimal;
32use log::{debug, error};
33use serde_json::{Number, Value as JsonValue};
34use std::{
35    borrow::Borrow,
36    collections::{BTreeMap, HashMap},
37    fmt::Debug,
38    hash::BuildHasher,
39    str::FromStr,
40};
41use uuid::Uuid;
42
43/// Compute the maximum decimal value precision of a byte array of length `len` could hold.
44fn max_prec_for_len(len: usize) -> Result<usize, Error> {
45    let len = i32::try_from(len).map_err(|e| Details::ConvertLengthToI32(e, len))?;
46    Ok((2.0_f64.powi(8 * len - 1) - 1.0).log10().floor() as usize)
47}
48
49/// A valid Avro value.
50///
51/// More information about Avro values can be found in the [Avro
52/// Specification](https://avro.apache.org/docs/++version++/specification/#schema-declaration)
53#[derive(Clone, Debug, PartialEq, strum::EnumDiscriminants)]
54#[strum_discriminants(name(ValueKind))]
55pub enum Value {
56    /// A `null` Avro value.
57    Null,
58    /// A `boolean` Avro value.
59    Boolean(bool),
60    /// A `int` Avro value.
61    Int(i32),
62    /// A `long` Avro value.
63    Long(i64),
64    /// A `float` Avro value.
65    Float(f32),
66    /// A `double` Avro value.
67    Double(f64),
68    /// A `bytes` Avro value.
69    Bytes(Vec<u8>),
70    /// A `string` Avro value.
71    String(String),
72    /// A `fixed` Avro value.
73    /// The size of the fixed value is represented as a `usize`.
74    Fixed(usize, Vec<u8>),
75    /// An `enum` Avro value.
76    ///
77    /// An Enum is represented by a symbol and its position in the symbols list
78    /// of its corresponding schema.
79    /// This allows schema-less encoding, as well as schema resolution while
80    /// reading values.
81    Enum(u32, String),
82    /// An `union` Avro value.
83    ///
84    /// A Union is represented by the value it holds and its position in the type list
85    /// of its corresponding schema
86    /// This allows schema-less encoding, as well as schema resolution while
87    /// reading values.
88    Union(u32, Box<Value>),
89    /// An `array` Avro value.
90    Array(Vec<Value>),
91    /// A `map` Avro value.
92    Map(HashMap<String, Value>),
93    /// A `record` Avro value.
94    ///
95    /// A Record is represented by a vector of (`<record name>`, `value`).
96    /// This allows schema-less encoding.
97    ///
98    /// See [Record](types.Record) for a more user-friendly support.
99    Record(Vec<(String, Value)>),
100    /// A date value.
101    ///
102    /// Serialized and deserialized as `i32` directly. Can only be deserialized properly with a
103    /// schema.
104    Date(i32),
105    /// An Avro Decimal value. Bytes are in big-endian order, per the Avro spec.
106    Decimal(Decimal),
107    /// An Avro Decimal value.
108    BigDecimal(BigDecimal),
109    /// Time in milliseconds.
110    TimeMillis(i32),
111    /// Time in microseconds.
112    TimeMicros(i64),
113    /// Timestamp in milliseconds.
114    TimestampMillis(i64),
115    /// Timestamp in microseconds.
116    TimestampMicros(i64),
117    /// Timestamp in nanoseconds.
118    TimestampNanos(i64),
119    /// Local timestamp in milliseconds.
120    LocalTimestampMillis(i64),
121    /// Local timestamp in microseconds.
122    LocalTimestampMicros(i64),
123    /// Local timestamp in nanoseconds.
124    LocalTimestampNanos(i64),
125    /// Avro Duration. An amount of time defined by months, days and milliseconds.
126    Duration(Duration),
127    /// Universally unique identifier.
128    Uuid(Uuid),
129}
130
131macro_rules! to_value(
132    ($type:ty, $variant_constructor:expr) => (
133        impl From<$type> for Value {
134            fn from(value: $type) -> Self {
135                $variant_constructor(value)
136            }
137        }
138    );
139);
140
141to_value!(bool, Value::Boolean);
142to_value!(i32, Value::Int);
143to_value!(i64, Value::Long);
144to_value!(f32, Value::Float);
145to_value!(f64, Value::Double);
146to_value!(String, Value::String);
147to_value!(Vec<u8>, Value::Bytes);
148to_value!(Uuid, Value::Uuid);
149to_value!(Decimal, Value::Decimal);
150to_value!(BigDecimal, Value::BigDecimal);
151to_value!(Duration, Value::Duration);
152
153impl From<()> for Value {
154    fn from(_: ()) -> Self {
155        Self::Null
156    }
157}
158
159impl TryFrom<usize> for Value {
160    type Error = Error;
161
162    fn try_from(value: usize) -> Result<Self, Self::Error> {
163        Ok(i64::try_from(value)
164            .map_err(|e| Details::ConvertUsizeToI64(e, value))?
165            .into())
166    }
167}
168
169impl From<&str> for Value {
170    fn from(value: &str) -> Self {
171        Self::String(value.to_owned())
172    }
173}
174
175impl From<&[u8]> for Value {
176    fn from(value: &[u8]) -> Self {
177        Self::Bytes(value.to_owned())
178    }
179}
180
181impl<T> From<Option<T>> for Value
182where
183    T: Into<Self>,
184{
185    fn from(value: Option<T>) -> Self {
186        // FIXME: this is incorrect in case first type in union is not "none"
187        Self::Union(
188            value.is_some() as u32,
189            Box::new(value.map_or_else(|| Self::Null, Into::into)),
190        )
191    }
192}
193
194impl<K, V, S> From<HashMap<K, V, S>> for Value
195where
196    K: Into<String>,
197    V: Into<Self>,
198    S: BuildHasher,
199{
200    fn from(value: HashMap<K, V, S>) -> Self {
201        Self::Map(
202            value
203                .into_iter()
204                .map(|(key, value)| (key.into(), value.into()))
205                .collect(),
206        )
207    }
208}
209
210/// Utility interface to build `Value::Record` objects.
211#[derive(Debug, Clone)]
212pub struct Record<'a> {
213    /// List of fields contained in the record.
214    /// Ordered according to the fields in the schema given to create this
215    /// `Record` object. Any unset field defaults to `Value::Null`.
216    pub fields: Vec<(String, Value)>,
217    schema_lookup: &'a BTreeMap<String, usize>,
218}
219
220impl Record<'_> {
221    /// Create a `Record` given a `Schema`.
222    ///
223    /// If the `Schema` is not a `Schema::Record` variant, `None` will be returned.
224    pub fn new(schema: &Schema) -> Option<Record<'_>> {
225        match *schema {
226            Schema::Record(RecordSchema {
227                fields: ref schema_fields,
228                lookup: ref schema_lookup,
229                ..
230            }) => {
231                let mut fields = Vec::with_capacity(schema_fields.len());
232                for schema_field in schema_fields.iter() {
233                    fields.push((schema_field.name.clone(), Value::Null));
234                }
235
236                Some(Record {
237                    fields,
238                    schema_lookup,
239                })
240            }
241            _ => None,
242        }
243    }
244
245    /// Add a field to the `Record`.
246    ///
247    // TODO: This should return an error at least panic
248    /// **NOTE**: If the field name does not exist in the schema, the value is silently dropped.
249    pub fn put<V>(&mut self, field: &str, value: V)
250    where
251        V: Into<Value>,
252    {
253        if let Some(&position) = self.schema_lookup.get(field) {
254            self.fields[position].1 = value.into();
255        }
256    }
257
258    /// Get the value for a given field name.
259    ///
260    /// Returns `None` if the field is not present in the schema
261    pub fn get(&self, field: &str) -> Option<&Value> {
262        self.schema_lookup
263            .get(field)
264            .map(|&position| &self.fields[position].1)
265    }
266}
267
268impl<'a> From<Record<'a>> for Value {
269    fn from(value: Record<'a>) -> Self {
270        Self::Record(value.fields)
271    }
272}
273
274impl TryFrom<JsonValue> for Value {
275    type Error = Error;
276
277    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
278        match value {
279            JsonValue::Null => Ok(Self::Null),
280            JsonValue::Bool(b) => Ok(b.into()),
281            JsonValue::Number(ref n) if n.is_i64() => {
282                let n = n.as_i64().unwrap();
283                if n >= i32::MIN as i64 && n <= i32::MAX as i64 {
284                    Ok(Value::Int(n as i32))
285                } else {
286                    Ok(Value::Long(n))
287                }
288            }
289            JsonValue::Number(ref n) if n.is_f64() => Ok(Value::Double(n.as_f64().unwrap())),
290            JsonValue::Number(n) => Err(Details::JsonNumberTooLarge(n).into()),
291            JsonValue::String(s) => Ok(s.into()),
292            JsonValue::Array(items) => {
293                let items = items
294                    .into_iter()
295                    .map(Value::try_from)
296                    .collect::<Result<Vec<_>, _>>()?;
297                Ok(Value::Array(items))
298            }
299            JsonValue::Object(items) => {
300                let items = items
301                    .into_iter()
302                    .map(|(key, value)| Value::try_from(value).map(|v| (key, v)))
303                    .collect::<Result<HashMap<_, _>, _>>()?;
304                Ok(Value::Map(items))
305            }
306        }
307    }
308}
309
310/// Convert Avro values to Json values
311impl TryFrom<Value> for JsonValue {
312    type Error = crate::error::Error;
313    fn try_from(value: Value) -> AvroResult<Self> {
314        match value {
315            Value::Null => Ok(Self::Null),
316            Value::Boolean(b) => Ok(Self::Bool(b)),
317            Value::Int(i) => Ok(Self::Number(i.into())),
318            Value::Long(l) => Ok(Self::Number(l.into())),
319            Value::Float(f) => Number::from_f64(f.into())
320                .map(Self::Number)
321                .ok_or_else(|| Details::ConvertF64ToJson(f.into()).into()),
322            Value::Double(d) => Number::from_f64(d)
323                .map(Self::Number)
324                .ok_or_else(|| Details::ConvertF64ToJson(d).into()),
325            Value::Bytes(bytes) => Ok(Self::Array(bytes.into_iter().map(|b| b.into()).collect())),
326            Value::String(s) => Ok(Self::String(s)),
327            Value::Fixed(_size, items) => {
328                Ok(Self::Array(items.into_iter().map(|v| v.into()).collect()))
329            }
330            Value::Enum(_i, s) => Ok(Self::String(s)),
331            Value::Union(_i, b) => Self::try_from(*b),
332            Value::Array(items) => items
333                .into_iter()
334                .map(Self::try_from)
335                .collect::<Result<Vec<_>, _>>()
336                .map(Self::Array),
337            Value::Map(items) => items
338                .into_iter()
339                .map(|(key, value)| Self::try_from(value).map(|v| (key, v)))
340                .collect::<Result<Vec<_>, _>>()
341                .map(|v| Self::Object(v.into_iter().collect())),
342            Value::Record(items) => items
343                .into_iter()
344                .map(|(key, value)| Self::try_from(value).map(|v| (key, v)))
345                .collect::<Result<Vec<_>, _>>()
346                .map(|v| Self::Object(v.into_iter().collect())),
347            Value::Date(d) => Ok(Self::Number(d.into())),
348            Value::Decimal(ref d) => <Vec<u8>>::try_from(d)
349                .map(|vec| Self::Array(vec.into_iter().map(|v| v.into()).collect())),
350            Value::BigDecimal(ref bg) => {
351                let vec1: Vec<u8> = serialize_big_decimal(bg)?;
352                Ok(Self::Array(vec1.into_iter().map(|b| b.into()).collect()))
353            }
354            Value::TimeMillis(t) => Ok(Self::Number(t.into())),
355            Value::TimeMicros(t) => Ok(Self::Number(t.into())),
356            Value::TimestampMillis(t) => Ok(Self::Number(t.into())),
357            Value::TimestampMicros(t) => Ok(Self::Number(t.into())),
358            Value::TimestampNanos(t) => Ok(Self::Number(t.into())),
359            Value::LocalTimestampMillis(t) => Ok(Self::Number(t.into())),
360            Value::LocalTimestampMicros(t) => Ok(Self::Number(t.into())),
361            Value::LocalTimestampNanos(t) => Ok(Self::Number(t.into())),
362            Value::Duration(d) => Ok(Self::Array(
363                <[u8; 12]>::from(d).iter().map(|&v| v.into()).collect(),
364            )),
365            Value::Uuid(uuid) => Ok(Self::String(uuid.as_hyphenated().to_string())),
366        }
367    }
368}
369
370impl Value {
371    /// Validate the value against the given [`Schema`].
372    ///
373    /// Note: This will first build a reference map from the schema (see [`ResolvedSchema`]). If this
374    /// function is called more than once for the same schema, it is recommended to use
375    /// [`validate_with_names`](Self::validate_with_names) instead.
376    ///
377    /// See the [Avro specification](https://avro.apache.org/docs/++version++/specification)
378    /// for the full set of rules of schema validation.
379    ///
380    /// # Panics
381    /// Will panic if the schema contain unresolved references or duplicate named types.
382    pub fn validate(&self, schema: &Schema) -> bool {
383        self.validate_schemata(&[schema])
384    }
385
386    /// Validate the value against the given schemata.
387    ///
388    /// Note: This will first build a reference map from the schema (see [`ResolvedSchema`]). If this
389    /// function is called more than once for the same schema, it is recommended to use
390    /// [`validate_with_names`](Self::validate_with_names) instead.
391    ///
392    /// See the [Avro specification](https://avro.apache.org/docs/++version++/specification)
393    /// for the full set of rules of schema validation.
394    ///
395    /// # Panics
396    /// Will panic if the schemata contain unresolved references or duplicate schemas.
397    pub fn validate_schemata(&self, schemata: &[&Schema]) -> bool {
398        let rs = ResolvedSchema::try_from(schemata.to_vec())
399            .expect("Schemata didn't successfully resolve");
400        let schemata_len = schemata.len();
401        schemata.iter().any(
402            |schema| match self.validate_internal(schema, rs.get_names(), None) {
403                Some(reason) => {
404                    let log_message =
405                        format!("Invalid value: {self:?} for schema: {schema:?}. Reason: {reason}");
406                    if schemata_len == 1 {
407                        error!("{log_message}");
408                    } else {
409                        debug!("{log_message}");
410                    };
411                    false
412                }
413                None => true,
414            },
415        )
416    }
417
418    /// Validate the value against the given schema using `names` to resolve any references.
419    ///
420    /// See the [Avro specification](https://avro.apache.org/docs/++version++/specification)
421    /// for the full set of rules of schema validation.
422    pub fn validate_with_names<S: Borrow<Schema> + Debug>(
423        &self,
424        schema: &Schema,
425        names: &HashMap<Name, S>,
426    ) -> bool {
427        match self.validate_internal(schema, names, None) {
428            Some(reason) => {
429                error!("Invalid value: {self:?} for schema: {schema:?}. Reason: {reason}");
430                false
431            }
432            None => true,
433        }
434    }
435
436    fn accumulate(accumulator: Option<String>, other: Option<String>) -> Option<String> {
437        match (accumulator, other) {
438            (None, None) => None,
439            (None, s @ Some(_)) => s,
440            (s @ Some(_), None) => s,
441            (Some(reason1), Some(reason2)) => Some(format!("{reason1}\n{reason2}")),
442        }
443    }
444
445    /// Validates the value against the provided schema.
446    pub(crate) fn validate_internal<S: Borrow<Schema> + Debug>(
447        &self,
448        schema: &Schema,
449        names: &HashMap<Name, S>,
450        enclosing_namespace: NamespaceRef,
451    ) -> Option<String> {
452        match (self, schema) {
453            (_, Schema::Ref { name }) => {
454                let name = name.fully_qualified_name(enclosing_namespace);
455                names.get(&name).map_or_else(
456                    || {
457                        Some(format!(
458                            "Unresolved schema reference: '{:?}'. Parsed names: {:?}",
459                            name,
460                            names.keys()
461                        ))
462                    },
463                    |s| self.validate_internal(s.borrow(), names, name.namespace()),
464                )
465            }
466            (&Value::Null, &Schema::Null) => None,
467            (&Value::Boolean(_), &Schema::Boolean) => None,
468            (&Value::Int(_), &Schema::Int) => None,
469            (&Value::Int(_), &Schema::Date) => None,
470            (&Value::Int(_), &Schema::TimeMillis) => None,
471            (&Value::Int(_), &Schema::Long) => None,
472            (&Value::Long(_), &Schema::Long) => None,
473            (&Value::Long(_), &Schema::TimeMicros) => None,
474            (&Value::Long(_), &Schema::TimestampMillis) => None,
475            (&Value::Long(_), &Schema::TimestampMicros) => None,
476            (&Value::Long(_), &Schema::LocalTimestampMillis) => None,
477            (&Value::Long(_), &Schema::LocalTimestampMicros) => None,
478            (&Value::TimestampMicros(_), &Schema::TimestampMicros) => None,
479            (&Value::TimestampMillis(_), &Schema::TimestampMillis) => None,
480            (&Value::TimestampNanos(_), &Schema::TimestampNanos) => None,
481            (&Value::LocalTimestampMicros(_), &Schema::LocalTimestampMicros) => None,
482            (&Value::LocalTimestampMillis(_), &Schema::LocalTimestampMillis) => None,
483            (&Value::LocalTimestampNanos(_), &Schema::LocalTimestampNanos) => None,
484            (&Value::TimeMicros(_), &Schema::TimeMicros) => None,
485            (&Value::TimeMillis(_), &Schema::TimeMillis) => None,
486            (&Value::Date(_), &Schema::Date) => None,
487            (&Value::Decimal(_), &Schema::Decimal { .. }) => None,
488            (&Value::BigDecimal(_), &Schema::BigDecimal) => None,
489            (&Value::Duration(_), &Schema::Duration(_)) => None,
490            (&Value::Uuid(_), &Schema::Uuid(_)) => None,
491            (&Value::Float(_), &Schema::Float) => None,
492            (&Value::Float(_), &Schema::Double) => None,
493            (&Value::Double(_), &Schema::Double) => None,
494            (&Value::Bytes(_), &Schema::Bytes) => None,
495            (&Value::Bytes(_), &Schema::Decimal { .. }) => None,
496            (Value::Bytes(bytes), &Schema::Uuid(UuidSchema::Bytes)) => {
497                if bytes.len() != 16 {
498                    Some(format!(
499                        "The value's size ({}) is not the right length for a bytes UUID (16)",
500                        bytes.len()
501                    ))
502                } else {
503                    None
504                }
505            }
506            (&Value::String(_), &Schema::String) => None,
507            (Value::String(string), &Schema::Uuid(UuidSchema::String)) => {
508                // Non-hyphenated is 32 characters, hyphenated is longer
509                if string.len() < 32 {
510                    Some(format!(
511                        "The value's size ({}) is not the right length for a string UUID (>=32)",
512                        string.len()
513                    ))
514                } else {
515                    None
516                }
517            }
518            (&Value::Fixed(n, _), &Schema::Fixed(FixedSchema { size, .. })) => {
519                if n != size {
520                    Some(format!(
521                        "The value's size ({n}) is different than the schema's size ({size})"
522                    ))
523                } else {
524                    None
525                }
526            }
527            (Value::Bytes(b), &Schema::Fixed(FixedSchema { size, .. })) => {
528                if b.len() != size {
529                    Some(format!(
530                        "The bytes' length ({}) is different than the schema's size ({})",
531                        b.len(),
532                        size
533                    ))
534                } else {
535                    None
536                }
537            }
538            (&Value::Fixed(n, _), &Schema::Duration(_)) => {
539                if n != 12 {
540                    Some(format!(
541                        "The value's size ('{n}') must be exactly 12 to be a Duration"
542                    ))
543                } else {
544                    None
545                }
546            }
547            (&Value::Fixed(n, _), Schema::Uuid(UuidSchema::Fixed(size, ..))) => {
548                if size.size != 16 {
549                    Some(format!(
550                        "The schema's size ('{}') must be exactly 16 to be a Uuid",
551                        size.size
552                    ))
553                } else if n != 16 {
554                    Some(format!(
555                        "The value's size ('{n}') must be exactly 16 to be a Uuid"
556                    ))
557                } else {
558                    None
559                }
560            }
561            // TODO: check precision against n
562            (&Value::Fixed(_n, _), &Schema::Decimal { .. }) => None,
563            (Value::String(s), Schema::Enum(EnumSchema { symbols, .. })) => {
564                if !symbols.contains(s) {
565                    Some(format!("'{s}' is not a member of the possible symbols"))
566                } else {
567                    None
568                }
569            }
570            (
571                &Value::Enum(i, ref s),
572                Schema::Enum(EnumSchema {
573                    symbols, default, ..
574                }),
575            ) => symbols
576                .get(i as usize)
577                .map(|ref symbol| {
578                    if symbol != &s {
579                        Some(format!("Symbol '{s}' is not at position '{i}'"))
580                    } else {
581                        None
582                    }
583                })
584                .unwrap_or_else(|| match default {
585                    Some(_) => None,
586                    None => Some(format!("No symbol at position '{i}'")),
587                }),
588            // (&Value::Union(None), &Schema::Union(_)) => None,
589            (&Value::Union(i, ref value), Schema::Union(inner)) => inner
590                .variants()
591                .get(i as usize)
592                .map(|schema| value.validate_internal(schema, names, enclosing_namespace))
593                .unwrap_or_else(|| Some(format!("No schema in the union at position '{i}'"))),
594            (v, Schema::Union(inner)) => {
595                match inner.find_schema_with_known_schemata(v, Some(names), enclosing_namespace) {
596                    Some(_) => None,
597                    None => Some("Could not find matching type in union".to_string()),
598                }
599            }
600            (Value::Array(items), Schema::Array(inner)) => items.iter().fold(None, |acc, item| {
601                Value::accumulate(
602                    acc,
603                    item.validate_internal(&inner.items, names, enclosing_namespace),
604                )
605            }),
606            (Value::Map(items), Schema::Map(inner)) => {
607                items.iter().fold(None, |acc, (_, value)| {
608                    Value::accumulate(
609                        acc,
610                        value.validate_internal(&inner.types, names, enclosing_namespace),
611                    )
612                })
613            }
614            (
615                Value::Record(record_fields),
616                Schema::Record(RecordSchema {
617                    fields,
618                    lookup,
619                    name,
620                    ..
621                }),
622            ) => {
623                let non_nullable_fields_count =
624                    fields.iter().filter(|&rf| !rf.is_nullable()).count();
625
626                // If the record contains fewer fields as required fields by the schema, it is invalid.
627                if record_fields.len() < non_nullable_fields_count {
628                    return Some(format!(
629                        "The value's records length ({}) doesn't match the schema ({} non-nullable fields)",
630                        record_fields.len(),
631                        non_nullable_fields_count
632                    ));
633                } else if record_fields.len() > fields.len() {
634                    return Some(format!(
635                        "The value's records length ({}) is greater than the schema's ({} fields)",
636                        record_fields.len(),
637                        fields.len(),
638                    ));
639                }
640
641                record_fields
642                    .iter()
643                    .fold(None, |acc, (field_name, record_field)| {
644                        let record_namespace = name.namespace().or(enclosing_namespace);
645                        match lookup.get(field_name) {
646                            Some(idx) => {
647                                let field = &fields[*idx];
648                                Value::accumulate(
649                                    acc,
650                                    record_field.validate_internal(
651                                        &field.schema,
652                                        names,
653                                        record_namespace,
654                                    ),
655                                )
656                            }
657                            None => Value::accumulate(
658                                acc,
659                                Some(format!("There is no schema field for field '{field_name}'")),
660                            ),
661                        }
662                    })
663            }
664            (Value::Map(items), Schema::Record(RecordSchema { fields, .. })) => {
665                fields.iter().fold(None, |acc, field| {
666                    if let Some(item) = items.get(&field.name) {
667                        let res = item.validate_internal(&field.schema, names, enclosing_namespace);
668                        Value::accumulate(acc, res)
669                    } else if !field.is_nullable() {
670                        Value::accumulate(
671                            acc,
672                            Some(format!(
673                                "Field with name '{:?}' is not a member of the map items",
674                                field.name
675                            )),
676                        )
677                    } else {
678                        acc
679                    }
680                })
681            }
682            (v, s) => Some(format!(
683                "Unsupported value-schema combination! Value: {v:?}, schema: {s:?}"
684            )),
685        }
686    }
687
688    /// Resolve this value into a new schema.
689    ///
690    /// Note: This will first build a reference map from the schema (see [`ResolvedSchema`]). If this
691    /// function is called more than once for the same schema, it is recommended to use
692    /// [`resolve_with_names`](Self::resolve_with_names) instead.
693    ///
694    /// See [Schema Resolution](https://avro.apache.org/docs/++version++/specification/#schema-resolution)
695    /// in the Avro specification for the full set of rules of schema resolution.
696    pub fn resolve(self, schema: &Schema) -> AvroResult<Self> {
697        self.resolve_schemata(schema, Vec::with_capacity(0))
698    }
699
700    /// Resolve this value into a new schema using `schemata` to resolve any references.
701    ///
702    /// `schemata` must contain all referenced schemas in `schema`, including references to parts of
703    /// `schema` itself.
704    ///
705    /// Note: This will first build a reference map from the schema (see [`ResolvedSchema`]). If this
706    /// function is called more than once for the same schema, it is recommended to use
707    /// [`resolve_with_names`](Self::resolve_with_names) instead.
708    ///
709    /// See [Schema Resolution](https://avro.apache.org/docs/++version++/specification/#schema-resolution)
710    /// in the Avro specification for the full set of rules of schema resolution.
711    pub fn resolve_schemata(self, schema: &Schema, schemata: Vec<&Schema>) -> AvroResult<Self> {
712        let rs = if schemata.is_empty() {
713            ResolvedSchema::try_from(schema)?
714        } else {
715            ResolvedSchema::try_from(schemata)?
716        };
717        self.resolve_internal(schema, rs.get_names(), None, None)
718    }
719
720    /// Resolve this value into a new schema using `names` to resolve any references.
721    ///
722    /// See [Schema Resolution](https://avro.apache.org/docs/++version++/specification/#schema-resolution)
723    /// in the Avro specification for the full set of rules of schema resolution.
724    ///
725    /// # Example
726    /// ```
727    /// # use apache_avro::{types::Value, Error, Schema, schema::ResolvedSchema};
728    /// # let values: [Value; 0] = [];
729    /// # let schema = Schema::Null;
730    /// let resolved_schema = ResolvedSchema::new(&schema)?;
731    ///
732    /// for value in values {
733    ///     let resolved = value.resolve_with_names(&schema, resolved_schema.get_names())?;
734    ///     // Do something with the resolved value
735    /// }
736    /// # Ok::<(), Error>(())
737    /// ```
738    pub fn resolve_with_names<S: Borrow<Schema> + Debug>(
739        self,
740        schema: &Schema,
741        names: &HashMap<Name, S>,
742    ) -> AvroResult<Self> {
743        self.resolve_internal(schema, names, None, None)
744    }
745
746    pub(crate) fn resolve_internal<S: Borrow<Schema> + Debug>(
747        mut self,
748        schema: &Schema,
749        names: &HashMap<Name, S>,
750        enclosing_namespace: NamespaceRef,
751        field_default: Option<&JsonValue>,
752    ) -> AvroResult<Self> {
753        // Check if this schema is a union, and if the reader schema is not.
754        if SchemaKind::from(&self) == SchemaKind::Union
755            && SchemaKind::from(schema) != SchemaKind::Union
756        {
757            // Pull out the Union, and attempt to resolve against it.
758            let v = match self {
759                Value::Union(_i, b) => *b,
760                _ => unreachable!(),
761            };
762            self = v;
763        }
764        match schema {
765            Schema::Ref { name } => {
766                let name = name.fully_qualified_name(enclosing_namespace);
767
768                if let Some(resolved) = names.get(&name) {
769                    debug!("Resolved {name:?}");
770                    self.resolve_internal(resolved.borrow(), names, name.namespace(), field_default)
771                } else {
772                    error!("Failed to resolve schema {name:?}");
773                    Err(Details::SchemaResolutionError(name.into_owned()).into())
774                }
775            }
776            Schema::Null => self.resolve_null(),
777            Schema::Boolean => self.resolve_boolean(),
778            Schema::Int => self.resolve_int(),
779            Schema::Long => self.resolve_long(),
780            Schema::Float => self.resolve_float(),
781            Schema::Double => self.resolve_double(),
782            Schema::Bytes => self.resolve_bytes(),
783            Schema::String => self.resolve_string(),
784            Schema::Fixed(FixedSchema { size, .. }) => self.resolve_fixed(*size),
785            Schema::Union(inner) => {
786                self.resolve_union(inner, names, enclosing_namespace, field_default)
787            }
788            Schema::Enum(EnumSchema {
789                symbols, default, ..
790            }) => self.resolve_enum(symbols, default, field_default),
791            Schema::Array(inner) => self.resolve_array(&inner.items, names, enclosing_namespace),
792            Schema::Map(inner) => self.resolve_map(&inner.types, names, enclosing_namespace),
793            Schema::Record(RecordSchema { fields, name, .. }) => {
794                self.resolve_record(fields, names, name.namespace().or(enclosing_namespace))
795            }
796            Schema::Decimal(DecimalSchema {
797                scale,
798                precision,
799                inner,
800            }) => self.resolve_decimal(*precision, *scale, inner),
801            Schema::BigDecimal => self.resolve_bigdecimal(),
802            Schema::Date => self.resolve_date(),
803            Schema::TimeMillis => self.resolve_time_millis(),
804            Schema::TimeMicros => self.resolve_time_micros(),
805            Schema::TimestampMillis => self.resolve_timestamp_millis(),
806            Schema::TimestampMicros => self.resolve_timestamp_micros(),
807            Schema::TimestampNanos => self.resolve_timestamp_nanos(),
808            Schema::LocalTimestampMillis => self.resolve_local_timestamp_millis(),
809            Schema::LocalTimestampMicros => self.resolve_local_timestamp_micros(),
810            Schema::LocalTimestampNanos => self.resolve_local_timestamp_nanos(),
811            Schema::Duration(_) => self.resolve_duration(),
812            Schema::Uuid(inner) => self.resolve_uuid(inner),
813        }
814    }
815
816    fn resolve_uuid(self, inner: &UuidSchema) -> Result<Self, Error> {
817        let value = match (self, inner) {
818            (uuid @ Value::Uuid(_), _) => uuid,
819            (Value::String(ref string), UuidSchema::String) => {
820                Value::Uuid(Uuid::from_str(string).map_err(Details::ConvertStrToUuid)?)
821            }
822            (Value::Bytes(ref bytes), UuidSchema::Bytes) => {
823                Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
824            }
825            (Value::Fixed(n, ref bytes), UuidSchema::Fixed(_)) => {
826                if n != 16 {
827                    return Err(Details::ConvertFixedToUuid(n).into());
828                }
829                Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
830            }
831            (Value::String(ref string), UuidSchema::Fixed(_)) => {
832                let bytes = string.as_bytes();
833                if bytes.len() != 16 {
834                    return Err(Details::ConvertFixedToUuid(bytes.len()).into());
835                }
836                Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
837            }
838            (other, _) => return Err(Details::GetUuid(other).into()),
839        };
840        Ok(value)
841    }
842
843    fn resolve_bigdecimal(self) -> Result<Self, Error> {
844        Ok(match self {
845            bg @ Value::BigDecimal(_) => bg,
846            Value::Bytes(b) => Value::BigDecimal(deserialize_big_decimal(&b)?),
847            other => return Err(Details::GetBigDecimal(other).into()),
848        })
849    }
850
851    fn resolve_duration(self) -> Result<Self, Error> {
852        Ok(match self {
853            duration @ Value::Duration { .. } => duration,
854            Value::Fixed(size, bytes) => {
855                if size != 12 {
856                    return Err(Details::GetDurationFixedBytes(size).into());
857                }
858                Value::Duration(Duration::from([
859                    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
860                    bytes[8], bytes[9], bytes[10], bytes[11],
861                ]))
862            }
863            other => return Err(Details::ResolveDuration(other).into()),
864        })
865    }
866
867    fn resolve_decimal(
868        self,
869        precision: Precision,
870        scale: Scale,
871        inner: &InnerDecimalSchema,
872    ) -> Result<Self, Error> {
873        if scale > precision {
874            return Err(Details::GetScaleAndPrecision { scale, precision }.into());
875        }
876        match inner {
877            &InnerDecimalSchema::Fixed(FixedSchema { size, .. }) => {
878                if max_prec_for_len(size)? < precision {
879                    return Err(Details::GetScaleWithFixedSize { size, precision }.into());
880                }
881            }
882            InnerDecimalSchema::Bytes => (),
883        };
884        match self {
885            Value::Decimal(num) => {
886                let num_bytes = num.len();
887                if max_prec_for_len(num_bytes)? < precision {
888                    Err(Details::ComparePrecisionAndSize {
889                        precision,
890                        num_bytes,
891                    }
892                    .into())
893                } else {
894                    Ok(Value::Decimal(num))
895                }
896                // check num.bits() here
897            }
898            Value::Fixed(_, bytes) | Value::Bytes(bytes) => {
899                if max_prec_for_len(bytes.len())? < precision {
900                    Err(Details::ComparePrecisionAndSize {
901                        precision,
902                        num_bytes: bytes.len(),
903                    }
904                    .into())
905                } else {
906                    // precision and scale match, can we assume the underlying type can hold the data?
907                    Ok(Value::Decimal(Decimal::from(bytes)))
908                }
909            }
910
911            // Per spec §Records, a decimal value can be encoded as a JSON string
912            // whose codepoints (0-255) map directly to byte values. This applies
913            // to defaults and any other String → Decimal resolution. No precision
914            // check is performed — the bytes only need to be valid, not fit the
915            // declared precision.
916            Value::String(s) => {
917                let bytes = s
918                    .chars()
919                    .map(|c| {
920                        let cp = c as u32;
921                        if cp > 0xFF {
922                            Err(Details::ResolveDecimal(Value::String(s.clone())).into())
923                        } else {
924                            Ok(cp as u8)
925                        }
926                    })
927                    .collect::<Result<Vec<u8>, Error>>()?;
928                Ok(Value::Decimal(Decimal::from(bytes)))
929            }
930            other => Err(Details::ResolveDecimal(other).into()),
931        }
932    }
933
934    fn resolve_date(self) -> Result<Self, Error> {
935        match self {
936            Value::Date(d) | Value::Int(d) => Ok(Value::Date(d)),
937            other => Err(Details::GetDate(other).into()),
938        }
939    }
940
941    fn resolve_time_millis(self) -> Result<Self, Error> {
942        match self {
943            Value::TimeMillis(t) | Value::Int(t) => Ok(Value::TimeMillis(t)),
944            other => Err(Details::GetTimeMillis(other).into()),
945        }
946    }
947
948    fn resolve_time_micros(self) -> Result<Self, Error> {
949        match self {
950            Value::TimeMicros(t) | Value::Long(t) => Ok(Value::TimeMicros(t)),
951            Value::Int(t) => Ok(Value::TimeMicros(i64::from(t))),
952            other => Err(Details::GetTimeMicros(other).into()),
953        }
954    }
955
956    fn resolve_timestamp_millis(self) -> Result<Self, Error> {
957        match self {
958            Value::TimestampMillis(ts) | Value::Long(ts) => Ok(Value::TimestampMillis(ts)),
959            Value::Int(ts) => Ok(Value::TimestampMillis(i64::from(ts))),
960            other => Err(Details::GetTimestampMillis(other).into()),
961        }
962    }
963
964    fn resolve_timestamp_micros(self) -> Result<Self, Error> {
965        match self {
966            Value::TimestampMicros(ts) | Value::Long(ts) => Ok(Value::TimestampMicros(ts)),
967            Value::Int(ts) => Ok(Value::TimestampMicros(i64::from(ts))),
968            other => Err(Details::GetTimestampMicros(other).into()),
969        }
970    }
971
972    fn resolve_timestamp_nanos(self) -> Result<Self, Error> {
973        match self {
974            Value::TimestampNanos(ts) | Value::Long(ts) => Ok(Value::TimestampNanos(ts)),
975            Value::Int(ts) => Ok(Value::TimestampNanos(i64::from(ts))),
976            other => Err(Details::GetTimestampNanos(other).into()),
977        }
978    }
979
980    fn resolve_local_timestamp_millis(self) -> Result<Self, Error> {
981        match self {
982            Value::LocalTimestampMillis(ts) | Value::Long(ts) => {
983                Ok(Value::LocalTimestampMillis(ts))
984            }
985            Value::Int(ts) => Ok(Value::LocalTimestampMillis(i64::from(ts))),
986            other => Err(Details::GetLocalTimestampMillis(other).into()),
987        }
988    }
989
990    fn resolve_local_timestamp_micros(self) -> Result<Self, Error> {
991        match self {
992            Value::LocalTimestampMicros(ts) | Value::Long(ts) => {
993                Ok(Value::LocalTimestampMicros(ts))
994            }
995            Value::Int(ts) => Ok(Value::LocalTimestampMicros(i64::from(ts))),
996            other => Err(Details::GetLocalTimestampMicros(other).into()),
997        }
998    }
999
1000    fn resolve_local_timestamp_nanos(self) -> Result<Self, Error> {
1001        match self {
1002            Value::LocalTimestampNanos(ts) | Value::Long(ts) => Ok(Value::LocalTimestampNanos(ts)),
1003            Value::Int(ts) => Ok(Value::LocalTimestampNanos(i64::from(ts))),
1004            other => Err(Details::GetLocalTimestampNanos(other).into()),
1005        }
1006    }
1007
1008    fn resolve_null(self) -> Result<Self, Error> {
1009        match self {
1010            Value::Null => Ok(Value::Null),
1011            other => Err(Details::GetNull(other).into()),
1012        }
1013    }
1014
1015    fn resolve_boolean(self) -> Result<Self, Error> {
1016        match self {
1017            Value::Boolean(b) => Ok(Value::Boolean(b)),
1018            other => Err(Details::GetBoolean(other).into()),
1019        }
1020    }
1021
1022    fn resolve_int(self) -> Result<Self, Error> {
1023        match self {
1024            Value::Int(n) => Ok(Value::Int(n)),
1025            Value::Long(n) => {
1026                let n = i32::try_from(n).map_err(|e| Details::ZagI32(e, n))?;
1027                Ok(Value::Int(n))
1028            }
1029            other => Err(Details::GetInt(other).into()),
1030        }
1031    }
1032
1033    fn resolve_long(self) -> Result<Self, Error> {
1034        match self {
1035            Value::Int(n) => Ok(Value::Long(i64::from(n))),
1036            Value::Long(n) => Ok(Value::Long(n)),
1037            other => Err(Details::GetLong(other).into()),
1038        }
1039    }
1040
1041    fn resolve_float(self) -> Result<Self, Error> {
1042        match self {
1043            Value::Int(n) => Ok(Value::Float(n as f32)),
1044            Value::Long(n) => Ok(Value::Float(n as f32)),
1045            Value::Float(x) => Ok(Value::Float(x)),
1046            Value::Double(x) => Ok(Value::Float(x as f32)),
1047            Value::String(ref x) => match Self::parse_special_float(x) {
1048                Some(f) => Ok(Value::Float(f)),
1049                None => Err(Details::GetFloat(self).into()),
1050            },
1051            other => Err(Details::GetFloat(other).into()),
1052        }
1053    }
1054
1055    fn resolve_double(self) -> Result<Self, Error> {
1056        match self {
1057            Value::Int(n) => Ok(Value::Double(f64::from(n))),
1058            Value::Long(n) => Ok(Value::Double(n as f64)),
1059            Value::Float(x) => Ok(Value::Double(f64::from(x))),
1060            Value::Double(x) => Ok(Value::Double(x)),
1061            Value::String(ref x) => match Self::parse_special_float(x) {
1062                Some(f) => Ok(Value::Double(f64::from(f))),
1063                None => Err(Details::GetDouble(self).into()),
1064            },
1065            other => Err(Details::GetDouble(other).into()),
1066        }
1067    }
1068
1069    /// IEEE 754 NaN and infinities are not valid JSON numbers.
1070    /// So they are represented in JSON as strings.
1071    fn parse_special_float(value: &str) -> Option<f32> {
1072        match value {
1073            "NaN" => Some(f32::NAN),
1074            "INF" | "Infinity" => Some(f32::INFINITY),
1075            "-INF" | "-Infinity" => Some(f32::NEG_INFINITY),
1076            _ => None,
1077        }
1078    }
1079
1080    fn resolve_bytes(self) -> Result<Self, Error> {
1081        match self {
1082            Value::Bytes(bytes) => Ok(Value::Bytes(bytes)),
1083            Value::String(s) => Ok(Value::Bytes(s.into_bytes())),
1084            Value::Array(items) => Ok(Value::Bytes(
1085                items
1086                    .into_iter()
1087                    .map(Value::try_u8)
1088                    .collect::<Result<Vec<_>, _>>()?,
1089            )),
1090            other => Err(Details::GetBytes(other).into()),
1091        }
1092    }
1093
1094    fn resolve_string(self) -> Result<Self, Error> {
1095        match self {
1096            Value::String(s) => Ok(Value::String(s)),
1097            Value::Bytes(bytes) | Value::Fixed(_, bytes) => Ok(Value::String(
1098                String::from_utf8(bytes).map_err(Details::ConvertToUtf8)?,
1099            )),
1100            other => Err(Details::GetString(other).into()),
1101        }
1102    }
1103
1104    fn resolve_fixed(self, size: usize) -> Result<Self, Error> {
1105        match self {
1106            Value::Fixed(n, bytes) => {
1107                if n == size {
1108                    Ok(Value::Fixed(n, bytes))
1109                } else {
1110                    Err(Details::CompareFixedSizes { size, n }.into())
1111                }
1112            }
1113            Value::String(s) => Ok(Value::Fixed(s.len(), s.into_bytes())),
1114            Value::Bytes(s) => {
1115                if s.len() == size {
1116                    Ok(Value::Fixed(size, s))
1117                } else {
1118                    Err(Details::CompareFixedSizes { size, n: s.len() }.into())
1119                }
1120            }
1121            other => Err(Details::GetStringForFixed(other).into()),
1122        }
1123    }
1124
1125    pub(crate) fn resolve_enum(
1126        self,
1127        symbols: &[String],
1128        enum_default: &Option<String>,
1129        _field_default: Option<&JsonValue>,
1130    ) -> Result<Self, Error> {
1131        let validate_symbol = |symbol: String, symbols: &[String]| {
1132            if let Some(index) = symbols.iter().position(|item| item == &symbol) {
1133                Ok(Value::Enum(index as u32, symbol))
1134            } else {
1135                match enum_default {
1136                    Some(default) => {
1137                        if let Some(index) = symbols.iter().position(|item| item == default) {
1138                            Ok(Value::Enum(index as u32, default.clone()))
1139                        } else {
1140                            Err(Details::GetEnumDefault {
1141                                symbol,
1142                                symbols: symbols.into(),
1143                            }
1144                            .into())
1145                        }
1146                    }
1147                    _ => Err(Details::GetEnumDefault {
1148                        symbol,
1149                        symbols: symbols.into(),
1150                    }
1151                    .into()),
1152                }
1153            }
1154        };
1155
1156        match self {
1157            Value::Enum(_raw_index, s) => validate_symbol(s, symbols),
1158            Value::String(s) => validate_symbol(s, symbols),
1159            other => Err(Details::GetEnum(other).into()),
1160        }
1161    }
1162
1163    fn resolve_union<S: Borrow<Schema> + Debug>(
1164        self,
1165        schema: &UnionSchema,
1166        names: &HashMap<Name, S>,
1167        enclosing_namespace: NamespaceRef,
1168        field_default: Option<&JsonValue>,
1169    ) -> Result<Self, Error> {
1170        let v = match self {
1171            // Both are unions case.
1172            Value::Union(_i, v) => *v,
1173            // Reader is a union, but writer is not.
1174            v => v,
1175        };
1176        let (i, inner) = schema
1177            .find_schema_with_known_schemata(&v, Some(names), enclosing_namespace)
1178            .ok_or_else(|| Details::FindUnionVariant {
1179                schema: schema.clone(),
1180                value: v.clone(),
1181            })?;
1182
1183        Ok(Value::Union(
1184            i as u32,
1185            Box::new(v.resolve_internal(inner, names, enclosing_namespace, field_default)?),
1186        ))
1187    }
1188
1189    fn resolve_array<S: Borrow<Schema> + Debug>(
1190        self,
1191        schema: &Schema,
1192        names: &HashMap<Name, S>,
1193        enclosing_namespace: NamespaceRef,
1194    ) -> Result<Self, Error> {
1195        match self {
1196            Value::Array(items) => Ok(Value::Array(
1197                items
1198                    .into_iter()
1199                    .map(|item| item.resolve_internal(schema, names, enclosing_namespace, None))
1200                    .collect::<Result<_, _>>()?,
1201            )),
1202            other => Err(Details::GetArray {
1203                expected: schema.into(),
1204                other,
1205            }
1206            .into()),
1207        }
1208    }
1209
1210    fn resolve_map<S: Borrow<Schema> + Debug>(
1211        self,
1212        schema: &Schema,
1213        names: &HashMap<Name, S>,
1214        enclosing_namespace: NamespaceRef,
1215    ) -> Result<Self, Error> {
1216        match self {
1217            Value::Map(items) => Ok(Value::Map(
1218                items
1219                    .into_iter()
1220                    .map(|(key, value)| {
1221                        value
1222                            .resolve_internal(schema, names, enclosing_namespace, None)
1223                            .map(|value| (key, value))
1224                    })
1225                    .collect::<Result<_, _>>()?,
1226            )),
1227            other => Err(Details::GetMap {
1228                expected: schema.into(),
1229                other,
1230            }
1231            .into()),
1232        }
1233    }
1234
1235    fn resolve_record<S: Borrow<Schema> + Debug>(
1236        self,
1237        fields: &[RecordField],
1238        names: &HashMap<Name, S>,
1239        enclosing_namespace: NamespaceRef,
1240    ) -> Result<Self, Error> {
1241        let mut items = match self {
1242            Value::Map(items) => Ok(items),
1243            Value::Record(fields) => Ok(fields.into_iter().collect::<HashMap<_, _>>()),
1244            other => Err(Error::new(Details::GetRecord {
1245                expected: fields
1246                    .iter()
1247                    .map(|field| (field.name.clone(), field.schema.clone().into()))
1248                    .collect(),
1249                other,
1250            })),
1251        }?;
1252
1253        let new_fields = fields
1254            .iter()
1255            .map(|field| {
1256                let value = match items.remove(&field.name) {
1257                    Some(value) => value,
1258                    None => match field.default {
1259                        Some(ref value) => match field.schema {
1260                            Schema::Enum(EnumSchema {
1261                                ref symbols,
1262                                ref default,
1263                                ..
1264                            }) => Value::try_from(value.clone())?.resolve_enum(
1265                                symbols,
1266                                default,
1267                                field.default.as_ref(),
1268                            )?,
1269                            Schema::Union(ref union_schema) => {
1270                                let first = &union_schema.variants()[0];
1271                                // NOTE: this match exists only to optimize null defaults for large
1272                                // backward-compatible schemas with many nullable fields
1273                                match first {
1274                                    Schema::Null => Value::Union(0, Box::new(Value::Null)),
1275                                    _ => Value::Union(
1276                                        0,
1277                                        Box::new(
1278                                            Value::try_from(value.clone())?.resolve_internal(
1279                                                first,
1280                                                names,
1281                                                enclosing_namespace,
1282                                                field.default.as_ref(),
1283                                            )?,
1284                                        ),
1285                                    ),
1286                                }
1287                            }
1288                            _ => Value::try_from(value.clone())?,
1289                        },
1290                        None => {
1291                            return Err(Details::GetField(field.name.clone()).into());
1292                        }
1293                    },
1294                };
1295                value
1296                    .resolve_internal(
1297                        &field.schema,
1298                        names,
1299                        enclosing_namespace,
1300                        field.default.as_ref(),
1301                    )
1302                    .map(|value| (field.name.clone(), value))
1303            })
1304            .collect::<Result<Vec<_>, _>>()?;
1305
1306        Ok(Value::Record(new_fields))
1307    }
1308
1309    fn try_u8(self) -> AvroResult<u8> {
1310        let int = self.resolve(&Schema::Int)?;
1311        if let Value::Int(n) = int
1312            && n >= 0
1313            && n <= i32::from(u8::MAX)
1314        {
1315            return Ok(n as u8);
1316        }
1317
1318        Err(Details::GetU8(int).into())
1319    }
1320}
1321
1322#[cfg(test)]
1323mod tests {
1324    use super::*;
1325    use crate::{
1326        duration::{Days, Millis, Months},
1327        error::Details,
1328        to_value,
1329    };
1330    use apache_avro_test_helper::{
1331        TestResult,
1332        logger::{assert_logged, assert_not_logged},
1333    };
1334    use num_bigint::BigInt;
1335    use pretty_assertions::assert_eq;
1336    use serde_json::json;
1337
1338    #[test]
1339    fn avro_3809_validate_nested_records_with_implicit_namespace() -> TestResult {
1340        let schema = Schema::parse_str(
1341            r#"{
1342            "name": "record_name",
1343            "namespace": "space",
1344            "type": "record",
1345            "fields": [
1346              {
1347                "name": "outer_field_1",
1348                "type": {
1349                  "type": "record",
1350                  "name": "middle_record_name",
1351                  "namespace": "middle_namespace",
1352                  "fields": [
1353                    {
1354                      "name": "middle_field_1",
1355                      "type": {
1356                        "type": "record",
1357                        "name": "inner_record_name",
1358                        "fields": [
1359                          { "name": "inner_field_1", "type": "double" }
1360                        ]
1361                      }
1362                    },
1363                    { "name": "middle_field_2", "type": "inner_record_name" }
1364                  ]
1365                }
1366              }
1367            ]
1368          }"#,
1369        )?;
1370        let value = Value::Record(vec![(
1371            "outer_field_1".into(),
1372            Value::Record(vec![
1373                (
1374                    "middle_field_1".into(),
1375                    Value::Record(vec![("inner_field_1".into(), Value::Double(1.2f64))]),
1376                ),
1377                (
1378                    "middle_field_2".into(),
1379                    Value::Record(vec![("inner_field_1".into(), Value::Double(1.6f64))]),
1380                ),
1381            ]),
1382        )]);
1383
1384        assert!(value.validate(&schema));
1385        Ok(())
1386    }
1387
1388    #[test]
1389    fn validate() -> TestResult {
1390        let value_schema_valid = vec![
1391            (Value::Int(42), Schema::Int, true, ""),
1392            (Value::Int(43), Schema::Long, true, ""),
1393            (Value::Float(43.2), Schema::Float, true, ""),
1394            (Value::Float(45.9), Schema::Double, true, ""),
1395            (
1396                Value::Int(42),
1397                Schema::Boolean,
1398                false,
1399                "Invalid value: Int(42) for schema: Boolean. Reason: Unsupported value-schema combination! Value: Int(42), schema: Boolean",
1400            ),
1401            (
1402                Value::Union(0, Box::new(Value::Null)),
1403                Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1404                true,
1405                "",
1406            ),
1407            (
1408                Value::Union(1, Box::new(Value::Int(42))),
1409                Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1410                true,
1411                "",
1412            ),
1413            (
1414                Value::Union(0, Box::new(Value::Null)),
1415                Schema::Union(UnionSchema::new(vec![Schema::Double, Schema::Int])?),
1416                false,
1417                "Invalid value: Union(0, Null) for schema: Union(UnionSchema { schemas: [Double, Int] }). Reason: Unsupported value-schema combination! Value: Null, schema: Double",
1418            ),
1419            (
1420                Value::Union(3, Box::new(Value::Int(42))),
1421                Schema::Union(UnionSchema::new(vec![
1422                    Schema::Null,
1423                    Schema::Double,
1424                    Schema::String,
1425                    Schema::Int,
1426                ])?),
1427                true,
1428                "",
1429            ),
1430            (
1431                Value::Union(1, Box::new(Value::Long(42i64))),
1432                Schema::Union(UnionSchema::new(vec![
1433                    Schema::Null,
1434                    Schema::TimestampMillis,
1435                ])?),
1436                true,
1437                "",
1438            ),
1439            (
1440                Value::Union(2, Box::new(Value::Long(1_i64))),
1441                Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1442                false,
1443                "Invalid value: Union(2, Long(1)) for schema: Union(UnionSchema { schemas: [Null, Int] }). Reason: No schema in the union at position '2'",
1444            ),
1445            (
1446                Value::Array(vec![Value::Long(42i64)]),
1447                Schema::array(Schema::Long).build(),
1448                true,
1449                "",
1450            ),
1451            (
1452                Value::Array(vec![Value::Boolean(true)]),
1453                Schema::array(Schema::Long).build(),
1454                false,
1455                "Invalid value: Array([Boolean(true)]) for schema: Array(ArraySchema { items: Long, .. }). Reason: Unsupported value-schema combination! Value: Boolean(true), schema: Long",
1456            ),
1457            (
1458                Value::Record(vec![]),
1459                Schema::Null,
1460                false,
1461                "Invalid value: Record([]) for schema: Null. Reason: Unsupported value-schema combination! Value: Record([]), schema: Null",
1462            ),
1463            (
1464                Value::Fixed(12, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]),
1465                Schema::Duration(FixedSchema {
1466                    name: Name::try_from("TestName")?,
1467                    aliases: None,
1468                    doc: None,
1469                    size: 12,
1470                    attributes: BTreeMap::new(),
1471                }),
1472                true,
1473                "",
1474            ),
1475            (
1476                Value::Fixed(11, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
1477                Schema::Duration(FixedSchema {
1478                    name: Name::try_from("TestName")?,
1479                    aliases: None,
1480                    doc: None,
1481                    size: 12,
1482                    attributes: BTreeMap::new(),
1483                }),
1484                false,
1485                r#"Invalid value: Fixed(11, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) for schema: Duration(FixedSchema { name: Name { name: "TestName", .. }, size: 12, .. }). Reason: The value's size ('11') must be exactly 12 to be a Duration"#,
1486            ),
1487            (
1488                Value::Record(vec![("unknown_field_name".to_string(), Value::Null)]),
1489                Schema::Record(RecordSchema {
1490                    name: Name::new("record_name")?,
1491                    aliases: None,
1492                    doc: None,
1493                    fields: vec![
1494                        RecordField::builder()
1495                            .name("field_name".to_string())
1496                            .schema(Schema::Int)
1497                            .build(),
1498                    ],
1499                    lookup: Default::default(),
1500                    attributes: Default::default(),
1501                }),
1502                false,
1503                r#"Invalid value: Record([("unknown_field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", .. }, fields: [RecordField { name: "field_name", schema: Int, .. }], .. }). Reason: There is no schema field for field 'unknown_field_name'"#,
1504            ),
1505            (
1506                Value::Record(vec![("field_name".to_string(), Value::Null)]),
1507                Schema::Record(RecordSchema {
1508                    name: Name::new("record_name")?,
1509                    aliases: None,
1510                    doc: None,
1511                    fields: vec![
1512                        RecordField::builder()
1513                            .name("field_name".to_string())
1514                            .schema(Schema::Ref {
1515                                name: Name::new("missing")?,
1516                            })
1517                            .build(),
1518                    ],
1519                    lookup: [("field_name".to_string(), 0)].iter().cloned().collect(),
1520                    attributes: Default::default(),
1521                }),
1522                false,
1523                r#"Invalid value: Record([("field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", .. }, fields: [RecordField { name: "field_name", schema: Ref { name: Name { name: "missing", .. } }, .. }], .. }). Reason: Unresolved schema reference: 'Name { name: "missing", .. }'. Parsed names: []"#,
1524            ),
1525        ];
1526
1527        for (value, schema, valid, expected_err_message) in value_schema_valid.into_iter() {
1528            let err_message = value.validate_internal::<Schema>(&schema, &HashMap::default(), None);
1529            assert_eq!(valid, err_message.is_none());
1530            if !valid {
1531                let full_err_message = format!(
1532                    "Invalid value: {:?} for schema: {:?}. Reason: {}",
1533                    value,
1534                    schema,
1535                    err_message.unwrap()
1536                );
1537                assert_eq!(expected_err_message, full_err_message);
1538            }
1539        }
1540
1541        Ok(())
1542    }
1543
1544    #[test]
1545    fn validate_fixed() -> TestResult {
1546        let schema = Schema::Fixed(FixedSchema {
1547            size: 4,
1548            name: Name::new("some_fixed")?,
1549            aliases: None,
1550            doc: None,
1551            attributes: Default::default(),
1552        });
1553
1554        assert!(Value::Fixed(4, vec![0, 0, 0, 0]).validate(&schema));
1555        let value = Value::Fixed(5, vec![0, 0, 0, 0, 0]);
1556        assert!(!value.validate(&schema));
1557        assert_logged(
1558            format!(
1559                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1560                value, schema, "The value's size (5) is different than the schema's size (4)"
1561            )
1562            .as_str(),
1563        );
1564
1565        assert!(Value::Bytes(vec![0, 0, 0, 0]).validate(&schema));
1566        let value = Value::Bytes(vec![0, 0, 0, 0, 0]);
1567        assert!(!value.validate(&schema));
1568        assert_logged(
1569            format!(
1570                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1571                value, schema, "The bytes' length (5) is different than the schema's size (4)"
1572            )
1573            .as_str(),
1574        );
1575
1576        Ok(())
1577    }
1578
1579    #[test]
1580    fn validate_enum() -> TestResult {
1581        let schema = Schema::Enum(EnumSchema {
1582            name: Name::new("some_enum")?,
1583            aliases: None,
1584            doc: None,
1585            symbols: vec![
1586                "spades".to_string(),
1587                "hearts".to_string(),
1588                "diamonds".to_string(),
1589                "clubs".to_string(),
1590            ],
1591            default: None,
1592            attributes: Default::default(),
1593        });
1594
1595        assert!(Value::Enum(0, "spades".to_string()).validate(&schema));
1596        assert!(Value::String("spades".to_string()).validate(&schema));
1597
1598        let value = Value::Enum(1, "spades".to_string());
1599        assert!(!value.validate(&schema));
1600        assert_logged(
1601            format!(
1602                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1603                value, schema, "Symbol 'spades' is not at position '1'"
1604            )
1605            .as_str(),
1606        );
1607
1608        let value = Value::Enum(1000, "spades".to_string());
1609        assert!(!value.validate(&schema));
1610        assert_logged(
1611            format!(
1612                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1613                value, schema, "No symbol at position '1000'"
1614            )
1615            .as_str(),
1616        );
1617
1618        let value = Value::String("lorem".to_string());
1619        assert!(!value.validate(&schema));
1620        assert_logged(
1621            format!(
1622                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1623                value, schema, "'lorem' is not a member of the possible symbols"
1624            )
1625            .as_str(),
1626        );
1627
1628        let other_schema = Schema::Enum(EnumSchema {
1629            name: Name::new("some_other_enum")?,
1630            aliases: None,
1631            doc: None,
1632            symbols: vec![
1633                "hearts".to_string(),
1634                "diamonds".to_string(),
1635                "clubs".to_string(),
1636                "spades".to_string(),
1637            ],
1638            default: None,
1639            attributes: Default::default(),
1640        });
1641
1642        let value = Value::Enum(0, "spades".to_string());
1643        assert!(!value.validate(&other_schema));
1644        assert_logged(
1645            format!(
1646                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1647                value, other_schema, "Symbol 'spades' is not at position '0'"
1648            )
1649            .as_str(),
1650        );
1651
1652        Ok(())
1653    }
1654
1655    #[test]
1656    fn validate_record() -> TestResult {
1657        // {
1658        //    "type": "record",
1659        //    "fields": [
1660        //      {"type": "long", "name": "a"},
1661        //      {"type": "string", "name": "b"},
1662        //      {
1663        //          "type": ["null", "int"]
1664        //          "name": "c",
1665        //          "default": null
1666        //      }
1667        //    ]
1668        // }
1669        let schema = Schema::Record(RecordSchema {
1670            name: Name::new("some_record")?,
1671            aliases: None,
1672            doc: None,
1673            fields: vec![
1674                RecordField::builder()
1675                    .name("a".to_string())
1676                    .schema(Schema::Long)
1677                    .build(),
1678                RecordField::builder()
1679                    .name("b".to_string())
1680                    .schema(Schema::String)
1681                    .build(),
1682                RecordField::builder()
1683                    .name("c".to_string())
1684                    .default(JsonValue::Null)
1685                    .schema(Schema::Union(UnionSchema::new(vec![
1686                        Schema::Null,
1687                        Schema::Int,
1688                    ])?))
1689                    .build(),
1690            ],
1691            lookup: [
1692                ("a".to_string(), 0),
1693                ("b".to_string(), 1),
1694                ("c".to_string(), 2),
1695            ]
1696            .iter()
1697            .cloned()
1698            .collect(),
1699            attributes: Default::default(),
1700        });
1701
1702        assert!(
1703            Value::Record(vec![
1704                ("a".to_string(), Value::Long(42i64)),
1705                ("b".to_string(), Value::String("foo".to_string())),
1706            ])
1707            .validate(&schema)
1708        );
1709
1710        let value = Value::Record(vec![
1711            ("b".to_string(), Value::String("foo".to_string())),
1712            ("a".to_string(), Value::Long(42i64)),
1713        ]);
1714        assert!(value.validate(&schema));
1715
1716        let value = Value::Record(vec![
1717            ("a".to_string(), Value::Boolean(false)),
1718            ("b".to_string(), Value::String("foo".to_string())),
1719        ]);
1720        assert!(!value.validate(&schema));
1721        assert_logged(
1722            r#"Invalid value: Record([("a", Boolean(false)), ("b", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Unsupported value-schema combination! Value: Boolean(false), schema: Long"#,
1723        );
1724
1725        let value = Value::Record(vec![
1726            ("a".to_string(), Value::Long(42i64)),
1727            ("c".to_string(), Value::String("foo".to_string())),
1728        ]);
1729        assert!(!value.validate(&schema));
1730        assert_logged(
1731            r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Could not find matching type in union"#,
1732        );
1733        assert_not_logged(
1734            r#"Invalid value: String("foo") for schema: Int. Reason: Unsupported value-schema combination"#,
1735        );
1736
1737        let value = Value::Record(vec![
1738            ("a".to_string(), Value::Long(42i64)),
1739            ("d".to_string(), Value::String("foo".to_string())),
1740        ]);
1741        assert!(!value.validate(&schema));
1742        assert_logged(
1743            r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: There is no schema field for field 'd'"#,
1744        );
1745
1746        let value = Value::Record(vec![
1747            ("a".to_string(), Value::Long(42i64)),
1748            ("b".to_string(), Value::String("foo".to_string())),
1749            ("c".to_string(), Value::Null),
1750            ("d".to_string(), Value::Null),
1751        ]);
1752        assert!(!value.validate(&schema));
1753        assert_logged(
1754            r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), ("c", Null), ("d", Null)]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: The value's records length (4) is greater than the schema's (3 fields)"#,
1755        );
1756
1757        assert!(
1758            Value::Map(
1759                vec![
1760                    ("a".to_string(), Value::Long(42i64)),
1761                    ("b".to_string(), Value::String("foo".to_string())),
1762                ]
1763                .into_iter()
1764                .collect()
1765            )
1766            .validate(&schema)
1767        );
1768
1769        assert!(
1770            !Value::Map(
1771                vec![("d".to_string(), Value::Long(123_i64)),]
1772                    .into_iter()
1773                    .collect()
1774            )
1775            .validate(&schema)
1776        );
1777        assert_logged(
1778            r#"Invalid value: Map({"d": Long(123)}) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Field with name '"a"' is not a member of the map items
1779Field with name '"b"' is not a member of the map items"#,
1780        );
1781
1782        let union_schema = Schema::Union(UnionSchema::new(vec![Schema::Null, schema])?);
1783
1784        assert!(
1785            Value::Union(
1786                1,
1787                Box::new(Value::Record(vec![
1788                    ("a".to_string(), Value::Long(42i64)),
1789                    ("b".to_string(), Value::String("foo".to_string())),
1790                ]))
1791            )
1792            .validate(&union_schema)
1793        );
1794
1795        assert!(
1796            Value::Union(
1797                1,
1798                Box::new(Value::Map(
1799                    vec![
1800                        ("a".to_string(), Value::Long(42i64)),
1801                        ("b".to_string(), Value::String("foo".to_string())),
1802                    ]
1803                    .into_iter()
1804                    .collect()
1805                ))
1806            )
1807            .validate(&union_schema)
1808        );
1809
1810        Ok(())
1811    }
1812
1813    #[test]
1814    fn resolve_bytes_ok() -> TestResult {
1815        let value = Value::Array(vec![Value::Int(0), Value::Int(42)]);
1816        assert_eq!(
1817            value.resolve(&Schema::Bytes)?,
1818            Value::Bytes(vec![0u8, 42u8])
1819        );
1820
1821        Ok(())
1822    }
1823
1824    #[test]
1825    fn resolve_string_from_bytes() -> TestResult {
1826        let value = Value::Bytes(vec![97, 98, 99]);
1827        assert_eq!(
1828            value.resolve(&Schema::String)?,
1829            Value::String("abc".to_string())
1830        );
1831
1832        Ok(())
1833    }
1834
1835    #[test]
1836    fn resolve_string_from_fixed() -> TestResult {
1837        let value = Value::Fixed(3, vec![97, 98, 99]);
1838        assert_eq!(
1839            value.resolve(&Schema::String)?,
1840            Value::String("abc".to_string())
1841        );
1842
1843        Ok(())
1844    }
1845
1846    #[test]
1847    fn resolve_bytes_failure() {
1848        let value = Value::Array(vec![Value::Int(2000), Value::Int(-42)]);
1849        assert!(value.resolve(&Schema::Bytes).is_err());
1850    }
1851
1852    #[test]
1853    fn resolve_decimal_bytes() -> TestResult {
1854        let value = Value::Decimal(Decimal::from(vec![1, 2, 3, 4, 5]));
1855        value.clone().resolve(&Schema::Decimal(DecimalSchema {
1856            precision: 10,
1857            scale: 4,
1858            inner: InnerDecimalSchema::Bytes,
1859        }))?;
1860        assert!(value.resolve(&Schema::String).is_err());
1861
1862        Ok(())
1863    }
1864
1865    #[test]
1866    fn avro_rs_580_resolve_decimal_from_string_default() -> TestResult {
1867        let value = Value::String("\u{0000}".to_string());
1868        let resolved = value.resolve(&Schema::Decimal(DecimalSchema {
1869            precision: 10,
1870            scale: 4,
1871            inner: InnerDecimalSchema::Bytes,
1872        }))?;
1873        assert_eq!(resolved, Value::Decimal(Decimal::from(vec![0u8])));
1874
1875        let mut all_bytes_str = String::new();
1876        for b in 0u8..=255u8 {
1877            all_bytes_str.push(char::from_u32(b as u32).unwrap());
1878        }
1879        let resolved = Value::String(all_bytes_str).resolve(&Schema::Decimal(DecimalSchema {
1880            precision: 10,
1881            scale: 0,
1882            inner: InnerDecimalSchema::Bytes,
1883        }))?;
1884        assert_eq!(
1885            resolved,
1886            Value::Decimal(Decimal::from((0u8..=255u8).collect::<Vec<_>>()))
1887        );
1888
1889        let value = Value::String("\u{0100}".to_string());
1890        assert!(
1891            value
1892                .resolve(&Schema::Decimal(DecimalSchema {
1893                    precision: 10,
1894                    scale: 4,
1895                    inner: InnerDecimalSchema::Bytes,
1896                }))
1897                .is_err()
1898        );
1899
1900        Ok(())
1901    }
1902
1903    #[test]
1904    fn avro_rs_580_parse_schema_with_nullable_decimal_string_default() -> TestResult {
1905        let schema_json = r#"{
1906            "type": "record",
1907            "name": "NullableDecimal",
1908            "fields": [
1909                {
1910                    "name": "amount",
1911                    "type": [
1912                        {
1913                            "type": "bytes",
1914                            "scale": 4,
1915                            "precision": 10,
1916                            "logicalType": "decimal"
1917                        },
1918                        "null"
1919                    ],
1920                    "default": "\u0000"
1921                }
1922            ]
1923        }"#;
1924        Schema::parse_str(schema_json)?;
1925        Ok(())
1926    }
1927
1928    #[test]
1929    fn resolve_decimal_invalid_scale() {
1930        let value = Value::Decimal(Decimal::from(vec![1, 2]));
1931        assert!(
1932            value
1933                .resolve(&Schema::Decimal(DecimalSchema {
1934                    precision: 2,
1935                    scale: 3,
1936                    inner: InnerDecimalSchema::Bytes,
1937                }))
1938                .is_err()
1939        );
1940    }
1941
1942    #[test]
1943    fn resolve_decimal_invalid_precision_for_length() {
1944        let value = Value::Decimal(Decimal::from((1u8..=8u8).rev().collect::<Vec<_>>()));
1945        assert!(
1946            value
1947                .resolve(&Schema::Decimal(DecimalSchema {
1948                    precision: 1,
1949                    scale: 0,
1950                    inner: InnerDecimalSchema::Bytes,
1951                }))
1952                .is_ok()
1953        );
1954    }
1955
1956    #[test]
1957    fn resolve_decimal_fixed() {
1958        let value = Value::Decimal(Decimal::from(vec![1, 2, 3, 4, 5]));
1959        assert!(
1960            value
1961                .clone()
1962                .resolve(&Schema::Decimal(DecimalSchema {
1963                    precision: 10,
1964                    scale: 1,
1965                    inner: InnerDecimalSchema::Fixed(FixedSchema {
1966                        name: Name::new("decimal").unwrap(),
1967                        aliases: None,
1968                        size: 20,
1969                        doc: None,
1970                        attributes: Default::default(),
1971                    })
1972                }))
1973                .is_ok()
1974        );
1975        assert!(value.resolve(&Schema::String).is_err());
1976    }
1977
1978    #[test]
1979    fn resolve_date() {
1980        let value = Value::Date(2345);
1981        assert!(value.clone().resolve(&Schema::Date).is_ok());
1982        assert!(value.resolve(&Schema::String).is_err());
1983    }
1984
1985    #[test]
1986    fn resolve_time_millis() {
1987        let value = Value::TimeMillis(10);
1988        assert!(value.clone().resolve(&Schema::TimeMillis).is_ok());
1989        assert!(value.resolve(&Schema::TimeMicros).is_err());
1990    }
1991
1992    #[test]
1993    fn resolve_time_micros() {
1994        let value = Value::TimeMicros(10);
1995        assert!(value.clone().resolve(&Schema::TimeMicros).is_ok());
1996        assert!(value.resolve(&Schema::TimeMillis).is_err());
1997    }
1998
1999    #[test]
2000    fn resolve_timestamp_millis() {
2001        let value = Value::TimestampMillis(10);
2002        assert!(value.clone().resolve(&Schema::TimestampMillis).is_ok());
2003        assert!(value.resolve(&Schema::Float).is_err());
2004
2005        let value = Value::Float(10.0f32);
2006        assert!(value.resolve(&Schema::TimestampMillis).is_err());
2007    }
2008
2009    #[test]
2010    fn resolve_timestamp_micros() {
2011        let value = Value::TimestampMicros(10);
2012        assert!(value.clone().resolve(&Schema::TimestampMicros).is_ok());
2013        assert!(value.resolve(&Schema::Int).is_err());
2014
2015        let value = Value::Double(10.0);
2016        assert!(value.resolve(&Schema::TimestampMicros).is_err());
2017    }
2018
2019    #[test]
2020    fn test_avro_3914_resolve_timestamp_nanos() {
2021        let value = Value::TimestampNanos(10);
2022        assert!(value.clone().resolve(&Schema::TimestampNanos).is_ok());
2023        assert!(value.resolve(&Schema::Int).is_err());
2024
2025        let value = Value::Double(10.0);
2026        assert!(value.resolve(&Schema::TimestampNanos).is_err());
2027    }
2028
2029    #[test]
2030    fn test_avro_3853_resolve_timestamp_millis() {
2031        let value = Value::LocalTimestampMillis(10);
2032        assert!(value.clone().resolve(&Schema::LocalTimestampMillis).is_ok());
2033        assert!(value.resolve(&Schema::Float).is_err());
2034
2035        let value = Value::Float(10.0f32);
2036        assert!(value.resolve(&Schema::LocalTimestampMillis).is_err());
2037    }
2038
2039    #[test]
2040    fn test_avro_3853_resolve_timestamp_micros() {
2041        let value = Value::LocalTimestampMicros(10);
2042        assert!(value.clone().resolve(&Schema::LocalTimestampMicros).is_ok());
2043        assert!(value.resolve(&Schema::Int).is_err());
2044
2045        let value = Value::Double(10.0);
2046        assert!(value.resolve(&Schema::LocalTimestampMicros).is_err());
2047    }
2048
2049    #[test]
2050    fn test_avro_3916_resolve_timestamp_nanos() {
2051        let value = Value::LocalTimestampNanos(10);
2052        assert!(value.clone().resolve(&Schema::LocalTimestampNanos).is_ok());
2053        assert!(value.resolve(&Schema::Int).is_err());
2054
2055        let value = Value::Double(10.0);
2056        assert!(value.resolve(&Schema::LocalTimestampNanos).is_err());
2057    }
2058
2059    #[test]
2060    fn resolve_duration() {
2061        let value = Value::Duration(Duration::new(
2062            Months::new(10),
2063            Days::new(5),
2064            Millis::new(3000),
2065        ));
2066        assert!(
2067            value
2068                .clone()
2069                .resolve(&Schema::Duration(FixedSchema {
2070                    name: Name::try_from("TestName").expect("Name is valid"),
2071                    aliases: None,
2072                    doc: None,
2073                    size: 12,
2074                    attributes: BTreeMap::new()
2075                }))
2076                .is_ok()
2077        );
2078        assert!(value.resolve(&Schema::TimestampMicros).is_err());
2079        assert!(
2080            Value::Long(1i64)
2081                .resolve(&Schema::Duration(FixedSchema {
2082                    name: Name::try_from("TestName").expect("Name is valid"),
2083                    aliases: None,
2084                    doc: None,
2085                    size: 12,
2086                    attributes: BTreeMap::new()
2087                }))
2088                .is_err()
2089        );
2090    }
2091
2092    #[test]
2093    fn resolve_uuid() -> TestResult {
2094        let value = Value::Uuid(Uuid::parse_str("1481531d-ccc9-46d9-a56f-5b67459c0537")?);
2095        assert!(
2096            value
2097                .clone()
2098                .resolve(&Schema::Uuid(UuidSchema::String))
2099                .is_ok()
2100        );
2101        assert!(
2102            value
2103                .clone()
2104                .resolve(&Schema::Uuid(UuidSchema::Bytes))
2105                .is_ok()
2106        );
2107        assert!(
2108            value
2109                .clone()
2110                .resolve(&Schema::Uuid(UuidSchema::Fixed(FixedSchema {
2111                    name: Name::new("some_name")?,
2112                    aliases: None,
2113                    doc: None,
2114                    size: 16,
2115                    attributes: Default::default(),
2116                })))
2117                .is_ok()
2118        );
2119        assert!(value.resolve(&Schema::TimestampMicros).is_err());
2120
2121        Ok(())
2122    }
2123
2124    #[test]
2125    fn avro_3678_resolve_float_to_double() {
2126        let value = Value::Float(2345.1);
2127        assert!(value.resolve(&Schema::Double).is_ok());
2128    }
2129
2130    #[test]
2131    fn test_avro_3621_resolve_to_nullable_union() -> TestResult {
2132        let schema = Schema::parse_str(
2133            r#"{
2134            "type": "record",
2135            "name": "root",
2136            "fields": [
2137                {
2138                    "name": "event",
2139                    "type": [
2140                        "null",
2141                        {
2142                            "type": "record",
2143                            "name": "event",
2144                            "fields": [
2145                                {
2146                                    "name": "amount",
2147                                    "type": "int"
2148                                },
2149                                {
2150                                    "name": "size",
2151                                    "type": [
2152                                        "null",
2153                                        "int"
2154                                    ],
2155                                    "default": null
2156                                }
2157                            ]
2158                        }
2159                    ],
2160                    "default": null
2161                }
2162            ]
2163        }"#,
2164        )?;
2165
2166        let value = Value::Record(vec![(
2167            "event".to_string(),
2168            Value::Record(vec![("amount".to_string(), Value::Int(200))]),
2169        )]);
2170        assert!(value.resolve(&schema).is_ok());
2171
2172        let value = Value::Record(vec![(
2173            "event".to_string(),
2174            Value::Record(vec![("size".to_string(), Value::Int(1))]),
2175        )]);
2176        assert!(value.resolve(&schema).is_err());
2177
2178        Ok(())
2179    }
2180
2181    #[test]
2182    fn json_from_avro() -> TestResult {
2183        assert_eq!(JsonValue::try_from(Value::Null)?, JsonValue::Null);
2184        assert_eq!(
2185            JsonValue::try_from(Value::Boolean(true))?,
2186            JsonValue::Bool(true)
2187        );
2188        assert_eq!(
2189            JsonValue::try_from(Value::Int(1))?,
2190            JsonValue::Number(1.into())
2191        );
2192        assert_eq!(
2193            JsonValue::try_from(Value::Long(1))?,
2194            JsonValue::Number(1.into())
2195        );
2196        assert_eq!(
2197            JsonValue::try_from(Value::Float(1.0))?,
2198            JsonValue::Number(Number::from_f64(1.0).unwrap())
2199        );
2200        assert_eq!(
2201            JsonValue::try_from(Value::Double(1.0))?,
2202            JsonValue::Number(Number::from_f64(1.0).unwrap())
2203        );
2204        assert_eq!(
2205            JsonValue::try_from(Value::Bytes(vec![1, 2, 3]))?,
2206            JsonValue::Array(vec![
2207                JsonValue::Number(1.into()),
2208                JsonValue::Number(2.into()),
2209                JsonValue::Number(3.into())
2210            ])
2211        );
2212        assert_eq!(
2213            JsonValue::try_from(Value::String("test".into()))?,
2214            JsonValue::String("test".into())
2215        );
2216        assert_eq!(
2217            JsonValue::try_from(Value::Fixed(3, vec![1, 2, 3]))?,
2218            JsonValue::Array(vec![
2219                JsonValue::Number(1.into()),
2220                JsonValue::Number(2.into()),
2221                JsonValue::Number(3.into())
2222            ])
2223        );
2224        assert_eq!(
2225            JsonValue::try_from(Value::Enum(1, "test_enum".into()))?,
2226            JsonValue::String("test_enum".into())
2227        );
2228        assert_eq!(
2229            JsonValue::try_from(Value::Union(1, Box::new(Value::String("test_enum".into()))))?,
2230            JsonValue::String("test_enum".into())
2231        );
2232        assert_eq!(
2233            JsonValue::try_from(Value::Array(vec![
2234                Value::Int(1),
2235                Value::Int(2),
2236                Value::Int(3)
2237            ]))?,
2238            JsonValue::Array(vec![
2239                JsonValue::Number(1.into()),
2240                JsonValue::Number(2.into()),
2241                JsonValue::Number(3.into())
2242            ])
2243        );
2244        assert_eq!(
2245            JsonValue::try_from(Value::Map(
2246                vec![
2247                    ("v1".to_string(), Value::Int(1)),
2248                    ("v2".to_string(), Value::Int(2)),
2249                    ("v3".to_string(), Value::Int(3))
2250                ]
2251                .into_iter()
2252                .collect()
2253            ))?,
2254            JsonValue::Object(
2255                vec![
2256                    ("v1".to_string(), JsonValue::Number(1.into())),
2257                    ("v2".to_string(), JsonValue::Number(2.into())),
2258                    ("v3".to_string(), JsonValue::Number(3.into()))
2259                ]
2260                .into_iter()
2261                .collect()
2262            )
2263        );
2264        assert_eq!(
2265            JsonValue::try_from(Value::Record(vec![
2266                ("v1".to_string(), Value::Int(1)),
2267                ("v2".to_string(), Value::Int(2)),
2268                ("v3".to_string(), Value::Int(3))
2269            ]))?,
2270            JsonValue::Object(
2271                vec![
2272                    ("v1".to_string(), JsonValue::Number(1.into())),
2273                    ("v2".to_string(), JsonValue::Number(2.into())),
2274                    ("v3".to_string(), JsonValue::Number(3.into()))
2275                ]
2276                .into_iter()
2277                .collect()
2278            )
2279        );
2280        assert_eq!(
2281            JsonValue::try_from(Value::Date(1))?,
2282            JsonValue::Number(1.into())
2283        );
2284        assert_eq!(
2285            JsonValue::try_from(Value::Decimal(vec![1, 2, 3].into()))?,
2286            JsonValue::Array(vec![
2287                JsonValue::Number(1.into()),
2288                JsonValue::Number(2.into()),
2289                JsonValue::Number(3.into())
2290            ])
2291        );
2292        assert_eq!(
2293            JsonValue::try_from(Value::TimeMillis(1))?,
2294            JsonValue::Number(1.into())
2295        );
2296        assert_eq!(
2297            JsonValue::try_from(Value::TimeMicros(1))?,
2298            JsonValue::Number(1.into())
2299        );
2300        assert_eq!(
2301            JsonValue::try_from(Value::TimestampMillis(1))?,
2302            JsonValue::Number(1.into())
2303        );
2304        assert_eq!(
2305            JsonValue::try_from(Value::TimestampMicros(1))?,
2306            JsonValue::Number(1.into())
2307        );
2308        assert_eq!(
2309            JsonValue::try_from(Value::TimestampNanos(1))?,
2310            JsonValue::Number(1.into())
2311        );
2312        assert_eq!(
2313            JsonValue::try_from(Value::LocalTimestampMillis(1))?,
2314            JsonValue::Number(1.into())
2315        );
2316        assert_eq!(
2317            JsonValue::try_from(Value::LocalTimestampMicros(1))?,
2318            JsonValue::Number(1.into())
2319        );
2320        assert_eq!(
2321            JsonValue::try_from(Value::LocalTimestampNanos(1))?,
2322            JsonValue::Number(1.into())
2323        );
2324        assert_eq!(
2325            JsonValue::try_from(Value::Duration(
2326                [
2327                    1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8, 11u8, 12u8
2328                ]
2329                .into()
2330            ))?,
2331            JsonValue::Array(vec![
2332                JsonValue::Number(1.into()),
2333                JsonValue::Number(2.into()),
2334                JsonValue::Number(3.into()),
2335                JsonValue::Number(4.into()),
2336                JsonValue::Number(5.into()),
2337                JsonValue::Number(6.into()),
2338                JsonValue::Number(7.into()),
2339                JsonValue::Number(8.into()),
2340                JsonValue::Number(9.into()),
2341                JsonValue::Number(10.into()),
2342                JsonValue::Number(11.into()),
2343                JsonValue::Number(12.into()),
2344            ])
2345        );
2346        assert_eq!(
2347            JsonValue::try_from(Value::Uuid(Uuid::parse_str(
2348                "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
2349            )?))?,
2350            JsonValue::String("936da01f-9abd-4d9d-80c7-02af85c822a8".into())
2351        );
2352
2353        Ok(())
2354    }
2355
2356    #[test]
2357    fn test_avro_3433_recursive_resolves_record() -> TestResult {
2358        let schema = Schema::parse_str(
2359            r#"
2360        {
2361            "type":"record",
2362            "name":"TestStruct",
2363            "fields": [
2364                {
2365                    "name":"a",
2366                    "type":{
2367                        "type":"record",
2368                        "name": "Inner",
2369                        "fields": [ {
2370                            "name":"z",
2371                            "type":"int"
2372                        }]
2373                    }
2374                },
2375                {
2376                    "name":"b",
2377                    "type":"Inner"
2378                }
2379            ]
2380        }"#,
2381        )?;
2382
2383        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2384        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2385        let outer = Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
2386        outer
2387            .resolve(&schema)
2388            .expect("Record definition defined in one field must be available in other field");
2389
2390        Ok(())
2391    }
2392
2393    #[test]
2394    fn test_avro_3433_recursive_resolves_array() -> TestResult {
2395        let schema = Schema::parse_str(
2396            r#"
2397        {
2398            "type":"record",
2399            "name":"TestStruct",
2400            "fields": [
2401                {
2402                    "name":"a",
2403                    "type":{
2404                        "type":"array",
2405                        "items": {
2406                            "type":"record",
2407                            "name": "Inner",
2408                            "fields": [ {
2409                                "name":"z",
2410                                "type":"int"
2411                            }]
2412                        }
2413                    }
2414                },
2415                {
2416                    "name":"b",
2417                    "type": {
2418                        "type":"map",
2419                        "values":"Inner"
2420                    }
2421                }
2422            ]
2423        }"#,
2424        )?;
2425
2426        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2427        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2428        let outer_value = Value::Record(vec![
2429            ("a".into(), Value::Array(vec![inner_value1])),
2430            (
2431                "b".into(),
2432                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2433            ),
2434        ]);
2435        outer_value
2436            .resolve(&schema)
2437            .expect("Record defined in array definition must be resolvable from map");
2438
2439        Ok(())
2440    }
2441
2442    #[test]
2443    fn test_avro_3433_recursive_resolves_map() -> TestResult {
2444        let schema = Schema::parse_str(
2445            r#"
2446        {
2447            "type":"record",
2448            "name":"TestStruct",
2449            "fields": [
2450                {
2451                    "name":"a",
2452                    "type":{
2453                        "type":"record",
2454                        "name": "Inner",
2455                        "fields": [ {
2456                            "name":"z",
2457                            "type":"int"
2458                        }]
2459                    }
2460                },
2461                {
2462                    "name":"b",
2463                    "type": {
2464                        "type":"map",
2465                        "values":"Inner"
2466                    }
2467                }
2468            ]
2469        }"#,
2470        )?;
2471
2472        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2473        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2474        let outer_value = Value::Record(vec![
2475            ("a".into(), inner_value1),
2476            (
2477                "b".into(),
2478                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2479            ),
2480        ]);
2481        outer_value
2482            .resolve(&schema)
2483            .expect("Record defined in record field must be resolvable from map field");
2484
2485        Ok(())
2486    }
2487
2488    #[test]
2489    fn test_avro_3433_recursive_resolves_record_wrapper() -> TestResult {
2490        let schema = Schema::parse_str(
2491            r#"
2492        {
2493            "type":"record",
2494            "name":"TestStruct",
2495            "fields": [
2496                {
2497                    "name":"a",
2498                    "type":{
2499                        "type":"record",
2500                        "name": "Inner",
2501                        "fields": [ {
2502                            "name":"z",
2503                            "type":"int"
2504                        }]
2505                    }
2506                },
2507                {
2508                    "name":"b",
2509                    "type": {
2510                        "type":"record",
2511                        "name": "InnerWrapper",
2512                        "fields": [ {
2513                            "name":"j",
2514                            "type":"Inner"
2515                        }]
2516                    }
2517                }
2518            ]
2519        }"#,
2520        )?;
2521
2522        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2523        let inner_value2 = Value::Record(vec![(
2524            "j".into(),
2525            Value::Record(vec![("z".into(), Value::Int(6))]),
2526        )]);
2527        let outer_value =
2528            Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
2529        outer_value.resolve(&schema).expect("Record schema defined in field must be resolvable in Record schema defined in other field");
2530
2531        Ok(())
2532    }
2533
2534    #[test]
2535    fn test_avro_3433_recursive_resolves_map_and_array() -> TestResult {
2536        let schema = Schema::parse_str(
2537            r#"
2538        {
2539            "type":"record",
2540            "name":"TestStruct",
2541            "fields": [
2542                {
2543                    "name":"a",
2544                    "type":{
2545                        "type":"map",
2546                        "values": {
2547                            "type":"record",
2548                            "name": "Inner",
2549                            "fields": [ {
2550                                "name":"z",
2551                                "type":"int"
2552                            }]
2553                        }
2554                    }
2555                },
2556                {
2557                    "name":"b",
2558                    "type": {
2559                        "type":"array",
2560                        "items":"Inner"
2561                    }
2562                }
2563            ]
2564        }"#,
2565        )?;
2566
2567        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2568        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2569        let outer_value = Value::Record(vec![
2570            (
2571                "a".into(),
2572                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2573            ),
2574            ("b".into(), Value::Array(vec![inner_value1])),
2575        ]);
2576        outer_value
2577            .resolve(&schema)
2578            .expect("Record defined in map definition must be resolvable from array");
2579
2580        Ok(())
2581    }
2582
2583    #[test]
2584    fn test_avro_3433_recursive_resolves_union() -> TestResult {
2585        let schema = Schema::parse_str(
2586            r#"
2587        {
2588            "type":"record",
2589            "name":"TestStruct",
2590            "fields": [
2591                {
2592                    "name":"a",
2593                    "type":["null", {
2594                        "type":"record",
2595                        "name": "Inner",
2596                        "fields": [ {
2597                            "name":"z",
2598                            "type":"int"
2599                        }]
2600                    }]
2601                },
2602                {
2603                    "name":"b",
2604                    "type":"Inner"
2605                }
2606            ]
2607        }"#,
2608        )?;
2609
2610        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2611        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2612        let outer1 = Value::Record(vec![
2613            ("a".into(), inner_value1),
2614            ("b".into(), inner_value2.clone()),
2615        ]);
2616        outer1
2617            .resolve(&schema)
2618            .expect("Record definition defined in union must be resolved in other field");
2619        let outer2 = Value::Record(vec![("a".into(), Value::Null), ("b".into(), inner_value2)]);
2620        outer2
2621            .resolve(&schema)
2622            .expect("Record definition defined in union must be resolved in other field");
2623
2624        Ok(())
2625    }
2626
2627    #[test]
2628    fn test_avro_3461_test_multi_level_resolve_outer_namespace() -> TestResult {
2629        let schema = r#"
2630        {
2631          "name": "record_name",
2632          "namespace": "space",
2633          "type": "record",
2634          "fields": [
2635            {
2636              "name": "outer_field_1",
2637              "type": [
2638                        "null",
2639                        {
2640                            "type": "record",
2641                            "name": "middle_record_name",
2642                            "fields":[
2643                                {
2644                                    "name":"middle_field_1",
2645                                    "type":[
2646                                        "null",
2647                                        {
2648                                            "type":"record",
2649                                            "name":"inner_record_name",
2650                                            "fields":[
2651                                                {
2652                                                    "name":"inner_field_1",
2653                                                    "type":"double"
2654                                                }
2655                                            ]
2656                                        }
2657                                    ]
2658                                }
2659                            ]
2660                        }
2661                    ]
2662            },
2663            {
2664                "name": "outer_field_2",
2665                "type" : "space.inner_record_name"
2666            }
2667          ]
2668        }
2669        "#;
2670        let schema = Schema::parse_str(schema)?;
2671        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2672        let middle_record_variation_1 = Value::Record(vec![(
2673            "middle_field_1".into(),
2674            Value::Union(0, Box::new(Value::Null)),
2675        )]);
2676        let middle_record_variation_2 = Value::Record(vec![(
2677            "middle_field_1".into(),
2678            Value::Union(1, Box::new(inner_record.clone())),
2679        )]);
2680        let outer_record_variation_1 = Value::Record(vec![
2681            (
2682                "outer_field_1".into(),
2683                Value::Union(0, Box::new(Value::Null)),
2684            ),
2685            ("outer_field_2".into(), inner_record.clone()),
2686        ]);
2687        let outer_record_variation_2 = Value::Record(vec![
2688            (
2689                "outer_field_1".into(),
2690                Value::Union(1, Box::new(middle_record_variation_1)),
2691            ),
2692            ("outer_field_2".into(), inner_record.clone()),
2693        ]);
2694        let outer_record_variation_3 = Value::Record(vec![
2695            (
2696                "outer_field_1".into(),
2697                Value::Union(1, Box::new(middle_record_variation_2)),
2698            ),
2699            ("outer_field_2".into(), inner_record),
2700        ]);
2701
2702        outer_record_variation_1
2703            .resolve(&schema)
2704            .expect("Should be able to resolve value to the schema that is it's definition");
2705        outer_record_variation_2
2706            .resolve(&schema)
2707            .expect("Should be able to resolve value to the schema that is it's definition");
2708        outer_record_variation_3
2709            .resolve(&schema)
2710            .expect("Should be able to resolve value to the schema that is it's definition");
2711
2712        Ok(())
2713    }
2714
2715    #[test]
2716    fn test_avro_3461_test_multi_level_resolve_middle_namespace() -> TestResult {
2717        let schema = r#"
2718        {
2719          "name": "record_name",
2720          "namespace": "space",
2721          "type": "record",
2722          "fields": [
2723            {
2724              "name": "outer_field_1",
2725              "type": [
2726                        "null",
2727                        {
2728                            "type": "record",
2729                            "name": "middle_record_name",
2730                            "namespace":"middle_namespace",
2731                            "fields":[
2732                                {
2733                                    "name":"middle_field_1",
2734                                    "type":[
2735                                        "null",
2736                                        {
2737                                            "type":"record",
2738                                            "name":"inner_record_name",
2739                                            "fields":[
2740                                                {
2741                                                    "name":"inner_field_1",
2742                                                    "type":"double"
2743                                                }
2744                                            ]
2745                                        }
2746                                    ]
2747                                }
2748                            ]
2749                        }
2750                    ]
2751            },
2752            {
2753                "name": "outer_field_2",
2754                "type" : "middle_namespace.inner_record_name"
2755            }
2756          ]
2757        }
2758        "#;
2759        let schema = Schema::parse_str(schema)?;
2760        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2761        let middle_record_variation_1 = Value::Record(vec![(
2762            "middle_field_1".into(),
2763            Value::Union(0, Box::new(Value::Null)),
2764        )]);
2765        let middle_record_variation_2 = Value::Record(vec![(
2766            "middle_field_1".into(),
2767            Value::Union(1, Box::new(inner_record.clone())),
2768        )]);
2769        let outer_record_variation_1 = Value::Record(vec![
2770            (
2771                "outer_field_1".into(),
2772                Value::Union(0, Box::new(Value::Null)),
2773            ),
2774            ("outer_field_2".into(), inner_record.clone()),
2775        ]);
2776        let outer_record_variation_2 = Value::Record(vec![
2777            (
2778                "outer_field_1".into(),
2779                Value::Union(1, Box::new(middle_record_variation_1)),
2780            ),
2781            ("outer_field_2".into(), inner_record.clone()),
2782        ]);
2783        let outer_record_variation_3 = Value::Record(vec![
2784            (
2785                "outer_field_1".into(),
2786                Value::Union(1, Box::new(middle_record_variation_2)),
2787            ),
2788            ("outer_field_2".into(), inner_record),
2789        ]);
2790
2791        outer_record_variation_1
2792            .resolve(&schema)
2793            .expect("Should be able to resolve value to the schema that is it's definition");
2794        outer_record_variation_2
2795            .resolve(&schema)
2796            .expect("Should be able to resolve value to the schema that is it's definition");
2797        outer_record_variation_3
2798            .resolve(&schema)
2799            .expect("Should be able to resolve value to the schema that is it's definition");
2800
2801        Ok(())
2802    }
2803
2804    #[test]
2805    fn test_avro_3461_test_multi_level_resolve_inner_namespace() -> TestResult {
2806        let schema = r#"
2807        {
2808          "name": "record_name",
2809          "namespace": "space",
2810          "type": "record",
2811          "fields": [
2812            {
2813              "name": "outer_field_1",
2814              "type": [
2815                        "null",
2816                        {
2817                            "type": "record",
2818                            "name": "middle_record_name",
2819                            "namespace":"middle_namespace",
2820                            "fields":[
2821                                {
2822                                    "name":"middle_field_1",
2823                                    "type":[
2824                                        "null",
2825                                        {
2826                                            "type":"record",
2827                                            "name":"inner_record_name",
2828                                            "namespace":"inner_namespace",
2829                                            "fields":[
2830                                                {
2831                                                    "name":"inner_field_1",
2832                                                    "type":"double"
2833                                                }
2834                                            ]
2835                                        }
2836                                    ]
2837                                }
2838                            ]
2839                        }
2840                    ]
2841            },
2842            {
2843                "name": "outer_field_2",
2844                "type" : "inner_namespace.inner_record_name"
2845            }
2846          ]
2847        }
2848        "#;
2849        let schema = Schema::parse_str(schema)?;
2850
2851        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2852        let middle_record_variation_1 = Value::Record(vec![(
2853            "middle_field_1".into(),
2854            Value::Union(0, Box::new(Value::Null)),
2855        )]);
2856        let middle_record_variation_2 = Value::Record(vec![(
2857            "middle_field_1".into(),
2858            Value::Union(1, Box::new(inner_record.clone())),
2859        )]);
2860        let outer_record_variation_1 = Value::Record(vec![
2861            (
2862                "outer_field_1".into(),
2863                Value::Union(0, Box::new(Value::Null)),
2864            ),
2865            ("outer_field_2".into(), inner_record.clone()),
2866        ]);
2867        let outer_record_variation_2 = Value::Record(vec![
2868            (
2869                "outer_field_1".into(),
2870                Value::Union(1, Box::new(middle_record_variation_1)),
2871            ),
2872            ("outer_field_2".into(), inner_record.clone()),
2873        ]);
2874        let outer_record_variation_3 = Value::Record(vec![
2875            (
2876                "outer_field_1".into(),
2877                Value::Union(1, Box::new(middle_record_variation_2)),
2878            ),
2879            ("outer_field_2".into(), inner_record),
2880        ]);
2881
2882        outer_record_variation_1
2883            .resolve(&schema)
2884            .expect("Should be able to resolve value to the schema that is it's definition");
2885        outer_record_variation_2
2886            .resolve(&schema)
2887            .expect("Should be able to resolve value to the schema that is it's definition");
2888        outer_record_variation_3
2889            .resolve(&schema)
2890            .expect("Should be able to resolve value to the schema that is it's definition");
2891
2892        Ok(())
2893    }
2894
2895    #[test]
2896    fn test_avro_3460_validation_with_refs() -> TestResult {
2897        let schema = Schema::parse_str(
2898            r#"
2899        {
2900            "type":"record",
2901            "name":"TestStruct",
2902            "fields": [
2903                {
2904                    "name":"a",
2905                    "type":{
2906                        "type":"record",
2907                        "name": "Inner",
2908                        "fields": [ {
2909                            "name":"z",
2910                            "type":"int"
2911                        }]
2912                    }
2913                },
2914                {
2915                    "name":"b",
2916                    "type":"Inner"
2917                }
2918            ]
2919        }"#,
2920        )?;
2921
2922        let inner_value_right = Value::Record(vec![("z".into(), Value::Int(3))]);
2923        let inner_value_wrong1 = Value::Record(vec![("z".into(), Value::Null)]);
2924        let inner_value_wrong2 = Value::Record(vec![("a".into(), Value::String("testing".into()))]);
2925        let outer1 = Value::Record(vec![
2926            ("a".into(), inner_value_right.clone()),
2927            ("b".into(), inner_value_wrong1),
2928        ]);
2929
2930        let outer2 = Value::Record(vec![
2931            ("a".into(), inner_value_right),
2932            ("b".into(), inner_value_wrong2),
2933        ]);
2934
2935        assert!(
2936            !outer1.validate(&schema),
2937            "field b record is invalid against the schema"
2938        ); // this should pass, but doesn't
2939        assert!(
2940            !outer2.validate(&schema),
2941            "field b record is invalid against the schema"
2942        ); // this should pass, but doesn't
2943
2944        Ok(())
2945    }
2946
2947    #[test]
2948    fn test_avro_3460_validation_with_refs_real_struct() -> TestResult {
2949        use serde::Serialize;
2950
2951        #[derive(Serialize, Clone)]
2952        struct TestInner {
2953            z: i32,
2954        }
2955
2956        #[derive(Serialize)]
2957        struct TestRefSchemaStruct1 {
2958            a: TestInner,
2959            b: String, // could be literally anything
2960        }
2961
2962        #[derive(Serialize)]
2963        struct TestRefSchemaStruct2 {
2964            a: TestInner,
2965            b: i32, // could be literally anything
2966        }
2967
2968        #[derive(Serialize)]
2969        struct TestRefSchemaStruct3 {
2970            a: TestInner,
2971            b: Option<TestInner>, // could be literally anything
2972        }
2973
2974        let schema = Schema::parse_str(
2975            r#"
2976        {
2977            "type":"record",
2978            "name":"TestStruct",
2979            "fields": [
2980                {
2981                    "name":"a",
2982                    "type":{
2983                        "type":"record",
2984                        "name": "Inner",
2985                        "fields": [ {
2986                            "name":"z",
2987                            "type":"int"
2988                        }]
2989                    }
2990                },
2991                {
2992                    "name":"b",
2993                    "type":"Inner"
2994                }
2995            ]
2996        }"#,
2997        )?;
2998
2999        let test_inner = TestInner { z: 3 };
3000        let test_outer1 = TestRefSchemaStruct1 {
3001            a: test_inner.clone(),
3002            b: "testing".into(),
3003        };
3004        let test_outer2 = TestRefSchemaStruct2 {
3005            a: test_inner.clone(),
3006            b: 24,
3007        };
3008        let test_outer3 = TestRefSchemaStruct3 {
3009            a: test_inner,
3010            b: None,
3011        };
3012
3013        let test_outer1: Value = to_value(test_outer1)?;
3014        let test_outer2: Value = to_value(test_outer2)?;
3015        let test_outer3: Value = to_value(test_outer3)?;
3016
3017        assert!(
3018            !test_outer1.validate(&schema),
3019            "field b record is invalid against the schema"
3020        );
3021        assert!(
3022            !test_outer2.validate(&schema),
3023            "field b record is invalid against the schema"
3024        );
3025        assert!(
3026            !test_outer3.validate(&schema),
3027            "field b record is invalid against the schema"
3028        );
3029
3030        Ok(())
3031    }
3032
3033    fn avro_3674_with_or_without_namespace(with_namespace: bool) -> TestResult {
3034        use serde::Serialize;
3035
3036        let schema_str = r#"
3037        {
3038            "type": "record",
3039            "name": "NamespacedMessage",
3040            [NAMESPACE]
3041            "fields": [
3042                {
3043                    "name": "field_a",
3044                    "type": {
3045                        "type": "record",
3046                        "name": "NestedMessage",
3047                        "fields": [
3048                            {
3049                                "name": "enum_a",
3050                                "type": {
3051                                "type": "enum",
3052                                "name": "EnumType",
3053                                "symbols": ["SYMBOL_1", "SYMBOL_2"],
3054                                "default": "SYMBOL_1"
3055                                }
3056                            },
3057                            {
3058                                "name": "enum_b",
3059                                "type": "EnumType"
3060                            }
3061                        ]
3062                    }
3063                }
3064            ]
3065        }
3066        "#;
3067        let schema_str = schema_str.replace(
3068            "[NAMESPACE]",
3069            if with_namespace {
3070                r#""namespace": "com.domain","#
3071            } else {
3072                ""
3073            },
3074        );
3075
3076        let schema = Schema::parse_str(&schema_str)?;
3077
3078        #[derive(Serialize)]
3079        enum EnumType {
3080            #[serde(rename = "SYMBOL_1")]
3081            Symbol1,
3082            #[serde(rename = "SYMBOL_2")]
3083            Symbol2,
3084        }
3085
3086        #[derive(Serialize)]
3087        struct FieldA {
3088            enum_a: EnumType,
3089            enum_b: EnumType,
3090        }
3091
3092        #[derive(Serialize)]
3093        struct NamespacedMessage {
3094            field_a: FieldA,
3095        }
3096
3097        let msg = NamespacedMessage {
3098            field_a: FieldA {
3099                enum_a: EnumType::Symbol2,
3100                enum_b: EnumType::Symbol1,
3101            },
3102        };
3103
3104        let test_value: Value = to_value(msg)?;
3105        assert!(test_value.validate(&schema), "test_value should validate");
3106        assert!(
3107            test_value.resolve(&schema).is_ok(),
3108            "test_value should resolve"
3109        );
3110
3111        Ok(())
3112    }
3113
3114    #[test]
3115    fn test_avro_3674_validate_no_namespace_resolution() -> TestResult {
3116        avro_3674_with_or_without_namespace(false)
3117    }
3118
3119    #[test]
3120    fn test_avro_3674_validate_with_namespace_resolution() -> TestResult {
3121        avro_3674_with_or_without_namespace(true)
3122    }
3123
3124    fn avro_3688_schema_resolution_panic(set_field_b: bool) -> TestResult {
3125        use serde::{Deserialize, Serialize};
3126
3127        let schema_str = r#"{
3128            "type": "record",
3129            "name": "Message",
3130            "fields": [
3131                {
3132                    "name": "field_a",
3133                    "type": [
3134                        "null",
3135                        {
3136                            "name": "Inner",
3137                            "type": "record",
3138                            "fields": [
3139                                {
3140                                    "name": "inner_a",
3141                                    "type": "string"
3142                                }
3143                            ]
3144                        }
3145                    ],
3146                    "default": null
3147                },
3148                {
3149                    "name": "field_b",
3150                    "type": [
3151                        "null",
3152                        "Inner"
3153                    ],
3154                    "default": null
3155                }
3156            ]
3157        }"#;
3158
3159        #[derive(Serialize, Deserialize)]
3160        struct Inner {
3161            inner_a: String,
3162        }
3163
3164        #[derive(Serialize, Deserialize)]
3165        struct Message {
3166            field_a: Option<Inner>,
3167            field_b: Option<Inner>,
3168        }
3169
3170        let schema = Schema::parse_str(schema_str)?;
3171
3172        let msg = Message {
3173            field_a: Some(Inner {
3174                inner_a: "foo".to_string(),
3175            }),
3176            field_b: if set_field_b {
3177                Some(Inner {
3178                    inner_a: "bar".to_string(),
3179                })
3180            } else {
3181                None
3182            },
3183        };
3184
3185        let test_value: Value = to_value(msg)?;
3186        assert!(test_value.validate(&schema), "test_value should validate");
3187        assert!(
3188            test_value.resolve(&schema).is_ok(),
3189            "test_value should resolve"
3190        );
3191
3192        Ok(())
3193    }
3194
3195    #[test]
3196    fn test_avro_3688_field_b_not_set() -> TestResult {
3197        avro_3688_schema_resolution_panic(false)
3198    }
3199
3200    #[test]
3201    fn test_avro_3688_field_b_set() -> TestResult {
3202        avro_3688_schema_resolution_panic(true)
3203    }
3204
3205    #[test]
3206    fn test_avro_3764_use_resolve_schemata() -> TestResult {
3207        let referenced_schema =
3208            r#"{"name": "enumForReference", "type": "enum", "symbols": ["A", "B"]}"#;
3209        let main_schema = r#"{"name": "recordWithReference", "type": "record", "fields": [{"name": "reference", "type": "enumForReference"}]}"#;
3210
3211        let value: serde_json::Value = serde_json::from_str(
3212            r#"
3213            {
3214                "reference": "A"
3215            }
3216        "#,
3217        )?;
3218
3219        let avro_value = Value::try_from(value)?;
3220
3221        let schemas = Schema::parse_list([main_schema, referenced_schema])?;
3222
3223        let main_schema = schemas.first().unwrap();
3224        let schemata: Vec<_> = schemas.iter().skip(1).collect();
3225
3226        let resolve_result = avro_value.clone().resolve_schemata(main_schema, schemata);
3227
3228        assert!(
3229            resolve_result.is_ok(),
3230            "result of resolving with schemata should be ok, got: {resolve_result:?}"
3231        );
3232
3233        let resolve_result = avro_value.resolve(main_schema);
3234        assert!(
3235            resolve_result.is_err(),
3236            "result of resolving without schemata should be err, got: {resolve_result:?}"
3237        );
3238
3239        Ok(())
3240    }
3241
3242    #[test]
3243    fn test_avro_3767_union_resolve_complex_refs() -> TestResult {
3244        let referenced_enum =
3245            r#"{"name": "enumForReference", "type": "enum", "symbols": ["A", "B"]}"#;
3246        let referenced_record = r#"{"name": "recordForReference", "type": "record", "fields": [{"name": "refInRecord", "type": "enumForReference"}]}"#;
3247        let main_schema = r#"{"name": "recordWithReference", "type": "record", "fields": [{"name": "reference", "type": ["null", "recordForReference"]}]}"#;
3248
3249        let value: serde_json::Value = serde_json::from_str(
3250            r#"
3251            {
3252                "reference": {
3253                    "refInRecord": "A"
3254                }
3255            }
3256        "#,
3257        )?;
3258
3259        let avro_value = Value::try_from(value)?;
3260
3261        let schemata = Schema::parse_list([referenced_enum, referenced_record, main_schema])?;
3262
3263        let main_schema = schemata.last().unwrap();
3264        let other_schemata: Vec<&Schema> = schemata.iter().take(2).collect();
3265
3266        let resolve_result = avro_value.resolve_schemata(main_schema, other_schemata)?;
3267
3268        let schemata_ref = schemata.iter().collect::<Vec<_>>();
3269        assert!(
3270            resolve_result.validate_schemata(&schemata_ref),
3271            "result of validation with schemata should be true"
3272        );
3273
3274        Ok(())
3275    }
3276
3277    #[test]
3278    fn test_avro_3782_incorrect_decimal_resolving() -> TestResult {
3279        let schema = r#"{"name": "decimalSchema", "logicalType": "decimal", "type": "fixed", "precision": 8, "scale": 0, "size": 8}"#;
3280
3281        let avro_value = Value::Decimal(Decimal::from(
3282            BigInt::from(12345678u32).to_signed_bytes_be(),
3283        ));
3284        let schema = Schema::parse_str(schema)?;
3285        let resolve_result = avro_value.resolve(&schema);
3286        assert!(
3287            resolve_result.is_ok(),
3288            "resolve result must be ok, got: {resolve_result:?}"
3289        );
3290
3291        Ok(())
3292    }
3293
3294    #[test]
3295    fn test_avro_3779_bigdecimal_resolving() -> TestResult {
3296        let schema =
3297            r#"{"name": "bigDecimalSchema", "logicalType": "big-decimal", "type": "bytes" }"#;
3298
3299        let avro_value = Value::BigDecimal(BigDecimal::from(12345678u32));
3300        let schema = Schema::parse_str(schema)?;
3301        let resolve_result: AvroResult<Value> = avro_value.resolve(&schema);
3302        assert!(
3303            resolve_result.is_ok(),
3304            "resolve result must be ok, got: {resolve_result:?}"
3305        );
3306
3307        Ok(())
3308    }
3309
3310    #[test]
3311    fn test_avro_3892_resolve_fixed_from_bytes() -> TestResult {
3312        let value = Value::Bytes(vec![97, 98, 99]);
3313        assert_eq!(
3314            value.resolve(&Schema::Fixed(FixedSchema {
3315                name: "test".try_into()?,
3316                aliases: None,
3317                doc: None,
3318                size: 3,
3319                attributes: Default::default()
3320            }))?,
3321            Value::Fixed(3, vec![97, 98, 99])
3322        );
3323
3324        let value = Value::Bytes(vec![97, 99]);
3325        assert!(
3326            value
3327                .resolve(&Schema::Fixed(FixedSchema {
3328                    name: "test".try_into()?,
3329                    aliases: None,
3330                    doc: None,
3331                    size: 3,
3332                    attributes: Default::default()
3333                }))
3334                .is_err(),
3335        );
3336
3337        let value = Value::Bytes(vec![97, 98, 99, 100]);
3338        assert!(
3339            value
3340                .resolve(&Schema::Fixed(FixedSchema {
3341                    name: "test".try_into()?,
3342                    aliases: None,
3343                    doc: None,
3344                    size: 3,
3345                    attributes: Default::default()
3346                }))
3347                .is_err(),
3348        );
3349
3350        Ok(())
3351    }
3352
3353    #[test]
3354    fn avro_3928_from_serde_value_to_types_value() -> TestResult {
3355        assert_eq!(Value::try_from(serde_json::Value::Null)?, Value::Null);
3356        assert_eq!(Value::try_from(json!(true))?, Value::Boolean(true));
3357        assert_eq!(Value::try_from(json!(false))?, Value::Boolean(false));
3358        assert_eq!(Value::try_from(json!(0))?, Value::Int(0));
3359        assert_eq!(Value::try_from(json!(i32::MIN))?, Value::Int(i32::MIN));
3360        assert_eq!(Value::try_from(json!(i32::MAX))?, Value::Int(i32::MAX));
3361        assert_eq!(
3362            Value::try_from(json!(i32::MIN as i64 - 1))?,
3363            Value::Long(i32::MIN as i64 - 1)
3364        );
3365        assert_eq!(
3366            Value::try_from(json!(i32::MAX as i64 + 1))?,
3367            Value::Long(i32::MAX as i64 + 1)
3368        );
3369        assert_eq!(Value::try_from(json!(1.23))?, Value::Double(1.23));
3370        assert_eq!(Value::try_from(json!(-1.23))?, Value::Double(-1.23));
3371        assert_eq!(
3372            Value::try_from(json!(u64::MIN))?,
3373            Value::Int(u64::MIN as i32)
3374        );
3375        assert_eq!(
3376            Value::try_from(json!("some text"))?,
3377            Value::String("some text".into())
3378        );
3379        assert_eq!(
3380            Value::try_from(json!(["text1", "text2", "text3"]))?,
3381            Value::Array(vec![
3382                Value::String("text1".into()),
3383                Value::String("text2".into()),
3384                Value::String("text3".into())
3385            ])
3386        );
3387        assert_eq!(
3388            Value::try_from(json!({"key1": "value1", "key2": "value2"}))?,
3389            Value::Map(
3390                vec![
3391                    ("key1".into(), Value::String("value1".into())),
3392                    ("key2".into(), Value::String("value2".into()))
3393                ]
3394                .into_iter()
3395                .collect()
3396            )
3397        );
3398        Ok(())
3399    }
3400
3401    #[test]
3402    fn avro_4024_resolve_double_from_unknown_string_err() -> TestResult {
3403        let schema = Schema::parse_str(r#"{"type": "double"}"#)?;
3404        let value = Value::String("unknown".to_owned());
3405        match value.resolve(&schema).map_err(Error::into_details) {
3406            Err(err @ Details::GetDouble(_)) => {
3407                assert_eq!(
3408                    format!("{err:?}"),
3409                    r#"Expected Value::Double, Value::Float, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: String("unknown")"#
3410                );
3411            }
3412            other => {
3413                panic!("Expected Details::GetDouble, got {other:?}");
3414            }
3415        }
3416        Ok(())
3417    }
3418
3419    #[test]
3420    fn avro_4024_resolve_float_from_unknown_string_err() -> TestResult {
3421        let schema = Schema::parse_str(r#"{"type": "float"}"#)?;
3422        let value = Value::String("unknown".to_owned());
3423        match value.resolve(&schema).map_err(Error::into_details) {
3424            Err(err @ Details::GetFloat(_)) => {
3425                assert_eq!(
3426                    format!("{err:?}"),
3427                    r#"Expected Value::Float, Value::Double, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: String("unknown")"#
3428                );
3429            }
3430            other => {
3431                panic!("Expected Details::GetFloat, got {other:?}");
3432            }
3433        }
3434        Ok(())
3435    }
3436
3437    #[test]
3438    fn avro_4029_resolve_from_unsupported_err() -> TestResult {
3439        let data: Vec<(&str, Value, &str)> = vec![
3440            (
3441                r#"{ "name": "NAME", "type": "int" }"#,
3442                Value::Float(123_f32),
3443                "Expected Value::Int, got: Float(123.0)",
3444            ),
3445            (
3446                r#"{ "name": "NAME", "type": "fixed", "size": 3 }"#,
3447                Value::Float(123_f32),
3448                "String expected for fixed, got: Float(123.0)",
3449            ),
3450            (
3451                r#"{ "name": "NAME", "type": "bytes" }"#,
3452                Value::Float(123_f32),
3453                "Expected Value::Bytes, got: Float(123.0)",
3454            ),
3455            (
3456                r#"{ "name": "NAME", "type": "string", "logicalType": "uuid" }"#,
3457                Value::String("abc-1234".into()),
3458                "Failed to convert &str to UUID: invalid group count: expected 5, found 2",
3459            ),
3460            (
3461                r#"{ "name": "NAME", "type": "string", "logicalType": "uuid" }"#,
3462                Value::Float(123_f32),
3463                "Expected Value::Uuid, got: Float(123.0)",
3464            ),
3465            (
3466                r#"{ "name": "NAME", "type": "bytes", "logicalType": "big-decimal" }"#,
3467                Value::Float(123_f32),
3468                "Expected Value::BigDecimal, got: Float(123.0)",
3469            ),
3470            (
3471                r#"{ "name": "NAME", "type": "fixed", "size": 12, "logicalType": "duration" }"#,
3472                Value::Float(123_f32),
3473                "Expected Value::Duration or Value::Fixed(12), got: Float(123.0)",
3474            ),
3475            (
3476                r#"{ "name": "NAME", "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 3 }"#,
3477                Value::Float(123_f32),
3478                "Expected Value::Decimal, Value::Bytes, Value::Fixed or Value::String, got: Float(123.0)",
3479            ),
3480            (
3481                r#"{ "name": "NAME", "type": "bytes" }"#,
3482                Value::Array(vec![Value::Long(256_i64)]),
3483                "Unable to convert to u8, got Int(256)",
3484            ),
3485            (
3486                r#"{ "name": "NAME", "type": "int", "logicalType": "date" }"#,
3487                Value::Float(123_f32),
3488                "Expected Value::Date or Value::Int, got: Float(123.0)",
3489            ),
3490            (
3491                r#"{ "name": "NAME", "type": "int", "logicalType": "time-millis" }"#,
3492                Value::Float(123_f32),
3493                "Expected Value::TimeMillis or Value::Int, got: Float(123.0)",
3494            ),
3495            (
3496                r#"{ "name": "NAME", "type": "long", "logicalType": "time-micros" }"#,
3497                Value::Float(123_f32),
3498                "Expected Value::TimeMicros, Value::Long or Value::Int, got: Float(123.0)",
3499            ),
3500            (
3501                r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-millis" }"#,
3502                Value::Float(123_f32),
3503                "Expected Value::TimestampMillis, Value::Long or Value::Int, got: Float(123.0)",
3504            ),
3505            (
3506                r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-micros" }"#,
3507                Value::Float(123_f32),
3508                "Expected Value::TimestampMicros, Value::Long or Value::Int, got: Float(123.0)",
3509            ),
3510            (
3511                r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-nanos" }"#,
3512                Value::Float(123_f32),
3513                "Expected Value::TimestampNanos, Value::Long or Value::Int, got: Float(123.0)",
3514            ),
3515            (
3516                r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-millis" }"#,
3517                Value::Float(123_f32),
3518                "Expected Value::LocalTimestampMillis, Value::Long or Value::Int, got: Float(123.0)",
3519            ),
3520            (
3521                r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-micros" }"#,
3522                Value::Float(123_f32),
3523                "Expected Value::LocalTimestampMicros, Value::Long or Value::Int, got: Float(123.0)",
3524            ),
3525            (
3526                r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-nanos" }"#,
3527                Value::Float(123_f32),
3528                "Expected Value::LocalTimestampNanos, Value::Long or Value::Int, got: Float(123.0)",
3529            ),
3530            (
3531                r#"{ "name": "NAME", "type": "null" }"#,
3532                Value::Float(123_f32),
3533                "Expected Value::Null, got: Float(123.0)",
3534            ),
3535            (
3536                r#"{ "name": "NAME", "type": "boolean" }"#,
3537                Value::Float(123_f32),
3538                "Expected Value::Boolean, got: Float(123.0)",
3539            ),
3540            (
3541                r#"{ "name": "NAME", "type": "int" }"#,
3542                Value::Float(123_f32),
3543                "Expected Value::Int, got: Float(123.0)",
3544            ),
3545            (
3546                r#"{ "name": "NAME", "type": "long" }"#,
3547                Value::Float(123_f32),
3548                "Expected Value::Long or Value::Int, got: Float(123.0)",
3549            ),
3550            (
3551                r#"{ "name": "NAME", "type": "float" }"#,
3552                Value::Boolean(false),
3553                r#"Expected Value::Float, Value::Double, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: Boolean(false)"#,
3554            ),
3555            (
3556                r#"{ "name": "NAME", "type": "double" }"#,
3557                Value::Boolean(false),
3558                r#"Expected Value::Double, Value::Float, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: Boolean(false)"#,
3559            ),
3560            (
3561                r#"{ "name": "NAME", "type": "string" }"#,
3562                Value::Boolean(false),
3563                "Expected Value::String, Value::Bytes or Value::Fixed, got: Boolean(false)",
3564            ),
3565            (
3566                r#"{ "name": "NAME", "type": "enum", "symbols": ["one", "two"] }"#,
3567                Value::Boolean(false),
3568                "Expected Value::Enum, got: Boolean(false)",
3569            ),
3570        ];
3571
3572        for (schema_str, value, expected_error) in data {
3573            let schema = Schema::parse_str(schema_str)?;
3574            match value.resolve(&schema) {
3575                Err(error) => {
3576                    assert_eq!(format!("{error}"), expected_error);
3577                }
3578                other => {
3579                    panic!("Expected '{expected_error}', got {other:?}");
3580                }
3581            }
3582        }
3583        Ok(())
3584    }
3585
3586    #[test]
3587    fn avro_rs_130_get_from_record() -> TestResult {
3588        let schema = r#"
3589        {
3590            "type": "record",
3591            "name": "NamespacedMessage",
3592            "namespace": "space",
3593            "fields": [
3594                {
3595                    "name": "foo",
3596                    "type": "string"
3597                },
3598                {
3599                    "name": "bar",
3600                    "type": "long"
3601                }
3602            ]
3603        }
3604        "#;
3605
3606        let schema = Schema::parse_str(schema)?;
3607        let mut record = Record::new(&schema).unwrap();
3608        record.put("foo", "hello");
3609        record.put("bar", 123_i64);
3610
3611        assert_eq!(
3612            record.get("foo").unwrap(),
3613            &Value::String("hello".to_string())
3614        );
3615        assert_eq!(record.get("bar").unwrap(), &Value::Long(123));
3616
3617        // also make sure it doesn't fail but return None for non-existing field
3618        assert_eq!(record.get("baz"), None);
3619
3620        Ok(())
3621    }
3622
3623    #[test]
3624    fn avro_rs_392_resolve_long_to_int() {
3625        // Values that are valid as in i32 should work
3626        let value = Value::Long(0);
3627        value.resolve(&Schema::Int).unwrap();
3628        // Values that are outside the i32 range should not
3629        let value = Value::Long(i64::MAX);
3630        assert!(matches!(
3631            value.resolve(&Schema::Int).unwrap_err().details(),
3632            Details::ZagI32(_, _)
3633        ));
3634    }
3635
3636    #[test]
3637    fn avro_rs_450_serde_json_number_u64_max() {
3638        assert_eq!(
3639            Value::try_from(json!(u64::MAX))
3640                .unwrap_err()
3641                .into_details()
3642                .to_string(),
3643            "JSON number 18446744073709551615 could not be converted into an Avro value as it's too large"
3644        );
3645    }
3646}