use crate::Value;
use std::collections::{BTreeMap, HashMap};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("Invalid type")]
InvalidType,
}
pub trait Deserialize: Sized {
fn deserialize(value: &Value) -> Result<Self, Error>;
}
impl Deserialize for Value {
fn deserialize(value: &Value) -> Result<Self, Error> {
Ok(*value)
}
}
impl Deserialize for () {
fn deserialize(value: &Value) -> Result<Self, Error> {
if value.is_null() {
Ok(())
} else {
Err(Error::InvalidType)
}
}
}
impl Deserialize for bool {
fn deserialize(value: &Value) -> Result<Self, Error> {
value.as_bool().ok_or(Error::InvalidType)
}
}
macro_rules! impl_deserialize_for_int {
($ty:ty) => {
impl Deserialize for $ty {
fn deserialize(value: &Value) -> Result<Self, Error> {
value
.as_number()
.and_then(|n| {
if n.trunc() == n && n >= <$ty>::MIN as f64 && n <= <$ty>::MAX as f64 {
Some(n as $ty)
} else {
None
}
})
.ok_or(Error::InvalidType)
}
}
};
}
impl_deserialize_for_int!(i8);
impl_deserialize_for_int!(i16);
impl_deserialize_for_int!(i32);
impl_deserialize_for_int!(i64);
impl_deserialize_for_int!(u8);
impl_deserialize_for_int!(u16);
impl_deserialize_for_int!(u32);
impl_deserialize_for_int!(u64);
impl_deserialize_for_int!(usize);
impl_deserialize_for_int!(isize);
impl Deserialize for f64 {
fn deserialize(value: &Value) -> Result<Self, Error> {
value.as_number().ok_or(Error::InvalidType)
}
}
impl Deserialize for String {
fn deserialize(value: &Value) -> Result<Self, Error> {
value.as_string().ok_or(Error::InvalidType)
}
}
impl Deserialize for char {
fn deserialize(value: &Value) -> Result<Self, Error> {
let s = value.as_string().ok_or(Error::InvalidType)?;
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(Some(c), None) => Ok(c),
_ => Err(Error::InvalidType),
}
}
}
impl<T: Deserialize> Deserialize for Option<T> {
fn deserialize(value: &Value) -> Result<Self, Error> {
if value.is_null() {
Ok(None)
} else {
Ok(Some(T::deserialize(value)?))
}
}
}
impl<T: Deserialize> Deserialize for Vec<T> {
fn deserialize(value: &Value) -> Result<Self, Error> {
if let Some(len) = value.array_len() {
let mut vec = Vec::with_capacity(len);
for i in 0..len {
vec.push(T::deserialize(&value.get_at_index(i))?);
}
Ok(vec)
} else {
Err(Error::InvalidType)
}
}
}
impl<T: Deserialize> Deserialize for HashMap<String, T> {
fn deserialize(value: &Value) -> Result<Self, Error> {
let Some(obj_len) = value.obj_len() else {
return Err(Error::InvalidType);
};
let mut map = HashMap::new();
for i in 0..obj_len {
let key = value.get_obj_key_at_index(i).ok_or(Error::InvalidType)?;
let value = value.get_at_index(i);
map.insert(key, T::deserialize(&value)?);
}
Ok(map)
}
}
impl<T: Deserialize> Deserialize for BTreeMap<String, T> {
fn deserialize(value: &Value) -> Result<Self, Error> {
let Some(obj_len) = value.obj_len() else {
return Err(Error::InvalidType);
};
let mut map = BTreeMap::new();
for i in 0..obj_len {
let key = value.get_obj_key_at_index(i).ok_or(Error::InvalidType)?;
let value = value.get_at_index(i);
map.insert(key, T::deserialize(&value)?);
}
Ok(map)
}
}
macro_rules! impl_deserialize_tuple {
($n:literal) => {
seq_macro::seq!(N in 0..$n {
impl<#(T~N: Deserialize,)*> Deserialize for (#(T~N,)*) {
fn deserialize(value: &Value) -> Result<Self, Error> {
let Some(len) = value.array_len() else {
return Err(Error::InvalidType);
};
if len != $n {
return Err(Error::InvalidType);
}
Ok((#(T~N::deserialize(&value.get_at_index(N))?,)*))
}
}
});
}
}
seq_macro::seq!(N in 2..=10 {
impl_deserialize_tuple!(N);
});
macro_rules! impl_deserialize_array {
($n:literal) => {
impl<T: Deserialize> Deserialize for [T; $n] {
fn deserialize(value: &Value) -> Result<Self, Error> {
let Some(len) = value.array_len() else {
return Err(Error::InvalidType);
};
if len != $n {
return Err(Error::InvalidType);
}
seq_macro::seq!(N in 0..$n {
Ok([#(T::deserialize(&value.get_at_index(N))?,)*])
})
}
}
};
}
seq_macro::seq!(N in 0..=32 {
impl_deserialize_array!(N);
});
#[cfg(test)]
mod tests {
use super::*;
use crate::Context;
fn deserialize_json_value<T: Deserialize>(value: serde_json::Value) -> Result<T, Error> {
let context = Context::new_with_input(value);
let value = context.input_get().unwrap();
T::deserialize(&value)
}
#[test]
fn test_deserialize_bool() {
[true, false].iter().for_each(|&b| {
let value = serde_json::json!(b);
let result: bool = deserialize_json_value(value).unwrap();
assert_eq!(result, b);
});
}
macro_rules! test_deserialize_int {
($ty:ty) => {
paste::paste! {
#[test]
fn [<test_deserialize_ $ty>]() {
[$ty::MIN, 0 as $ty, $ty::MAX].iter().for_each(|&n| {
let value = serde_json::json!(n);
let result: $ty = deserialize_json_value(value).unwrap();
assert_eq!(result, n);
});
}
}
};
}
test_deserialize_int!(i8);
test_deserialize_int!(i16);
test_deserialize_int!(i32);
test_deserialize_int!(i64);
test_deserialize_int!(u8);
test_deserialize_int!(u16);
test_deserialize_int!(u32);
test_deserialize_int!(u64);
test_deserialize_int!(usize);
test_deserialize_int!(isize);
#[test]
fn test_deserialize_f64() {
let value = serde_json::json!(1.0);
let result: f64 = deserialize_json_value(value).unwrap();
assert_eq!(result, 1.0);
}
#[test]
fn test_deserialize_string() {
let value = serde_json::json!("test");
let result: String = deserialize_json_value(value).unwrap();
assert_eq!(result, "test");
}
#[test]
fn test_deserialize_char() {
let value = serde_json::json!("a");
let result: char = deserialize_json_value(value).unwrap();
assert_eq!(result, 'a');
let value = serde_json::json!("ab");
assert!(deserialize_json_value::<char>(value).is_err());
let value = serde_json::json!("");
assert!(deserialize_json_value::<char>(value).is_err());
}
#[test]
fn test_deserialize_option() {
[None, Some(1), Some(2)].iter().for_each(|&opt| {
let value = serde_json::json!(opt);
let result: Option<i32> = deserialize_json_value(value).unwrap();
assert_eq!(result, opt);
});
}
#[test]
fn test_deserialize_vec() {
let value = serde_json::json!([1, 2, 3]);
let result: Vec<i32> = deserialize_json_value(value).unwrap();
assert_eq!(result, vec![1, 2, 3]);
}
#[test]
fn test_deserialize_hash_map() {
let value = serde_json::json!({
"key1": "value1",
"key2": "value2",
});
let result: HashMap<String, String> = deserialize_json_value(value).unwrap();
let expected = HashMap::from([
("key1".to_string(), "value1".to_string()),
("key2".to_string(), "value2".to_string()),
]);
assert_eq!(result, expected);
}
#[test]
fn test_deserialize_btree_map() {
let value = serde_json::json!({
"key1": "value1",
"key2": "value2",
});
let result: BTreeMap<String, String> = deserialize_json_value(value).unwrap();
let expected = BTreeMap::from([
("key1".to_string(), "value1".to_string()),
("key2".to_string(), "value2".to_string()),
]);
assert_eq!(result, expected);
}
#[test]
fn test_deserialize_unit() {
let value = serde_json::json!(null);
deserialize_json_value::<()>(value).unwrap();
}
#[test]
fn test_deserialize_tuple() {
let value = serde_json::json!([1, 2, 3]);
let result: (i32, i32, i32) = deserialize_json_value(value).unwrap();
assert_eq!(result, (1, 2, 3));
}
#[test]
fn test_deserialize_fixed_array() {
let value = serde_json::json!([1, 2, 3]);
let result: [i32; 3] = deserialize_json_value(value).unwrap();
assert_eq!(result, [1, 2, 3]);
let value = serde_json::json!([1, 2]);
assert!(deserialize_json_value::<[i32; 3]>(value).is_err());
let value = serde_json::json!([1, 2, 3, 4]);
assert!(deserialize_json_value::<[i32; 3]>(value).is_err());
let value = serde_json::json!([]);
let result: [i32; 0] = deserialize_json_value(value).unwrap();
assert_eq!(result, [] as [i32; 0]);
let value = serde_json::json!([42]);
let result: [i32; 1] = deserialize_json_value(value).unwrap();
assert_eq!(result, [42]);
let value = serde_json::json!([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let result: [i32; 10] = deserialize_json_value(value).unwrap();
assert_eq!(result, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
}