valitron 0.5.6

Valitron is an ergonomics, functional and configurable validator
Documentation
use std::collections::BTreeMap;

use serde::Deserialize;

use crate::value::Value;

#[derive(Deserialize, Debug)]
struct A {
    b: B,
    foo: u8,
}
#[derive(Deserialize, Debug)]
struct B {
    c: C,
    foo_str: String,
}
#[derive(Deserialize, Debug)]
struct C(i8, u64, f32, f64);

#[test]
fn test_dep() {
    let c_value = Value::TupleStruct(vec![
        Value::Int8(22),
        Value::Uint64(33),
        Value::Float32(5.0_f32.into()),
        Value::Float64(100.0_f64.into()),
    ]);
    let b_value = Value::Struct({
        let mut map = BTreeMap::new();
        map.insert(Value::StructKey("c".to_string()), c_value);
        map.insert(
            Value::StructKey("foo_str".to_string()),
            Value::String("hello".to_string()),
        );
        map
    });
    let a_value = Value::Struct({
        let mut map = BTreeMap::new();
        map.insert(Value::StructKey("b".to_string()), b_value);
        map.insert(Value::StructKey("foo".to_string()), Value::Uint8(11));
        map
    });

    let res = A::deserialize(a_value).unwrap();

    assert_eq!(
        format!("{res:?}"),
        r#"A { b: B { c: C(22, 33, 5.0, 100.0), foo_str: "hello" }, foo: 11 }"#
    );
}

#[derive(Deserialize, Debug, PartialEq)]
enum EnumA {
    Foo,
    Bar,
}

#[derive(Deserialize, Debug, PartialEq)]
enum EnumB {
    A(u8),
    B { r: u8, g: u8, b: u8 },
}

#[test]
fn test_enum() {
    let value = Value::EnumUnit("Foo");
    let a = EnumA::deserialize(value).unwrap();
    assert_eq!(a, EnumA::Foo);

    let value = Value::Enum("A", vec![Value::Uint8(11)]);
    let b = EnumB::deserialize(value).unwrap();
    assert!(matches!(b, EnumB::A(11)));

    let value = Value::StructVariant("B", {
        let mut map = BTreeMap::new();
        map.insert(Value::StructVariantKey("r".to_string()), Value::Uint8(22));
        map.insert(Value::StructVariantKey("g".to_string()), Value::Uint8(33));
        map.insert(Value::StructVariantKey("b".to_string()), Value::Uint8(44));
        map
    });
    let b = EnumB::deserialize(value).unwrap();
    assert!(matches!(
        b,
        EnumB::B {
            r: 22,
            g: 33,
            b: 44
        }
    ));
}

#[derive(Deserialize, Debug, PartialEq)]
struct Opt {
    val_u8: Option<u8>,
    val_f32: Option<f32>,
    val_string: Option<String>,
}

#[test]
fn test_option() {
    let value = Value::Option(Box::new(Some(Value::Uint32(10))));
    let a = Option::deserialize(value).unwrap();
    assert_eq!(a, Some(10u32));

    let value = Value::Option(Box::new(None));
    let b: Option<u32> = Option::deserialize(value).unwrap();
    assert_eq!(b, None);

    let value = Value::Struct({
        let mut map = BTreeMap::new();
        map.insert(
            Value::StructKey("val_u8".to_string()),
            Value::Option(Box::new(Some(Value::Uint8(22)))),
        );
        map.insert(
            Value::StructKey("val_f32".to_string()),
            Value::Option(Box::new(Some(Value::Float32(33.0_f32.into())))),
        );
        map.insert(
            Value::StructKey("val_string".to_string()),
            Value::Option(Box::new(None)),
        );
        map
    });
    let c = Opt::deserialize(value).unwrap();
    assert_eq!(
        c,
        Opt {
            val_u8: Some(22),
            val_f32: Some(33_f32),
            val_string: None,
        }
    );
}

#[test]
fn unsupport_str() {
    #[derive(Deserialize, Debug)]
    struct A<'a> {
        str: &'a str,
        num: u8,
    }

    let value = Value::Struct({
        let mut map = BTreeMap::new();
        map.insert(Value::StructKey("str".into()), Value::String("foo".into()));
        map.insert(Value::StructKey("num".into()), Value::Uint8(11));
        map
    });

    let err = A::deserialize(value).unwrap_err();
    println!("{err}")
}

#[test]
fn skip_str() {
    #[derive(Deserialize, Debug)]
    struct A<'a> {
        #[serde(skip_deserializing)]
        str: &'a str,
        num: u8,
    }

    let value = Value::Struct({
        let mut map = BTreeMap::new();
        map.insert(Value::StructKey("str".into()), Value::String("foo".into()));
        map.insert(Value::StructKey("num".into()), Value::Uint8(11));
        map
    });

    let a = A::deserialize(value).unwrap();
    assert!(a.str.is_empty());
}