rebound 0.4.4

Full runtime reflection for Rust, with lifetime safety
Documentation
use rebound::{rebound, Type, Value, Variant};

#[rebound]
struct Struct {
    field_a: f64,
}

#[rebound]
enum Enum {
    A,
    B(f64),
    C { is_thing: bool },
}

#[test]
fn test_access_struct() {
    let val = Value::from(Struct { field_a: -1.0 });
    if let Type::Struct(ty) = val.ty() {
        let field = &ty.fields()[0];
        let a = field
            .get_ref(&val)
            .expect("Couldn't get value from Struct::field_a");

        assert_eq!(a.ty(), field.ty());
        assert_eq!(*a.borrow::<f64>(), -1.0);
    } else {
        panic!("Struct wasn't reflected correctly")
    }
}

#[test]
fn test_set_struct() {
    let mut val = Value::from(Struct { field_a: -1.0 });
    if let Type::Struct(ty) = val.ty() {
        let field = &ty.fields()[0];
        field
            .set(&mut val, Value::from(10.5))
            .expect("Couldn't set value of Struct::field_a");

        assert_eq!(val.borrow::<Struct>().field_a, 10.5);
    } else {
        panic!("Struct wasn't reflected correctly")
    }
}

#[test]
fn test_access_enum() {
    if let Type::Enum(ty) = Type::from::<Enum>() {
        let val = Value::from(Enum::B(-10.0));
        if let Variant::Tuple(info) = &ty.variants()[1] {
            let field = &info.fields()[0];
            let f = field
                .get_ref(&val)
                .expect("Couldn't get value from Enum::B(f64) field");

            assert_eq!(f.ty(), field.ty());
            assert_eq!(*f.borrow::<f64>(), -10.0);
        } else {
            panic!("Enum wasn't reflected properly")
        }

        let val = Value::from(Enum::C { is_thing: false });
        if let Variant::Struct(info) = &ty.variants()[2] {
            let field = &info.fields()[0];
            let f = field
                .get_ref(&val)
                .expect("Couldn't get value from Enum::C { is_thing } field");

            assert_eq!(f.ty(), field.ty());
            assert_eq!(*f.borrow::<bool>(), false);
        } else {
            panic!("Enum wasn't reflected properly")
        }
    } else {
        panic!("Enum wasn't reflected properly")
    }
}

#[test]
fn test_set_enum() {
    if let Type::Enum(ty) = Type::from::<Enum>() {
        let mut val = Value::from(Enum::B(-10.0));
        if let Variant::Tuple(info) = &ty.variants()[1] {
            let field = &info.fields()[0];
            field
                .set(&mut val, Value::from(123.45))
                .expect("Couldn't set value of Enum::B(f64) field");

            assert!(matches!(*val.borrow::<Enum>(), Enum::B(f) if f == 123.45));
        } else {
            panic!("Enum wasn't reflected properly")
        }

        let mut val = Value::from(Enum::C { is_thing: false });
        if let Variant::Struct(info) = &ty.variants()[2] {
            let field = &info.fields()[0];
            field
                .set(&mut val, Value::from(true))
                .expect("Couldn't set value of Enum::C { is_thing } field");

            assert!(matches!(*val.borrow::<Enum>(), Enum::C { is_thing } if is_thing == true));
        } else {
            panic!("Enum wasn't reflected properly")
        }
    } else {
        panic!("Enum wasn't reflected properly")
    }
}

#[test]
fn test_wrong_ty() {
    let mut val = Value::from(Vec::<i32>::new());
    if let Type::Struct(info) = Type::from::<Struct>() {
        let field = &info.fields()[0];
        field
            .get_ref(&val)
            .expect_err("Successfully got Struct field on a Vec");
        field
            .set(&mut val, Value::from(-1.0))
            .expect_err("Successfully set Struct field on a Vec");
    }
}

#[test]
fn test_wrong_variant() {
    let mut val = Value::from(Enum::A);
    if let Type::Enum(ty) = val.ty() {
        if let Variant::Tuple(info) = &ty.variants()[1] {
            let field = &info.fields()[0];
            field
                .get_ref(&val)
                .expect_err("Successfully got field from unit enum");
            field
                .set(&mut val, Value::from(1.0))
                .expect_err("Successfully set field on unit enum");
        }
    } else {
        panic!("Enum wasn't reflected properly")
    }
}