blob: 6562e622e7c43d656e8ae01f33f5cd145885bf8d [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! Logic for serde-compatible deserialization.
use crate::{types::Value, Error};
use serde::{
de::{self, DeserializeSeed, Visitor},
forward_to_deserialize_any, Deserialize,
};
use std::{
collections::{
hash_map::{Keys, Values},
HashMap,
},
slice::Iter,
};
pub struct Deserializer<'de> {
input: &'de Value,
}
struct SeqDeserializer<'de> {
input: Iter<'de, Value>,
}
struct MapDeserializer<'de> {
input_keys: Keys<'de, String, Value>,
input_values: Values<'de, String, Value>,
}
struct StructDeserializer<'de> {
input: Iter<'de, (String, Value)>,
value: Option<&'de Value>,
}
pub struct EnumUnitDeserializer<'a> {
input: &'a str,
}
pub struct EnumDeserializer<'de> {
input: &'de [(String, Value)],
}
impl<'de> Deserializer<'de> {
pub fn new(input: &'de Value) -> Self {
Deserializer { input }
}
}
impl<'de> SeqDeserializer<'de> {
pub fn new(input: &'de [Value]) -> Self {
SeqDeserializer {
input: input.iter(),
}
}
}
impl<'de> MapDeserializer<'de> {
pub fn new(input: &'de HashMap<String, Value>) -> Self {
MapDeserializer {
input_keys: input.keys(), // input.keys().map(|k| Value::String(k.clone())).collect::<Vec<_>>().iter(),
input_values: input.values(),
// keys: input.keys().map(|s| Value::String(s.to_owned())).collect::<Vec<Value>>(),
// values: input.values().map(|s| s.to_owned()).collect::<Vec<Value>>(),
}
}
}
impl<'de> StructDeserializer<'de> {
pub fn new(input: &'de [(String, Value)]) -> Self {
StructDeserializer {
input: input.iter(),
value: None,
}
}
}
impl<'a> EnumUnitDeserializer<'a> {
pub fn new(input: &'a str) -> Self {
EnumUnitDeserializer { input }
}
}
impl<'de> EnumDeserializer<'de> {
pub fn new(input: &'de [(String, Value)]) -> Self {
EnumDeserializer { input }
}
}
impl<'de> de::EnumAccess<'de> for EnumUnitDeserializer<'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
Ok((
seed.deserialize(StringDeserializer {
input: self.input.to_owned(),
})?,
self,
))
}
}
impl<'de> de::VariantAccess<'de> for EnumUnitDeserializer<'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Error>
where
T: DeserializeSeed<'de>,
{
Err(de::Error::custom("Unexpected Newtype variant"))
}
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
Err(de::Error::custom("Unexpected tuple variant"))
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
Err(de::Error::custom("Unexpected struct variant"))
}
}
impl<'de> de::EnumAccess<'de> for EnumDeserializer<'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
self.input.first().map_or(
Err(de::Error::custom("A record must have a least one field")),
|item| match (item.0.as_ref(), &item.1) {
("type", Value::String(x)) | ("type", Value::Enum(_, x)) => Ok((
seed.deserialize(StringDeserializer {
input: x.to_owned(),
})?,
self,
)),
(field, Value::String(_)) => Err(de::Error::custom(format!(
"Expected first field named 'type': got '{}' instead",
field
))),
(_, _) => Err(de::Error::custom(
"Expected first field of type String or Enum for the type name".to_string(),
)),
},
)
}
}
impl<'de> de::VariantAccess<'de> for EnumDeserializer<'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
where
T: DeserializeSeed<'de>,
{
self.input.get(1).map_or(
Err(de::Error::custom(
"Expected a newtype variant, got nothing instead.",
)),
|item| seed.deserialize(&Deserializer::new(&item.1)),
)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
self.input.get(1).map_or(
Err(de::Error::custom(
"Expected a tuple variant, got nothing instead.",
)),
|item| de::Deserializer::deserialize_seq(&Deserializer::new(&item.1), visitor),
)
}
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
self.input.get(1).map_or(
Err(de::Error::custom("Expected a struct variant, got nothing")),
|item| {
de::Deserializer::deserialize_struct(
&Deserializer::new(&item.1),
"",
fields,
visitor,
)
},
)
}
}
impl<'a, 'de> de::Deserializer<'de> for &'a Deserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.input {
Value::Null => visitor.visit_unit(),
&Value::Boolean(b) => visitor.visit_bool(b),
Value::Int(i) | Value::Date(i) | Value::TimeMillis(i) => visitor.visit_i32(*i),
Value::Long(i)
| Value::TimeMicros(i)
| Value::TimestampMillis(i)
| Value::TimestampMicros(i) => visitor.visit_i64(*i),
&Value::Float(f) => visitor.visit_f32(f),
&Value::Double(d) => visitor.visit_f64(d),
Value::Union(_i, u) => match **u {
Value::Null => visitor.visit_unit(),
Value::Boolean(b) => visitor.visit_bool(b),
Value::Int(i) => visitor.visit_i32(i),
Value::Long(i)
| Value::TimeMicros(i)
| Value::TimestampMillis(i)
| Value::TimestampMicros(i) => visitor.visit_i64(i),
Value::Float(f) => visitor.visit_f32(f),
Value::Double(d) => visitor.visit_f64(d),
Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
Value::Array(ref fields) => visitor.visit_seq(SeqDeserializer::new(fields)),
Value::String(ref s) => visitor.visit_borrowed_str(s),
Value::Map(ref items) => visitor.visit_map(MapDeserializer::new(items)),
_ => Err(de::Error::custom(format!(
"unsupported union: {:?}",
self.input
))),
},
Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
Value::Array(ref fields) => visitor.visit_seq(SeqDeserializer::new(fields)),
Value::String(ref s) => visitor.visit_borrowed_str(s),
Value::Map(ref items) => visitor.visit_map(MapDeserializer::new(items)),
value => Err(de::Error::custom(format!(
"incorrect value of type: {:?}",
crate::schema::SchemaKind::from(value)
))),
}
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64
}
fn deserialize_char<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(de::Error::custom("avro does not support char"))
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::String(ref s) => visitor.visit_borrowed_str(s),
Value::Bytes(ref bytes) | Value::Fixed(_, ref bytes) => ::std::str::from_utf8(bytes)
.map_err(|e| de::Error::custom(e.to_string()))
.and_then(|s| visitor.visit_borrowed_str(s)),
Value::Uuid(ref u) => visitor.visit_str(&u.to_string()),
_ => Err(de::Error::custom("not a string|bytes|fixed")),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::String(ref s) => visitor.visit_borrowed_str(s),
Value::Bytes(ref bytes) | Value::Fixed(_, ref bytes) => {
String::from_utf8(bytes.to_owned())
.map_err(|e| de::Error::custom(e.to_string()))
.and_then(|s| visitor.visit_string(s))
}
Value::Union(_i, ref x) => match **x {
Value::String(ref s) => visitor.visit_borrowed_str(s),
_ => Err(de::Error::custom("not a string|bytes|fixed")),
},
_ => Err(de::Error::custom("not a string|bytes|fixed")),
}
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::String(ref s) => visitor.visit_bytes(s.as_bytes()),
Value::Bytes(ref bytes) | Value::Fixed(_, ref bytes) => visitor.visit_bytes(bytes),
Value::Uuid(ref u) => visitor.visit_bytes(u.as_bytes()),
_ => Err(de::Error::custom("not a string|bytes|fixed")),
}
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::String(ref s) => visitor.visit_byte_buf(s.clone().into_bytes()),
Value::Bytes(ref bytes) | Value::Fixed(_, ref bytes) => {
visitor.visit_byte_buf(bytes.to_owned())
}
_ => Err(de::Error::custom("not a string|bytes|fixed")),
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::Union(_i, ref inner) if inner.as_ref() == &Value::Null => visitor.visit_none(),
Value::Union(_i, ref inner) => visitor.visit_some(&Deserializer::new(inner)),
_ => Err(de::Error::custom("not a union")),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::Null => visitor.visit_unit(),
_ => Err(de::Error::custom("not a null")),
}
}
fn deserialize_unit_struct<V>(
self,
_: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(
self,
_: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::Array(ref items) => visitor.visit_seq(SeqDeserializer::new(items)),
Value::Union(_i, ref inner) => match **inner {
Value::Array(ref items) => visitor.visit_seq(SeqDeserializer::new(items)),
_ => Err(de::Error::custom("not an array")),
},
_ => Err(de::Error::custom("not an array")),
}
}
fn deserialize_tuple<V>(self, _: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_: &'static str,
_: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::Map(ref items) => visitor.visit_map(MapDeserializer::new(items)),
_ => Err(de::Error::custom("not a map")),
}
}
fn deserialize_struct<V>(
self,
_: &'static str,
_: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
Value::Union(_i, ref inner) => match **inner {
Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
_ => Err(de::Error::custom("not a record")),
},
_ => Err(de::Error::custom("not a record")),
}
}
fn deserialize_enum<V>(
self,
_: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.input {
// This branch can be anything...
Value::Record(ref fields) => visitor.visit_enum(EnumDeserializer::new(fields)),
// This has to be a unit Enum
Value::Enum(_index, ref field) => visitor.visit_enum(EnumUnitDeserializer::new(field)),
_ => Err(de::Error::custom("not an enum")),
}
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
impl<'de> de::SeqAccess<'de> for SeqDeserializer<'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.input.next() {
Some(item) => seed.deserialize(&Deserializer::new(item)).map(Some),
None => Ok(None),
}
}
}
impl<'de> de::MapAccess<'de> for MapDeserializer<'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
match self.input_keys.next() {
Some(key) => seed
.deserialize(StringDeserializer {
input: (*key).clone(),
})
.map(Some),
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
{
match self.input_values.next() {
Some(value) => seed.deserialize(&Deserializer::new(value)),
None => Err(de::Error::custom("should not happen - too many values")),
}
}
}
impl<'de> de::MapAccess<'de> for StructDeserializer<'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
match self.input.next() {
Some(item) => {
let (ref field, ref value) = *item;
self.value = Some(value);
seed.deserialize(StringDeserializer {
input: field.clone(),
})
.map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
{
match self.value.take() {
Some(value) => seed.deserialize(&Deserializer::new(value)),
None => Err(de::Error::custom("should not happen - too many values")),
}
}
}
#[derive(Clone)]
struct StringDeserializer {
input: String,
}
impl<'de> de::Deserializer<'de> for StringDeserializer {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_string(self.input)
}
forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq bytes byte_buf map unit_struct newtype_struct
tuple_struct struct tuple enum identifier ignored_any
}
}
/// Interpret a `Value` as an instance of type `D`.
///
/// This conversion can fail if the structure of the `Value` does not match the
/// structure expected by `D`.
pub fn from_value<'de, D: Deserialize<'de>>(value: &'de Value) -> Result<D, Error> {
let de = Deserializer::new(value);
D::deserialize(&de)
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use serde::Serialize;
use uuid::Uuid;
use super::*;
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
struct Test {
a: i64,
b: String,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct TestInner {
a: Test,
b: i32,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct TestUnitExternalEnum {
a: UnitExternalEnum,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
enum UnitExternalEnum {
Val1,
Val2,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct TestUnitInternalEnum {
a: UnitInternalEnum,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "t")]
enum UnitInternalEnum {
Val1,
Val2,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct TestUnitAdjacentEnum {
a: UnitAdjacentEnum,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "t", content = "v")]
enum UnitAdjacentEnum {
Val1,
Val2,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct TestUnitUntaggedEnum {
a: UnitUntaggedEnum,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
enum UnitUntaggedEnum {
Val1,
Val2,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct TestSingleValueExternalEnum {
a: SingleValueExternalEnum,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum SingleValueExternalEnum {
Double(f64),
String(String),
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct TestStructExternalEnum {
a: StructExternalEnum,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum StructExternalEnum {
Val1 { x: f32, y: f32 },
Val2 { x: f32, y: f32 },
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct TestTupleExternalEnum {
a: TupleExternalEnum,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum TupleExternalEnum {
Val1(f32, f32),
Val2(f32, f32, f32),
}
#[test]
fn test_from_value() {
let test = Value::Record(vec![
("a".to_owned(), Value::Long(27)),
("b".to_owned(), Value::String("foo".to_owned())),
]);
let expected = Test {
a: 27,
b: "foo".to_owned(),
};
let final_value: Test = from_value(&test).unwrap();
assert_eq!(final_value, expected);
let test_inner = Value::Record(vec![
(
"a".to_owned(),
Value::Record(vec![
("a".to_owned(), Value::Long(27)),
("b".to_owned(), Value::String("foo".to_owned())),
]),
),
("b".to_owned(), Value::Int(35)),
]);
let expected_inner = TestInner { a: expected, b: 35 };
let final_value: TestInner = from_value(&test_inner).unwrap();
assert_eq!(final_value, expected_inner)
}
#[test]
fn test_from_value_unit_enum() {
let expected = TestUnitExternalEnum {
a: UnitExternalEnum::Val1,
};
let test = Value::Record(vec![("a".to_owned(), Value::Enum(0, "Val1".to_owned()))]);
let final_value: TestUnitExternalEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"Error deserializing unit external enum"
);
let expected = TestUnitInternalEnum {
a: UnitInternalEnum::Val1,
};
let test = Value::Record(vec![(
"a".to_owned(),
Value::Record(vec![("t".to_owned(), Value::String("Val1".to_owned()))]),
)]);
let final_value: TestUnitInternalEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"Error deserializing unit internal enum"
);
let expected = TestUnitAdjacentEnum {
a: UnitAdjacentEnum::Val1,
};
let test = Value::Record(vec![(
"a".to_owned(),
Value::Record(vec![("t".to_owned(), Value::String("Val1".to_owned()))]),
)]);
let final_value: TestUnitAdjacentEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"Error deserializing unit adjacent enum"
);
let expected = TestUnitUntaggedEnum {
a: UnitUntaggedEnum::Val1,
};
let test = Value::Record(vec![("a".to_owned(), Value::Null)]);
let final_value: TestUnitUntaggedEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"Error deserializing unit untagged enum"
);
}
#[test]
fn test_from_value_single_value_enum() {
let expected = TestSingleValueExternalEnum {
a: SingleValueExternalEnum::Double(64.0),
};
let test = Value::Record(vec![(
"a".to_owned(),
Value::Record(vec![
("type".to_owned(), Value::String("Double".to_owned())),
(
"value".to_owned(),
Value::Union(1, Box::new(Value::Double(64.0))),
),
]),
)]);
let final_value: TestSingleValueExternalEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"Error deserializing single value external enum(union)"
);
}
#[test]
fn test_from_value_struct_enum() {
let expected = TestStructExternalEnum {
a: StructExternalEnum::Val1 { x: 1.0, y: 2.0 },
};
let test = Value::Record(vec![(
"a".to_owned(),
Value::Record(vec![
("type".to_owned(), Value::String("Val1".to_owned())),
(
"value".to_owned(),
Value::Union(
0,
Box::new(Value::Record(vec![
("x".to_owned(), Value::Float(1.0)),
("y".to_owned(), Value::Float(2.0)),
])),
),
),
]),
)]);
let final_value: TestStructExternalEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"error deserializing struct external enum(union)"
);
}
#[test]
fn test_from_value_tuple_enum() {
let expected = TestTupleExternalEnum {
a: TupleExternalEnum::Val1(1.0, 2.0),
};
let test = Value::Record(vec![(
"a".to_owned(),
Value::Record(vec![
("type".to_owned(), Value::String("Val1".to_owned())),
(
"value".to_owned(),
Value::Union(
0,
Box::new(Value::Array(vec![Value::Float(1.0), Value::Float(2.0)])),
),
),
]),
)]);
let final_value: TestTupleExternalEnum = from_value(&test).unwrap();
assert_eq!(
final_value, expected,
"error serializing tuple external enum(union)"
);
}
type TestResult<T> = Result<T, Box<dyn std::error::Error>>;
#[test]
fn test_date() -> TestResult<()> {
let raw_value = 1;
let value = Value::Date(raw_value);
let result = crate::from_value::<i32>(&value)?;
assert_eq!(result, raw_value);
Ok(())
}
#[test]
fn test_time_millis() -> TestResult<()> {
let raw_value = 1;
let value = Value::TimeMillis(raw_value);
let result = crate::from_value::<i32>(&value)?;
assert_eq!(result, raw_value);
Ok(())
}
#[test]
fn test_time_micros() -> TestResult<()> {
let raw_value = 1;
let value = Value::TimeMicros(raw_value);
let result = crate::from_value::<i64>(&value)?;
assert_eq!(result, raw_value);
Ok(())
}
#[test]
fn test_timestamp_millis() -> TestResult<()> {
let raw_value = 1;
let value = Value::TimestampMillis(raw_value);
let result = crate::from_value::<i64>(&value)?;
assert_eq!(result, raw_value);
Ok(())
}
#[test]
fn test_timestamp_micros() -> TestResult<()> {
let raw_value = 1;
let value = Value::TimestampMicros(raw_value);
let result = crate::from_value::<i64>(&value)?;
assert_eq!(result, raw_value);
Ok(())
}
#[test]
fn test_from_value_uuid_str() -> TestResult<()> {
let raw_value = "9ec535ff-3e2a-45bd-91d3-0a01321b5a49";
let value = Value::Uuid(Uuid::parse_str(raw_value).unwrap());
let result = crate::from_value::<Uuid>(&value)?;
assert_eq!(result.to_string(), raw_value);
Ok(())
}
#[test]
fn test_from_value_uuid_slice() -> TestResult<()> {
let raw_value = &[4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87];
let value = Value::Uuid(Uuid::from_slice(raw_value)?);
let result = crate::from_value::<Uuid>(&value)?;
assert_eq!(result.as_bytes(), raw_value);
Ok(())
}
#[test]
fn test_from_value_with_union() -> TestResult<()> {
// AVRO-3232 test for deserialize_any on missing fields on the destination struct:
// Error: DeserializeValue("Unsupported union")
// Error: DeserializeValue("incorrect value of type: String")
#[derive(Debug, Deserialize, PartialEq)]
struct RecordInUnion {
record_in_union: i32,
}
#[derive(Debug, Deserialize, PartialEq)]
struct StructWithMissingFields {
a_string: String,
a_record: Option<RecordInUnion>,
an_array: Option<[bool; 2]>,
a_union_map: Option<HashMap<String, i64>>,
}
let raw_map: HashMap<String, i64> = [
("long_one".to_string(), 1),
("long_two".to_string(), 2),
("long_three".to_string(), 3),
("time_micros_a".to_string(), 123),
("timestamp_millis_b".to_string(), 234),
("timestamp_micros_c".to_string(), 345),
]
.iter()
.cloned()
.collect();
let value_map = raw_map
.iter()
.map(|(k, v)| match k {
key if key.starts_with("long_") => (k.clone(), Value::Long(*v)),
key if key.starts_with("time_micros_") => (k.clone(), Value::TimeMicros(*v)),
key if key.starts_with("timestamp_millis_") => {
(k.clone(), Value::TimestampMillis(*v))
}
key if key.starts_with("timestamp_micros_") => {
(k.clone(), Value::TimestampMicros(*v))
}
_ => unreachable!("unexpected key: {:?}", k),
})
.collect();
let record = Value::Record(vec![
(
"a_string".to_string(),
Value::String("a valid message field".to_string()),
),
(
"a_non_existing_string".to_string(),
Value::String("a string".to_string()),
),
(
"a_union_string".to_string(),
Value::Union(0, Box::new(Value::String("a union string".to_string()))),
),
(
"a_union_long".to_string(),
Value::Union(0, Box::new(Value::Long(412))),
),
(
"a_union_long".to_string(),
Value::Union(0, Box::new(Value::Long(412))),
),
(
"a_time_micros".to_string(),
Value::Union(0, Box::new(Value::TimeMicros(123))),
),
(
"a_non_existing_time_micros".to_string(),
Value::Union(0, Box::new(Value::TimeMicros(-123))),
),
(
"a_timestamp_millis".to_string(),
Value::Union(0, Box::new(Value::TimestampMillis(234))),
),
(
"a_non_existing_timestamp_millis".to_string(),
Value::Union(0, Box::new(Value::TimestampMillis(-234))),
),
(
"a_timestamp_micros".to_string(),
Value::Union(0, Box::new(Value::TimestampMicros(345))),
),
(
"a_non_existing_timestamp_micros".to_string(),
Value::Union(0, Box::new(Value::TimestampMicros(-345))),
),
(
"a_record".to_string(),
Value::Union(
0,
Box::new(Value::Record(vec![(
"record_in_union".to_string(),
Value::Int(-2),
)])),
),
),
(
"a_non_existing_record".to_string(),
Value::Union(
0,
Box::new(Value::Record(vec![("blah".to_string(), Value::Int(-22))])),
),
),
(
"an_array".to_string(),
Value::Union(
0,
Box::new(Value::Array(vec![
Value::Boolean(true),
Value::Boolean(false),
])),
),
),
(
"a_non_existing_array".to_string(),
Value::Union(
0,
Box::new(Value::Array(vec![
Value::Boolean(false),
Value::Boolean(true),
])),
),
),
(
"a_union_map".to_string(),
Value::Union(0, Box::new(Value::Map(value_map))),
),
(
"a_non_existing_union_map".to_string(),
Value::Union(0, Box::new(Value::Map(HashMap::new()))),
),
]);
let deserialized: StructWithMissingFields = crate::from_value(&record)?;
let reference = StructWithMissingFields {
a_string: "a valid message field".to_string(),
a_record: Some(RecordInUnion {
record_in_union: -2,
}),
an_array: Some([true, false]),
a_union_map: Some(raw_map),
};
assert_eq!(deserialized, reference);
Ok(())
}
}