// Anycast - Any upcasting // Copyright (C) 2022 Soni L. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //! Anycast is a library for casting to `::core::any::Any`. #![cfg_attr(not(feature="std"), no_std)] use ::core::any::Any; #[cfg(feature="alloc")] extern crate alloc; #[cfg(feature="alloc")] use ::alloc::boxed::Box; mod sealed { pub trait Sealed { } } use sealed::Sealed; /// Trait for casting to [`::core::any::Any`]. /// /// This is useful to add to your own traits, when you want to expose `Any` /// upcasting (and downcasting!) ability to your users, on your object-safe /// traits. /// /// # Examples /// /// ```rust /// use ::anycast::Anycast; /// /// trait Foo: Anycast { /// fn foo(&mut self); /// } /// /// impl Foo for i32 { /// fn foo(&mut self) { /// *self += 1; /// } /// } /// /// let mut x = 10; /// let x: &mut dyn Foo = &mut x; /// x.foo(); /// // it's recommended to use Anycast::* due to weird implicit (de)ref. /// assert_eq!(Anycast::any_ref(x).downcast_ref::().unwrap(), &11); /// ``` pub trait Anycast: Any + Sealed { /// Casts `&Self` to `&dyn Any`. fn any_ref(&self) -> &dyn Any; /// Casts `&mut Self` to `&mut dyn Any`. fn any_mut(&mut self) -> &mut dyn Any; #[cfg(feature="alloc")] /// Casts `Box` to `Box`. fn into_any(self: Box) -> Box; } impl Sealed for T where T: Any { } impl Anycast for T where T: Any { fn any_ref(&self) -> &dyn Any { self } fn any_mut(&mut self) -> &mut dyn Any { self } #[cfg(feature="alloc")] fn into_any(self: Box) -> Box { self } } #[cfg(test)] mod test { use super::Anycast; #[test] fn test_anycast() { let string = "foo"; let anycast: &dyn Anycast = &string; let any = anycast.any_ref(); let string_ref = any.downcast_ref::<&'static str>().unwrap(); assert!(::core::ptr::eq(string, *string_ref)); } }