dyn-dyn 0.2.0

Flexible trait object downcasting using ptr_metadata
Documentation
use dyn_dyn::{dyn_dyn_base, dyn_dyn_cast, dyn_dyn_impl};

#[test]
fn test_generic_base() {
    #[dyn_dyn_base]
    trait Base<T: 'static> {}

    trait TestTraitA {}
    trait TestTraitB {}

    struct TestStruct;

    #[dyn_dyn_impl(TestTraitA)]
    impl Base<u32> for TestStruct {}

    #[dyn_dyn_impl(TestTraitB)]
    impl Base<u64> for TestStruct {}

    impl TestTraitA for TestStruct {}
    impl TestTraitB for TestStruct {}

    assert!(dyn_dyn_cast!(Base<u32> => TestTraitA, &TestStruct as &dyn Base<u32>).is_ok());
    assert!(dyn_dyn_cast!(Base<u32> => TestTraitB, &TestStruct as &dyn Base<u32>).is_err());

    assert!(dyn_dyn_cast!(Base<u64> => TestTraitA, &TestStruct as &dyn Base<u64>).is_err());
    assert!(dyn_dyn_cast!(Base<u64> => TestTraitB, &TestStruct as &dyn Base<u64>).is_ok());
}

#[test]
fn test_generic_trait() {
    #[dyn_dyn_base]
    trait Base {}

    trait GenericTrait<T: 'static> {
        fn test(&self) -> u32;
    }

    struct TestStruct;

    #[dyn_dyn_impl(GenericTrait<u32>, GenericTrait<u64>)]
    impl Base for TestStruct {}
    impl GenericTrait<u32> for TestStruct {
        fn test(&self) -> u32 {
            0
        }
    }
    impl GenericTrait<u64> for TestStruct {
        fn test(&self) -> u32 {
            1
        }
    }

    assert_eq!(
        Ok(0),
        dyn_dyn_cast!(Base => GenericTrait<u32>, &TestStruct as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
    assert_eq!(
        Ok(1),
        dyn_dyn_cast!(Base => GenericTrait<u64>, &TestStruct as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
    assert_eq!(
        Err(()),
        dyn_dyn_cast!(Base => GenericTrait<u16>, &TestStruct as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
}

#[test]
fn test_generic_trait_from_param() {
    #[dyn_dyn_base]
    trait Base {}

    trait GenericTrait<T: 'static> {
        fn test(&self) -> u32;
    }

    struct TestStruct<T: 'static>(T);

    #[dyn_dyn_impl(GenericTrait<T>)]
    impl<T: 'static> Base for TestStruct<T> {}

    impl<T: 'static> GenericTrait<T> for TestStruct<T> {
        fn test(&self) -> u32 {
            1234
        }
    }

    assert_eq!(
        Ok(1234),
        dyn_dyn_cast!(Base => GenericTrait<u32>, &TestStruct(0_u32) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
    assert_eq!(
        Err(()),
        dyn_dyn_cast!(Base => GenericTrait<u64>, &TestStruct(0_u32) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );

    assert_eq!(
        Err(()),
        dyn_dyn_cast!(Base => GenericTrait<u32>, &TestStruct(0_u64) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
    assert_eq!(
        Ok(1234),
        dyn_dyn_cast!(Base => GenericTrait<u64>, &TestStruct(0_u64) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
}

#[test]
fn test_generic_base_from_param() {
    #[dyn_dyn_base]
    trait Base<T: 'static> {}
    trait TestTrait<T: 'static> {}

    struct TestStruct<T: 'static>(T);

    #[dyn_dyn_impl(TestTrait<T>)]
    impl<T: 'static> Base<T> for TestStruct<T> {}
    impl<T: 'static> TestTrait<T> for TestStruct<T> {}

    assert!(
        dyn_dyn_cast!(Base<u32> => TestTrait<u32>, &TestStruct(0_u32) as &dyn Base<u32>).is_ok()
    );
    assert!(
        dyn_dyn_cast!(Base<u32> => TestTrait<u64>, &TestStruct(0_u32) as &dyn Base<u32>).is_err()
    );
    assert!(
        dyn_dyn_cast!(Base<u64> => TestTrait<u32>, &TestStruct(0_u64) as &dyn Base<u64>).is_err()
    );
    assert!(
        dyn_dyn_cast!(Base<u64> => TestTrait<u64>, &TestStruct(0_u64) as &dyn Base<u64>).is_ok()
    );
}

#[test]
fn test_generic_base_blanket_impl() {
    #[dyn_dyn_base]
    trait Base<T: 'static> {}
    trait TestTrait<T: 'static> {}

    struct TestStruct;

    #[dyn_dyn_impl(TestTrait<T>)]
    impl<T: 'static> Base<T> for TestStruct {}
    impl<T: 'static> TestTrait<T> for TestStruct {}

    assert!(dyn_dyn_cast!(Base<u32> => TestTrait<u32>, &TestStruct as &dyn Base<u32>).is_ok());
    assert!(dyn_dyn_cast!(Base<u32> => TestTrait<u64>, &TestStruct as &dyn Base<u32>).is_err());
    assert!(dyn_dyn_cast!(Base<u64> => TestTrait<u32>, &TestStruct as &dyn Base<u64>).is_err());
    assert!(dyn_dyn_cast!(Base<u64> => TestTrait<u64>, &TestStruct as &dyn Base<u64>).is_ok());
}

#[test]
fn test_where_clause_on_base() {
    #[dyn_dyn_base]
    trait Base<T>
    where
        T: 'static,
    {
    }
    trait TestTrait {}

    struct TestStruct;

    #[dyn_dyn_impl(TestTrait)]
    impl Base<u32> for TestStruct {}
    impl TestTrait for TestStruct {}

    assert!(dyn_dyn_cast!(Base<u32> => TestTrait, &TestStruct as &dyn Base<u32>).is_ok());
}

#[test]
fn test_where_clause_on_derived() {
    #[dyn_dyn_base]
    trait Base {}

    trait GenericTrait<T: 'static> {
        fn test(&self) -> u32;
    }

    struct TestStruct<T>(T)
    where
        T: 'static;

    #[dyn_dyn_impl(GenericTrait<T>)]
    impl<T> Base for TestStruct<T> where T: 'static {}

    impl<T: 'static> GenericTrait<T> for TestStruct<T> {
        fn test(&self) -> u32 {
            1234
        }
    }

    assert_eq!(
        Ok(1234),
        dyn_dyn_cast!(Base => GenericTrait<u32>, &TestStruct(0_u32) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
    assert_eq!(
        Err(()),
        dyn_dyn_cast!(Base => GenericTrait<u64>, &TestStruct(0_u32) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );

    assert_eq!(
        Err(()),
        dyn_dyn_cast!(Base => GenericTrait<u32>, &TestStruct(0_u64) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
    assert_eq!(
        Ok(1234),
        dyn_dyn_cast!(Base => GenericTrait<u64>, &TestStruct(0_u64) as &dyn Base)
            .map(|b| b.test())
            .map_err(|_| ())
    );
}