summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs100
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));
+    }
+}