aboutsummaryrefslogtreecommitdiff
path: root/src/libs/intertrait/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/intertrait/mod.rs')
-rw-r--r--src/libs/intertrait/mod.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/libs/intertrait/mod.rs b/src/libs/intertrait/mod.rs
new file mode 100644
index 0000000..1daca64
--- /dev/null
+++ b/src/libs/intertrait/mod.rs
@@ -0,0 +1,137 @@
+/**
+ * Originally from Intertrait by CodeChain
+ *
+ * <https://github.com/CodeChain-io/intertrait>
+ * <https://crates.io/crates/intertrait/0.2.2>
+ *
+ * Licensed under either of
+ *
+ * Apache License, Version 2.0 (LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)
+ * MIT license (LICENSE-MIT or <http://opensource.org/licenses/MIT>)
+
+ * at your option.
+*/
+use std::any::{Any, TypeId};
+use std::collections::HashMap;
+use std::rc::Rc;
+use std::sync::Arc;
+
+use linkme::distributed_slice;
+use once_cell::sync::Lazy;
+
+mod hasher;
+
+use hasher::BuildFastHasher;
+
+pub mod cast_box;
+pub mod cast_rc;
+
+pub type BoxedCaster = Box<dyn Any + Send + Sync>;
+
+#[distributed_slice]
+pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..];
+
+static CASTER_MAP: Lazy<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher>> =
+ Lazy::new(|| {
+ CASTERS
+ .iter()
+ .map(|f| {
+ let (type_id, caster) = f();
+ ((type_id, (*caster).type_id()), caster)
+ })
+ .collect()
+ });
+
+pub struct Caster<T: ?Sized + 'static>
+{
+ /// Casts a `Box` holding a trait object for `Any` to another `Box` holding a trait object
+ /// for trait `T`.
+ pub cast_box: fn(from: Box<dyn Any>) -> Box<T>,
+
+ /// Casts an `Rc` holding a trait object for `Any` to another `Rc` holding a trait object
+ /// for trait `T`.
+ pub cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
+}
+
+impl<T: ?Sized + 'static> Caster<T>
+{
+ pub fn new(
+ cast_box: fn(from: Box<dyn Any>) -> Box<T>,
+ cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
+ ) -> Caster<T>
+ {
+ Caster::<T> { cast_box, cast_rc }
+ }
+}
+
+/// Returns a `Caster<S, T>` from a concrete type `S` to a trait `T` implemented by it.
+fn caster<T: ?Sized + 'static>(type_id: TypeId) -> Option<&'static Caster<T>>
+{
+ CASTER_MAP
+ .get(&(type_id, TypeId::of::<Caster<T>>()))
+ .and_then(|caster| caster.downcast_ref::<Caster<T>>())
+}
+
+/// `CastFrom` must be extended by a trait that wants to allow for casting into another trait.
+///
+/// It is used for obtaining a trait object for [`Any`] from a trait object for its sub-trait,
+/// and blanket implemented for all `Sized + Any + 'static` types.
+///
+/// # Examples
+/// ```ignore
+/// trait Source: CastFrom {
+/// ...
+/// }
+/// ```
+pub trait CastFrom: Any + 'static
+{
+ /// Returns a `Box` of `Any`, which is backed by the type implementing this trait.
+ fn box_any(self: Box<Self>) -> Box<dyn Any>;
+
+ /// Returns an `Rc` of `Any`, which is backed by the type implementing this trait.
+ fn rc_any(self: Rc<Self>) -> Rc<dyn Any>;
+}
+
+pub trait CastFromSync: CastFrom + Sync + Send + 'static
+{
+ fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>;
+}
+
+impl<T: Sized + Any + 'static> CastFrom for T
+{
+ fn box_any(self: Box<Self>) -> Box<dyn Any>
+ {
+ self
+ }
+
+ fn rc_any(self: Rc<Self>) -> Rc<dyn Any>
+ {
+ self
+ }
+}
+
+impl CastFrom for dyn Any + 'static
+{
+ fn box_any(self: Box<Self>) -> Box<dyn Any>
+ {
+ self
+ }
+
+ fn rc_any(self: Rc<Self>) -> Rc<dyn Any>
+ {
+ self
+ }
+}
+
+impl CastFrom for dyn Any + Sync + Send + 'static
+{
+ fn box_any(self: Box<Self>) -> Box<dyn Any>
+ {
+ self
+ }
+
+ fn rc_any(self: Rc<Self>) -> Rc<dyn Any>
+ {
+ self
+ }
+}