From 2d1a6b2d432408d74eb57e0bda3f7434617e1070 Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 20 Jul 2022 14:29:45 +0200 Subject: refactor: reorganize folder hierarchy --- src/libs/intertrait/mod.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/libs/intertrait/mod.rs (limited to 'src/libs/intertrait/mod.rs') 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 + * + * + * + * + * Licensed under either of + * + * Apache License, Version 2.0 (LICENSE-APACHE or ) + * MIT license (LICENSE-MIT or ) + + * 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; + +#[distributed_slice] +pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..]; + +static CASTER_MAP: Lazy> = + Lazy::new(|| { + CASTERS + .iter() + .map(|f| { + let (type_id, caster) = f(); + ((type_id, (*caster).type_id()), caster) + }) + .collect() + }); + +pub struct Caster +{ + /// 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) -> Box, + + /// 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) -> Rc, +} + +impl Caster +{ + pub fn new( + cast_box: fn(from: Box) -> Box, + cast_rc: fn(from: Rc) -> Rc, + ) -> Caster + { + Caster:: { cast_box, cast_rc } + } +} + +/// Returns a `Caster` from a concrete type `S` to a trait `T` implemented by it. +fn caster(type_id: TypeId) -> Option<&'static Caster> +{ + CASTER_MAP + .get(&(type_id, TypeId::of::>())) + .and_then(|caster| caster.downcast_ref::>()) +} + +/// `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) -> Box; + + /// Returns an `Rc` of `Any`, which is backed by the type implementing this trait. + fn rc_any(self: Rc) -> Rc; +} + +pub trait CastFromSync: CastFrom + Sync + Send + 'static +{ + fn arc_any(self: Arc) -> Arc; +} + +impl CastFrom for T +{ + fn box_any(self: Box) -> Box + { + self + } + + fn rc_any(self: Rc) -> Rc + { + self + } +} + +impl CastFrom for dyn Any + 'static +{ + fn box_any(self: Box) -> Box + { + self + } + + fn rc_any(self: Rc) -> Rc + { + self + } +} + +impl CastFrom for dyn Any + Sync + Send + 'static +{ + fn box_any(self: Box) -> Box + { + self + } + + fn rc_any(self: Rc) -> Rc + { + self + } +} -- cgit v1.2.3-18-g5258