use std::collections::HashMap;
use std::fmt;
use serde::de::{self, DeserializeSeed, MapAccess, SeqAccess, Visitor};
use crate::types::{ListItem, Value};
#[derive(Debug, Clone, PartialEq)]
pub enum DeserializeError {
TypeMismatch {
expected: &'static str,
got: &'static str,
},
MissingField(String),
ParseError(String),
Custom(String),
}
impl fmt::Display for DeserializeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DeserializeError::TypeMismatch { expected, got } => {
write!(f, "type mismatch: expected {}, got {}", expected, got)
}
DeserializeError::MissingField(field) => {
write!(f, "missing field: {}", field)
}
DeserializeError::ParseError(msg) => {
write!(f, "parse error: {}", msg)
}
DeserializeError::Custom(msg) => write!(f, "{}", msg),
}
}
}
impl std::error::Error for DeserializeError {}
impl de::Error for DeserializeError {
fn custom<T: fmt::Display>(msg: T) -> Self {
DeserializeError::Custom(msg.to_string())
}
}
pub struct ValueDeserializer {
value: Value,
}
impl ValueDeserializer {
pub fn new(value: Value) -> Self {
Self { value }
}
}
impl<'de> de::Deserializer<'de> for ValueDeserializer {
type Error = DeserializeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.value {
Value::Empty => visitor.visit_none(),
Value::Single(s) => visitor.visit_string(s),
Value::List(items) => visitor.visit_seq(ListSeqAccess::new(items)),
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Single(s) => match s.to_lowercase().as_str() {
"true" | "yes" | "1" | "on" => visitor.visit_bool(true),
"false" | "no" | "0" | "off" | "" => visitor.visit_bool(false),
_ => Err(DeserializeError::ParseError(format!(
"cannot parse '{}' as bool",
s
))),
},
Value::Empty => visitor.visit_bool(false),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "bool",
got: "list",
}),
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Single(s) => {
let n: i64 = s.parse().map_err(|_| {
DeserializeError::ParseError(format!("cannot parse '{}' as integer", s))
})?;
visitor.visit_i64(n)
}
Value::Empty => visitor.visit_i64(0),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "integer",
got: "list",
}),
}
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Single(s) => {
let n: u64 = s.parse().map_err(|_| {
DeserializeError::ParseError(format!(
"cannot parse '{}' as unsigned integer",
s
))
})?;
visitor.visit_u64(n)
}
Value::Empty => visitor.visit_u64(0),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "unsigned integer",
got: "list",
}),
}
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_f64(visitor)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Single(s) => {
let n: f64 = s.parse().map_err(|_| {
DeserializeError::ParseError(format!("cannot parse '{}' as float", s))
})?;
visitor.visit_f64(n)
}
Value::Empty => visitor.visit_f64(0.0),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "float",
got: "list",
}),
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Single(s) => {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => visitor.visit_char(c),
_ => Err(DeserializeError::ParseError(format!(
"expected single character, got '{}'",
s
))),
}
}
Value::Empty => Err(DeserializeError::TypeMismatch {
expected: "char",
got: "empty",
}),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "char",
got: "list",
}),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_string(visitor)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.value {
Value::Single(s) => visitor.visit_string(s),
Value::Empty => visitor.visit_string(String::new()),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "string",
got: "list",
}),
}
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.value {
Value::Single(s) => visitor.visit_bytes(s.as_bytes()),
Value::Empty => visitor.visit_bytes(&[]),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "bytes",
got: "list",
}),
}
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Empty => visitor.visit_none(),
_ => visitor.visit_some(self),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match &self.value {
Value::Empty => visitor.visit_unit(),
_ => Err(DeserializeError::TypeMismatch {
expected: "unit",
got: "value",
}),
}
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(
self,
_name: &'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.value {
Value::List(items) => visitor.visit_seq(ListSeqAccess::new(items)),
Value::Empty => visitor.visit_seq(ListSeqAccess::new(vec![])),
Value::Single(_) => Err(DeserializeError::TypeMismatch {
expected: "sequence",
got: "string",
}),
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: 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>,
{
Err(DeserializeError::TypeMismatch {
expected: "map",
got: "value",
})
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(DeserializeError::TypeMismatch {
expected: "struct",
got: "value",
})
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.value {
Value::Single(s) => visitor.visit_enum(EnumDeserializer(s)),
Value::Empty => Err(DeserializeError::TypeMismatch {
expected: "enum",
got: "empty",
}),
Value::List(_) => Err(DeserializeError::TypeMismatch {
expected: "enum",
got: "list",
}),
}
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_string(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
}
struct StringDeserializer(String);
impl<'de> de::Deserializer<'de> for StringDeserializer {
type Error = DeserializeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_string(self.0)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
struct BorrowedStrDeserializer<'a>(&'a str);
impl<'de, 'a> de::Deserializer<'de> for BorrowedStrDeserializer<'a> {
type Error = DeserializeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(self.0)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(self.0)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(self.0)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(self.0)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum ignored_any
}
}
struct EnumDeserializer(String);
impl<'de> de::EnumAccess<'de> for EnumDeserializer {
type Error = DeserializeError;
type Variant = UnitVariantAccess;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let variant = seed.deserialize(StringDeserializer(self.0))?;
Ok((variant, UnitVariantAccess))
}
}
struct UnitVariantAccess;
impl<'de> de::VariantAccess<'de> for UnitVariantAccess {
type Error = DeserializeError;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
Err(DeserializeError::TypeMismatch {
expected: "unit variant",
got: "newtype variant",
})
}
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(DeserializeError::TypeMismatch {
expected: "unit variant",
got: "tuple variant",
})
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(DeserializeError::TypeMismatch {
expected: "unit variant",
got: "struct variant",
})
}
}
struct ListSeqAccess {
iter: std::vec::IntoIter<ListItem>,
}
impl ListSeqAccess {
fn new(items: Vec<ListItem>) -> Self {
Self {
iter: items.into_iter(),
}
}
}
impl<'de> SeqAccess<'de> for ListSeqAccess {
type Error = DeserializeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.iter.next() {
Some(item) => seed.deserialize(ListItemDeserializer::new(item)).map(Some),
None => Ok(None),
}
}
}
struct ListItemDeserializer {
item: ListItem,
}
impl ListItemDeserializer {
fn new(item: ListItem) -> Self {
Self { item }
}
}
impl<'de> de::Deserializer<'de> for ListItemDeserializer {
type Error = DeserializeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::String(s) => visitor.visit_string(s),
ListItem::Dict(map) => visitor.visit_map(DictMapAccess::new(map)),
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::String(s) => match s.to_lowercase().as_str() {
"true" | "yes" | "1" | "on" => visitor.visit_bool(true),
"false" | "no" | "0" | "off" | "" => visitor.visit_bool(false),
_ => Err(DeserializeError::ParseError(format!(
"cannot parse '{}' as bool",
s
))),
},
ListItem::Dict(_) => Err(DeserializeError::TypeMismatch {
expected: "bool",
got: "dict",
}),
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_i64(visitor)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::String(s) => {
let n: i64 = s.parse().map_err(|_| {
DeserializeError::ParseError(format!("cannot parse '{}' as integer", s))
})?;
visitor.visit_i64(n)
}
ListItem::Dict(_) => Err(DeserializeError::TypeMismatch {
expected: "integer",
got: "dict",
}),
}
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_u64(visitor)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::String(s) => {
let n: u64 = s.parse().map_err(|_| {
DeserializeError::ParseError(format!(
"cannot parse '{}' as unsigned integer",
s
))
})?;
visitor.visit_u64(n)
}
ListItem::Dict(_) => Err(DeserializeError::TypeMismatch {
expected: "unsigned integer",
got: "dict",
}),
}
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_f64(visitor)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::String(s) => {
let n: f64 = s.parse().map_err(|_| {
DeserializeError::ParseError(format!("cannot parse '{}' as float", s))
})?;
visitor.visit_f64(n)
}
ListItem::Dict(_) => Err(DeserializeError::TypeMismatch {
expected: "float",
got: "dict",
}),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_string(visitor)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::String(s) => visitor.visit_string(s),
ListItem::Dict(_) => Err(DeserializeError::TypeMismatch {
expected: "string",
got: "dict",
}),
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_some(self)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::Dict(map) => visitor.visit_map(DictMapAccess::new(map)),
ListItem::String(_) => Err(DeserializeError::TypeMismatch {
expected: "map",
got: "string",
}),
}
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.item {
ListItem::Dict(map) => visitor.visit_map(DictMapAccess::new(map)),
ListItem::String(_) => Err(DeserializeError::TypeMismatch {
expected: "struct",
got: "string",
}),
}
}
serde::forward_to_deserialize_any! {
char bytes byte_buf unit unit_struct
newtype_struct seq tuple tuple_struct enum identifier ignored_any
}
}
struct DictMapAccess {
iter: std::collections::hash_map::IntoIter<String, String>,
pending_value: Option<String>,
}
impl DictMapAccess {
fn new(map: HashMap<String, String>) -> Self {
Self {
iter: map.into_iter(),
pending_value: None,
}
}
}
impl<'de> MapAccess<'de> for DictMapAccess {
type Error = DeserializeError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
match self.iter.next() {
Some((key, value)) => {
self.pending_value = Some(value);
seed.deserialize(StringDeserializer(key)).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.pending_value.take() {
Some(value) => seed.deserialize(StringDeserializer(value)),
None => Err(DeserializeError::Custom(
"next_value_seed called without pending value".into(),
)),
}
}
}
pub struct RecordDeserializer<'a, S: AsRef<str>> {
header: &'a [S],
values: Vec<Value>,
}
impl<'a, S: AsRef<str>> RecordDeserializer<'a, S> {
pub fn new(header: &'a [S], values: Vec<Value>) -> Self {
Self { header, values }
}
}
impl<'de, 'a, S: AsRef<str>> de::Deserializer<'de> for RecordDeserializer<'a, S> {
type Error = DeserializeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_map(RecordMapAccess::new(self.header, self.values))
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct enum identifier ignored_any
}
}
struct RecordMapAccess<'a, S: AsRef<str>> {
header: &'a [S],
values: std::vec::IntoIter<Value>,
index: usize,
pending_value: Option<Value>,
}
impl<'a, S: AsRef<str>> RecordMapAccess<'a, S> {
fn new(header: &'a [S], values: Vec<Value>) -> Self {
Self {
header,
values: values.into_iter(),
index: 0,
pending_value: None,
}
}
}
impl<'de, 'a, S: AsRef<str>> MapAccess<'de> for RecordMapAccess<'a, S> {
type Error = DeserializeError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
if self.index >= self.header.len() {
return Ok(None);
}
let key = self.header[self.index].as_ref();
self.pending_value = self.values.next();
self.index += 1;
seed.deserialize(BorrowedStrDeserializer(key)).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
{
match self.pending_value.take() {
Some(value) => seed.deserialize(ValueDeserializer::new(value)),
None => seed.deserialize(ValueDeserializer::new(Value::Empty)),
}
}
}
pub fn from_value<'de, T>(value: Value) -> Result<T, DeserializeError>
where
T: de::Deserialize<'de>,
{
T::deserialize(ValueDeserializer::new(value))
}
pub fn from_record<'de, T, S>(header: &[S], values: Vec<Value>) -> Result<T, DeserializeError>
where
T: de::Deserialize<'de>,
S: AsRef<str>,
{
let lowercase_header: Vec<String> = header.iter().map(|s| s.as_ref().to_lowercase()).collect();
T::deserialize(RecordDeserializer::new(&lowercase_header, values))
}
pub fn from_record_borrowed<'de, T>(
header: &[String],
values: Vec<Value>,
) -> Result<T, DeserializeError>
where
T: de::Deserialize<'de>,
{
T::deserialize(RecordDeserializer::new(header, values))
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
#[test]
fn test_deserialize_string() {
let value = Value::Single("hello".into());
let result: String = from_value(value).unwrap();
assert_eq!(result, "hello");
}
#[test]
fn test_deserialize_empty_to_option() {
let value = Value::Empty;
let result: Option<String> = from_value(value).unwrap();
assert_eq!(result, None);
}
#[test]
fn test_deserialize_single_to_option() {
let value = Value::Single("test".into());
let result: Option<String> = from_value(value).unwrap();
assert_eq!(result, Some("test".into()));
}
#[test]
fn test_deserialize_integer() {
let value = Value::Single("42".into());
let result: i32 = from_value(value).unwrap();
assert_eq!(result, 42);
}
#[test]
fn test_deserialize_bool_true() {
let value = Value::Single("yes".into());
let result: bool = from_value(value).unwrap();
assert!(result);
}
#[test]
fn test_deserialize_bool_false() {
let value = Value::Single("no".into());
let result: bool = from_value(value).unwrap();
assert!(!result);
}
#[test]
fn test_deserialize_list_strings() {
let value = Value::List(vec![
ListItem::String("a".into()),
ListItem::String("b".into()),
ListItem::String("c".into()),
]);
let result: Vec<String> = from_value(value).unwrap();
assert_eq!(result, vec!["a", "b", "c"]);
}
#[test]
fn test_deserialize_list_integers() {
let value = Value::List(vec![
ListItem::String("1".into()),
ListItem::String("2".into()),
ListItem::String("3".into()),
]);
let result: Vec<i32> = from_value(value).unwrap();
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_deserialize_dict_to_hashmap() {
let mut map = HashMap::new();
map.insert("key1".into(), "value1".into());
map.insert("key2".into(), "value2".into());
let value = Value::List(vec![ListItem::Dict(map.clone())]);
let result: Vec<HashMap<String, String>> = from_value(value).unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].get("key1"), Some(&"value1".to_string()));
assert_eq!(result[0].get("key2"), Some(&"value2".to_string()));
}
#[test]
fn test_deserialize_record_to_struct() {
#[derive(Deserialize, Debug, PartialEq)]
struct Person {
name: String,
age: u32,
}
let header = vec!["Name".to_string(), "Age".to_string()];
let values = vec![Value::Single("Alice".into()), Value::Single("30".into())];
let result: Person = from_record(&header, values).unwrap();
assert_eq!(
result,
Person {
name: "Alice".into(),
age: 30
}
);
}
#[test]
fn test_deserialize_record_with_optional() {
#[derive(Deserialize, Debug, PartialEq)]
struct Entry {
name: String,
#[serde(default)]
description: Option<String>,
}
let header = vec!["Name".to_string(), "Description".to_string()];
let values = vec![Value::Single("Test".into()), Value::Empty];
let result: Entry = from_record(&header, values).unwrap();
assert_eq!(
result,
Entry {
name: "Test".into(),
description: None
}
);
}
#[test]
fn test_deserialize_record_with_list() {
#[derive(Deserialize, Debug, PartialEq)]
struct Route {
network: String,
next_hops: Vec<String>,
}
let header = vec!["Network".to_string(), "Next_Hops".to_string()];
let values = vec![
Value::Single("10.0.0.0/8".into()),
Value::List(vec![
ListItem::String("192.168.1.1".into()),
ListItem::String("192.168.1.2".into()),
]),
];
let result: Route = from_record(&header, values).unwrap();
assert_eq!(
result,
Route {
network: "10.0.0.0/8".into(),
next_hops: vec!["192.168.1.1".into(), "192.168.1.2".into()]
}
);
}
#[test]
fn test_deserialize_enum_from_string() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(rename_all = "lowercase")]
enum Status {
Up,
Down,
Unknown,
}
let value = Value::Single("up".into());
let result: Status = from_value(value).unwrap();
assert_eq!(result, Status::Up);
}
}