diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..88e5c90 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,100 @@ +// 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 <https://www.gnu.org/licenses/>. + +//! 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::<i32>().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<Self>` to `Box<dyn Any>`. + fn into_any(self: Box<Self>) -> Box<dyn Any>; +} + +impl<T> Sealed for T where T: Any { +} +impl<T> 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<Self>) -> Box<dyn Any> { + 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)); + } +} |