use alloc::collections::BTreeMap;
use crate::key_path;
use crate::key_path::*;
use crate::type_info::ScalarType;
use crate::type_info::TypeAtPath;
use crate::DescribeType;
use crate::Reflect;
#[test]
#[allow(clippy::bool_assert_comparison)]
fn works() {
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
struct A {
a: i32,
b: B,
c: C,
d: BTreeMap<String, u32>,
e: Vec<f32>,
}
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
struct B {
c: bool,
}
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
enum C {
C { d: String },
}
let mut a = A {
a: 42,
b: B { c: true },
c: C::C {
d: "foo".to_owned(),
},
d: BTreeMap::from([("fourtytwo".to_owned(), 42)]),
e: Vec::from([1.0, 2.0, 3.0]),
};
assert!(a.get_at::<A>(&key_path!()).is_some());
assert_eq!(a.get_at::<i32>(&key_path!(.a)).unwrap(), &42);
assert_eq!(a.get_at::<bool>(&key_path!(.b.c)).unwrap(), &true);
assert_eq!(a.get_at::<String>(&key_path!(.c::C.d)).unwrap(), &"foo");
assert!(a.at(&key_path!(.c::DoesntExist)).is_none());
assert_eq!(a.get_at::<u32>(&key_path!(.d["fourtytwo"])).unwrap(), &42);
assert_eq!(a.get_at::<f32>(&key_path!(.e[0])).unwrap(), &1.0);
assert_eq!(a.get_at::<f32>(&key_path!(.e[1])).unwrap(), &2.0);
assert_eq!(a.get_at::<f32>(&key_path!(.e[2])).unwrap(), &3.0);
assert!(a.at(&key_path!(.e[3])).is_none());
assert_eq!(a.b.c, true);
*a.get_at_mut(&key_path!(.b.c)).unwrap() = false;
assert_eq!(a.b.c, false);
}
#[test]
fn display() {
assert_eq!(
key_path!(.a.0.b.c[1]["foo"]::D.e[3]).to_string(),
".a.0.b.c[1][\"foo\"]::D.e[3]"
);
}
#[test]
fn query_type_info_struct() {
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
struct User {
employer: Company,
}
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
struct Company {
countries: Vec<Country>,
}
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
struct Country {
name: String,
}
let user = User {
employer: Company {
countries: Vec::from([Country {
name: "Denmark".to_owned(),
}]),
},
};
let key_path = key_path!(.employer.countries[0].name);
assert_eq!(user.get_at::<String>(&key_path).unwrap(), "Denmark");
let type_info = <User as DescribeType>::type_descriptor();
assert!(matches!(
dbg!(type_info.type_at(&key_path).unwrap()),
TypeAtPath::Scalar(ScalarType::String)
));
}
#[test]
fn query_type_info_enum() {
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
enum Foo {
A { a: String },
B(i32),
C,
}
assert!(matches!(
dbg!(<Foo as DescribeType>::type_descriptor()
.type_at(&key_path!(::A.a))
.unwrap()),
TypeAtPath::Scalar(ScalarType::String)
));
assert!(matches!(
dbg!(<Foo as DescribeType>::type_descriptor()
.type_at(&key_path!(::B.0))
.unwrap()),
TypeAtPath::Scalar(ScalarType::i32)
));
assert!(<Foo as DescribeType>::type_descriptor()
.type_at(&key_path!(::B[0]))
.is_none());
let info = <Foo as DescribeType>::type_descriptor();
let variant = info.type_at(&key_path!(::C)).unwrap().as_variant().unwrap();
assert_eq!(variant.name(), "C");
}
#[test]
fn select_tuple_field() {
#[derive(Reflect, Clone, Debug)]
#[reflect(crate_name(crate))]
struct Foo(i32, bool);
let foo = Foo(42, true);
assert_eq!(foo.get_at::<i32>(&key_path!(.0)).unwrap(), &42);
assert_eq!(foo.get_at::<bool>(&key_path!(.1)).unwrap(), &true);
}
#[test]
fn breadcrumbs() {
let path = key_path!(.a.b.c.d);
let actual = path
.breadcrumbs()
.map(|key| key.iter().cloned().collect::<KeyPath>());
let expected = Vec::from([
key_path!(.a),
key_path!(.a.b),
key_path!(.a.b.c),
key_path!(.a.b.c.d),
]);
for (a, b) in actual.into_iter().zip(expected) {
assert_eq!(a, b);
}
}