use multi_any::{Meta, MultiAny, multi_any};
use std::any::TypeId;
#[test]
fn test_basic() {
#[multi_any]
trait Hello {
fn hello(&self) -> String;
}
#[multi_any]
trait Bye {
fn bye(&self) -> String;
}
#[multi_any]
trait Other {}
struct Foo {
name: String,
}
impl Hello for Foo {
fn hello(&self) -> String {
format!("Hello, {}", self.name)
}
}
impl Bye for Foo {
fn bye(&self) -> String {
format!("Bye, {}", self.name)
}
}
impl MultiAny for Foo {
fn get_metadata(&self, type_id: TypeId) -> Option<Meta> {
Meta::try_from(self, type_id, |v| v)
.or_else(|| Meta::try_from(self, type_id, |v| v as &dyn Hello))
.or_else(|| Meta::try_from(self, type_id, |v| v as &dyn Bye))
}
}
let foo: Box<dyn MultiAny> = Box::new(Foo { name: "Bob".into() });
assert_eq!(foo.downcast_ref::<Foo>().unwrap().name, "Bob");
assert_eq!(
foo.downcast_ref::<dyn Hello>().unwrap().hello(),
"Hello, Bob"
);
assert_eq!(foo.downcast_ref::<dyn Bye>().unwrap().bye(), "Bye, Bob");
assert!(foo.downcast_ref::<dyn Other>().is_none());
assert!(foo.downcast_ref::<()>().is_none());
}
#[test]
fn test_derive() {
#[multi_any]
trait Trait1 {}
#[multi_any]
trait Trait2 {}
#[multi_any]
trait Trait3 {}
#[derive(MultiAny)]
#[multi_any(Trait1, Trait2)]
struct Foo;
impl Trait1 for Foo {}
impl Trait2 for Foo {}
let foo: Box<dyn MultiAny> = Box::new(Foo);
assert!(foo.downcast_ref::<Foo>().is_some());
assert!(foo.downcast_ref::<dyn Trait1>().is_some());
assert!(foo.downcast_ref::<dyn Trait2>().is_some());
assert!(foo.downcast_ref::<dyn Trait3>().is_none());
}
#[test]
fn test_downcast_mut() {
#[multi_any]
trait Named {
fn set_name(&mut self, name: &str);
}
#[multi_any]
trait Other {}
#[derive(MultiAny)]
#[multi_any(Named)]
struct Foo {
name: String,
}
impl Named for Foo {
fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
}
let mut foo: Box<dyn MultiAny> = Box::new(Foo { name: "old".into() });
foo.downcast_mut::<Foo>().unwrap().name = "new".to_string();
assert_eq!(foo.downcast_ref::<Foo>().unwrap().name, "new");
foo.downcast_mut::<dyn Named>().unwrap().set_name("trait");
assert_eq!(foo.downcast_ref::<Foo>().unwrap().name, "trait");
assert!(foo.downcast_mut::<dyn Other>().is_none());
assert!(foo.downcast_mut::<()>().is_none());
}
#[test]
fn test_downcast() {
#[multi_any]
trait Displayable {
fn get_value(&self) -> i32;
}
#[derive(MultiAny)]
#[multi_any(Displayable)]
struct Foo {
value: i32,
}
impl Displayable for Foo {
fn get_value(&self) -> i32 {
self.value
}
}
let foo: Box<dyn MultiAny> = Box::new(Foo { value: 42 });
match foo.downcast::<Foo>() {
Ok(downcasted) => assert_eq!(downcasted.value, 42),
Err(_) => panic!("Expected successful downcast"),
}
let foo: Box<dyn MultiAny> = Box::new(Foo { value: 99 });
match foo.downcast::<dyn Displayable>() {
Ok(downcasted) => assert_eq!(downcasted.get_value(), 99),
Err(_) => panic!("Expected successful trait downcast"),
}
let foo: Box<dyn MultiAny> = Box::new(Foo { value: 123 });
match foo.downcast::<String>() {
Ok(_) => panic!("Expected failed downcast"),
Err(original) => assert_eq!(original.downcast_ref::<Foo>().unwrap().value, 123),
}
}
#[cfg(feature = "nightly")]
#[test]
fn test_nightly() {
trait Trait {}
#[derive(MultiAny)]
#[multi_any(Trait)]
struct Foo;
impl Trait for Foo {}
let foo: Box<dyn MultiAny> = Box::new(Foo);
assert!(foo.downcast_ref::<dyn Trait>().is_some())
}