multi-any 0.1.1

`MultiAny` is just like `Any` but can downcast to trait objects.
Documentation
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() });

    // downcast to concrete type
    assert_eq!(foo.downcast_ref::<Foo>().unwrap().name, "Bob");

    // downcast to dyn traits that are implemented
    assert_eq!(
        foo.downcast_ref::<dyn Hello>().unwrap().hello(),
        "Hello, Bob"
    );
    assert_eq!(foo.downcast_ref::<dyn Bye>().unwrap().bye(), "Bye, Bob");

    // Test invalid downcasts
    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() });

    // Test mutable downcast to concrete type
    foo.downcast_mut::<Foo>().unwrap().name = "new".to_string();
    assert_eq!(foo.downcast_ref::<Foo>().unwrap().name, "new");

    // Test mutable downcast to trait
    foo.downcast_mut::<dyn Named>().unwrap().set_name("trait");
    assert_eq!(foo.downcast_ref::<Foo>().unwrap().name, "trait");

    // Test invalid downcasts
    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
        }
    }

    // Test successful downcast to concrete type
    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"),
    }

    // Test successful downcast to trait object
    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"),
    }

    // Test failed 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() {
    // We can omit `#[multi_any]` on 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())
}