aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--macros/src/libs/intertrait_macros/gen_caster.rs33
-rw-r--r--src/libs/intertrait/cast_box.rs10
-rw-r--r--src/libs/intertrait/cast_rc.rs10
-rw-r--r--src/libs/intertrait/hasher.rs48
-rw-r--r--src/libs/intertrait/mod.rs71
6 files changed, 63 insertions, 110 deletions
diff --git a/Cargo.toml b/Cargo.toml
index f2160bc..10f3094 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,7 @@ syrette_macros = { path = "./macros", version = "0.1.1" }
linkme = "0.3.0"
once_cell = "1.4"
error-stack = "0.1.1"
+ahash = "0.7.6"
[dev_dependencies]
mockall = "0.11.1"
diff --git a/macros/src/libs/intertrait_macros/gen_caster.rs b/macros/src/libs/intertrait_macros/gen_caster.rs
index 9126200..d77262a 100644
--- a/macros/src/libs/intertrait_macros/gen_caster.rs
+++ b/macros/src/libs/intertrait_macros/gen_caster.rs
@@ -11,8 +11,9 @@
* at your option.
*/
-use std::str::from_utf8_unchecked;
+use std::str::from_utf8;
+use proc_macro2::Ident;
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::quote;
@@ -20,14 +21,16 @@ use quote::ToTokens;
use uuid::adapter::Simple;
use uuid::Uuid;
-pub fn generate_caster(ty: &impl ToTokens, trait_: &impl ToTokens) -> TokenStream
-{
- let mut fn_buf = [0u8; FN_BUF_LEN];
+const CASTER_FN_NAME_PREFIX: &[u8] = b"__";
+
+const FN_BUF_LEN: usize = CASTER_FN_NAME_PREFIX.len() + Simple::LENGTH;
- let fn_ident = format_ident!("{}", new_fn_name(&mut fn_buf));
+pub fn generate_caster(ty: &impl ToTokens, dst_trait: &impl ToTokens) -> TokenStream
+{
+ let fn_ident = create_caster_fn_ident();
let new_caster = quote! {
- syrette::libs::intertrait::Caster::<dyn #trait_>::new(
+ syrette::libs::intertrait::Caster::<dyn #dst_trait>::new(
|from| from.downcast::<#ty>().unwrap(),
|from| from.downcast::<#ty>().unwrap(),
)
@@ -42,14 +45,18 @@ pub fn generate_caster(ty: &impl ToTokens, trait_: &impl ToTokens) -> TokenStrea
}
}
-const FN_PREFIX: &[u8] = b"__";
-const FN_BUF_LEN: usize = FN_PREFIX.len() + Simple::LENGTH;
-
-fn new_fn_name(buf: &mut [u8]) -> &str
+fn create_caster_fn_ident() -> Ident
{
- buf[..FN_PREFIX.len()].copy_from_slice(FN_PREFIX);
+ let buf = &mut [0u8; FN_BUF_LEN];
+
+ buf[..CASTER_FN_NAME_PREFIX.len()].copy_from_slice(CASTER_FN_NAME_PREFIX);
+
Uuid::new_v4()
.to_simple()
- .encode_lower(&mut buf[FN_PREFIX.len()..]);
- unsafe { from_utf8_unchecked(&buf[..FN_BUF_LEN]) }
+ .encode_lower(&mut buf[CASTER_FN_NAME_PREFIX.len()..]);
+
+ let fn_name =
+ from_utf8(&buf[..FN_BUF_LEN]).expect("Created caster function name is not UTF-8");
+
+ format_ident!("{}", fn_name)
}
diff --git a/src/libs/intertrait/cast_box.rs b/src/libs/intertrait/cast_box.rs
index 793efd0..b2ec77e 100644
--- a/src/libs/intertrait/cast_box.rs
+++ b/src/libs/intertrait/cast_box.rs
@@ -15,16 +15,16 @@ use crate::libs::intertrait::{caster, CastFrom};
pub trait CastBox
{
- /// Casts a box to this trait into that of type `T`. If fails, returns the receiver.
- fn cast<T: ?Sized + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>>;
+ /// Casts a box to this trait into that of `Trait`. If fails, returns the receiver.
+ fn cast<Trait: ?Sized + 'static>(self: Box<Self>) -> Result<Box<Trait>, Box<Self>>;
}
/// A blanket implementation of `CastBox` for traits extending `CastFrom`.
-impl<S: ?Sized + CastFrom> CastBox for S
+impl<CastableFrom: ?Sized + CastFrom> CastBox for CastableFrom
{
- fn cast<T: ?Sized + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>>
+ fn cast<Trait: ?Sized + 'static>(self: Box<Self>) -> Result<Box<Trait>, Box<Self>>
{
- match caster::<T>((*self).type_id()) {
+ match caster::<Trait>((*self).type_id()) {
Some(caster) => Ok((caster.cast_box)(self.box_any())),
None => Err(self),
}
diff --git a/src/libs/intertrait/cast_rc.rs b/src/libs/intertrait/cast_rc.rs
index 79d8d60..5901b5e 100644
--- a/src/libs/intertrait/cast_rc.rs
+++ b/src/libs/intertrait/cast_rc.rs
@@ -17,16 +17,16 @@ use crate::libs::intertrait::{caster, CastFrom};
pub trait CastRc
{
- /// Casts an `Rc` for this trait into that for type `T`.
- fn cast<T: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>>;
+ /// Casts an `Rc` for this trait into that for `Trait`.
+ fn cast<Trait: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<Trait>, Rc<Self>>;
}
/// A blanket implementation of `CastRc` for traits extending `CastFrom`.
-impl<S: ?Sized + CastFrom> CastRc for S
+impl<CastableFrom: ?Sized + CastFrom> CastRc for CastableFrom
{
- fn cast<T: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>>
+ fn cast<Trait: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<Trait>, Rc<Self>>
{
- match caster::<T>((*self).type_id()) {
+ match caster::<Trait>((*self).type_id()) {
Some(caster) => Ok((caster.cast_rc)(self.rc_any())),
None => Err(self),
}
diff --git a/src/libs/intertrait/hasher.rs b/src/libs/intertrait/hasher.rs
deleted file mode 100644
index e7f110d..0000000
--- a/src/libs/intertrait/hasher.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-#![allow(clippy::module_name_repetitions)]
-
-/**
- * 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::convert::TryInto;
-use std::hash::{BuildHasherDefault, Hasher};
-use std::mem::size_of;
-
-/// A simple `Hasher` implementation tuned for performance.
-#[derive(Default)]
-pub struct FastHasher(u64);
-
-/// A `BuildHasher` for `FastHasher`.
-pub type BuildFastHasher = BuildHasherDefault<FastHasher>;
-
-impl Hasher for FastHasher
-{
- fn finish(&self) -> u64
- {
- self.0
- }
-
- fn write(&mut self, bytes: &[u8])
- {
- let mut bytes = bytes;
- while bytes.len() > size_of::<u64>() {
- let (u64_bytes, remaining) = bytes.split_at(size_of::<u64>());
-
- self.0 ^= u64::from_ne_bytes(u64_bytes.try_into().unwrap());
-
- bytes = remaining;
- }
- self.0 ^= bytes
- .iter()
- .fold(0u64, |result, b| (result << 8) | u64::from(*b));
- }
-}
diff --git a/src/libs/intertrait/mod.rs b/src/libs/intertrait/mod.rs
index 1daca64..2cdc67d 100644
--- a/src/libs/intertrait/mod.rs
+++ b/src/libs/intertrait/mod.rs
@@ -12,64 +12,62 @@
* at your option.
*/
use std::any::{Any, TypeId};
-use std::collections::HashMap;
use std::rc::Rc;
-use std::sync::Arc;
+use ahash::AHashMap;
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>;
+type CasterFn = fn() -> (TypeId, BoxedCaster);
+
#[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>
+pub static CASTERS: [CasterFn] = [..];
+
+static CASTER_MAP: Lazy<AHashMap<(TypeId, TypeId), BoxedCaster>> = Lazy::new(|| {
+ CASTERS
+ .iter()
+ .map(|caster_fn| {
+ let (type_id, caster) = caster_fn();
+
+ ((type_id, (*caster).type_id()), caster)
+ })
+ .collect()
+});
+
+pub struct Caster<Trait: ?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>,
+ /// for `Trait`.
+ pub cast_box: fn(from: Box<dyn Any>) -> Box<Trait>,
/// 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>,
+ /// for `Trait`.
+ pub cast_rc: fn(from: Rc<dyn Any>) -> Rc<Trait>,
}
-impl<T: ?Sized + 'static> Caster<T>
+impl<Trait: ?Sized + 'static> Caster<Trait>
{
pub fn new(
- cast_box: fn(from: Box<dyn Any>) -> Box<T>,
- cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
- ) -> Caster<T>
+ cast_box: fn(from: Box<dyn Any>) -> Box<Trait>,
+ cast_rc: fn(from: Rc<dyn Any>) -> Rc<Trait>,
+ ) -> Caster<Trait>
{
- Caster::<T> { cast_box, cast_rc }
+ Caster::<Trait> { 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>>
+/// Returns a `Caster<Implementation, Trait>` from a concrete type `Implementation`
+/// from inside `CASTER_MAP` to a `Trait` implemented by it.
+fn caster<Trait: ?Sized + 'static>(type_id: TypeId) -> Option<&'static Caster<Trait>>
{
CASTER_MAP
- .get(&(type_id, TypeId::of::<Caster<T>>()))
- .and_then(|caster| caster.downcast_ref::<Caster<T>>())
+ .get(&(type_id, TypeId::of::<Caster<Trait>>()))
+ .and_then(|caster| caster.downcast_ref::<Caster<Trait>>())
}
/// `CastFrom` must be extended by a trait that wants to allow for casting into another trait.
@@ -92,12 +90,7 @@ pub trait CastFrom: Any + 'static
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
+impl<Trait: Sized + Any + 'static> CastFrom for Trait
{
fn box_any(self: Box<Self>) -> Box<dyn Any>
{