From 55ce1087e87b48384abf90bbedb5da03b42f6996 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Sat, 5 Feb 2022 12:55:27 -0300 Subject: [Project] Anycast Rust library for casting to Any. --- src/lib.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/lib.rs (limited to 'src') 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 . + +//! 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)); + } +} -- cgit 1.4.1