aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-12-25 22:53:13 +0100
committerHampusM <hampus@hampusmat.com>2023-12-28 12:00:11 +0100
commit607d8d50b76665b67ca6f3124aa81773bec110b7 (patch)
tree142a7c17c4e254eabd5a5396975921bca1869bec /src
parentc501a5cc770f632eba1529de09bd3ae2d7958de6 (diff)
WIP Linkme dependency removalwithout-linkme
Diffstat (limited to 'src')
-rw-r--r--src/di_container/asynchronous/mod.rs50
-rw-r--r--src/di_container/blocking/mod.rs32
-rw-r--r--src/interfaces/async_injectable.rs30
-rw-r--r--src/interfaces/injectable.rs30
-rw-r--r--src/lib.rs13
-rw-r--r--src/private/cast/arc.rs93
-rw-r--r--src/private/cast/boxed.rs87
-rw-r--r--src/private/cast/error.rs20
-rw-r--r--src/private/cast/mod.rs273
-rw-r--r--src/private/cast/rc.rs87
-rw-r--r--src/private/mod.rs6
-rw-r--r--src/ptr_buffer.rs341
-rw-r--r--src/test_utils.rs106
13 files changed, 530 insertions, 638 deletions
diff --git a/src/di_container/asynchronous/mod.rs b/src/di_container/asynchronous/mod.rs
index 3e29ef6..e5fd1fd 100644
--- a/src/di_container/asynchronous/mod.rs
+++ b/src/di_container/asynchronous/mod.rs
@@ -55,9 +55,6 @@ use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder;
use crate::di_container::binding_storage::DIContainerBindingStorage;
use crate::di_container::BindingOptions;
use crate::errors::async_di_container::AsyncDIContainerError;
-use crate::private::cast::arc::CastArc;
-use crate::private::cast::boxed::CastBox;
-use crate::private::cast::error::CastError;
use crate::provider::r#async::{AsyncProvidable, IAsyncProvider};
use crate::ptr::SomePtr;
use crate::util::use_double;
@@ -313,38 +310,27 @@ impl AsyncDIContainer
Interface: 'static + ?Sized + Send + Sync,
{
match binding_providable {
- AsyncProvidable::Transient(transient_binding) => Ok(SomePtr::Transient(
- transient_binding.cast::<Interface>().map_err(|_| {
- AsyncDIContainerError::CastFailed {
+ AsyncProvidable::Transient(transient_binding) => {
+ let ptr_buf = transient_binding.into_ptr_buffer_box();
+
+ ptr_buf
+ .cast_into_boxed::<Interface>()
+ .ok_or_else(|| AsyncDIContainerError::CastFailed {
interface: type_name::<Interface>(),
binding_kind: "transient",
- }
- })?,
- )),
+ })
+ .map(SomePtr::Transient)
+ }
AsyncProvidable::Singleton(singleton_binding) => {
- Ok(SomePtr::ThreadsafeSingleton(
- singleton_binding
- .cast::<Interface>()
- .map_err(|err| match err {
- CastError::NotArcCastable(_) => {
- AsyncDIContainerError::InterfaceNotAsync(type_name::<
- Interface,
- >(
- ))
- }
- CastError::CastFailed {
- source: _,
- from: _,
- to: _,
- }
- | CastError::GetCasterFailed(_) => {
- AsyncDIContainerError::CastFailed {
- interface: type_name::<Interface>(),
- binding_kind: "singleton",
- }
- }
- })?,
- ))
+ let ptr_buf = singleton_binding.into_ptr_buffer_arc();
+
+ ptr_buf
+ .cast_into_arc::<Interface>()
+ .ok_or_else(|| AsyncDIContainerError::CastFailed {
+ interface: type_name::<Interface>(),
+ binding_kind: "singleton",
+ })
+ .map(SomePtr::ThreadsafeSingleton)
}
#[cfg(feature = "factory")]
AsyncProvidable::Factory(factory_binding) => {
diff --git a/src/di_container/blocking/mod.rs b/src/di_container/blocking/mod.rs
index d9efe94..7286f48 100644
--- a/src/di_container/blocking/mod.rs
+++ b/src/di_container/blocking/mod.rs
@@ -55,8 +55,6 @@ use crate::di_container::binding_storage::DIContainerBindingStorage;
use crate::di_container::blocking::binding::builder::BindingBuilder;
use crate::di_container::BindingOptions;
use crate::errors::di_container::DIContainerError;
-use crate::private::cast::boxed::CastBox;
-use crate::private::cast::rc::CastRc;
use crate::provider::blocking::{IProvider, Providable};
use crate::ptr::SomePtr;
use crate::util::use_double;
@@ -267,22 +265,28 @@ impl DIContainer
.get_binding_providable::<Interface>(binding_options, dependency_history)?;
match binding_providable {
- Providable::Transient(transient_binding) => Ok(SomePtr::Transient(
- transient_binding.cast::<Interface>().map_err(|_| {
- DIContainerError::CastFailed {
+ Providable::Transient(transient_binding) => {
+ let ptr_buf = transient_binding.into_ptr_buffer_box();
+
+ ptr_buf
+ .cast_into_boxed::<Interface>()
+ .ok_or_else(|| DIContainerError::CastFailed {
interface: type_name::<Interface>(),
binding_kind: "transient",
- }
- })?,
- )),
- Providable::Singleton(singleton_binding) => Ok(SomePtr::Singleton(
- singleton_binding.cast::<Interface>().map_err(|_| {
- DIContainerError::CastFailed {
+ })
+ .map(SomePtr::Transient)
+ }
+ Providable::Singleton(singleton_binding) => {
+ let ptr_buf = singleton_binding.into_ptr_buffer_rc();
+
+ ptr_buf
+ .cast_into_rc::<Interface>()
+ .ok_or_else(|| DIContainerError::CastFailed {
interface: type_name::<Interface>(),
binding_kind: "singleton",
- }
- })?,
- )),
+ })
+ .map(SomePtr::Singleton)
+ }
#[cfg(feature = "factory")]
Providable::Factory(factory_binding) => {
use crate::castable_factory::CastableFactory;
diff --git a/src/interfaces/async_injectable.rs b/src/interfaces/async_injectable.rs
index 3600bac..cf903e7 100644
--- a/src/interfaces/async_injectable.rs
+++ b/src/interfaces/async_injectable.rs
@@ -1,17 +1,19 @@
//! Interface for structs that can be injected into or be injected to.
use std::fmt::Debug;
use std::future::ready;
+use std::rc::Rc;
+use std::sync::Arc;
use crate::errors::injectable::InjectableError;
use crate::future::BoxFuture;
-use crate::private::cast::CastFromArc;
use crate::ptr::TransientPtr;
+use crate::ptr_buffer::PtrBuffer;
use crate::util::use_double;
use_double!(crate::dependency_history::DependencyHistory);
/// Interface for structs that can be injected into or be injected to.
-pub trait AsyncInjectable<DIContainerT>: CastFromArc
+pub trait AsyncInjectable<DIContainerT>: 'static + Send + Sync
{
/// Resolves the dependencies of the injectable.
///
@@ -24,6 +26,15 @@ pub trait AsyncInjectable<DIContainerT>: CastFromArc
where
Self: Sized + 'fut,
'di_container: 'fut;
+
+ /// A.
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer;
+
+ /// A.
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer;
+
+ /// A.
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer;
}
impl<DIContainerT> Debug for dyn AsyncInjectable<DIContainerT>
@@ -48,4 +59,19 @@ where
{
Box::pin(ready(Ok(TransientPtr::new(Self::default()))))
}
+
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer
+ {
+ PtrBuffer::new_from(self)
+ }
+
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer
+ {
+ PtrBuffer::new_from(self)
+ }
+
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer
+ {
+ PtrBuffer::new_from(self)
+ }
}
diff --git a/src/interfaces/injectable.rs b/src/interfaces/injectable.rs
index 1d3a1a7..eb0839c 100644
--- a/src/interfaces/injectable.rs
+++ b/src/interfaces/injectable.rs
@@ -1,15 +1,17 @@
//! Interface for structs that can be injected into or be injected to.
use std::fmt::Debug;
+use std::rc::Rc;
+use std::sync::Arc;
use crate::errors::injectable::InjectableError;
-use crate::private::cast::CastFrom;
use crate::ptr::TransientPtr;
+use crate::ptr_buffer::{PtrBuffer, SmartPtr};
use crate::util::use_double;
use_double!(crate::dependency_history::DependencyHistory);
/// Interface for structs that can be injected into or be injected to.
-pub trait Injectable<DIContainerT>: CastFrom
+pub trait Injectable<DIContainerT>: 'static
{
/// Resolves the dependencies of the injectable.
///
@@ -21,6 +23,15 @@ pub trait Injectable<DIContainerT>: CastFrom
) -> Result<TransientPtr<Self>, InjectableError>
where
Self: Sized;
+
+ /// A.
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer;
+
+ /// A.
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer;
+
+ /// A.
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer;
}
impl<DIContainerT> Debug for dyn Injectable<DIContainerT>
@@ -42,4 +53,19 @@ where
{
Ok(TransientPtr::new(Self::default()))
}
+
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer
+ {
+ PtrBuffer::new_from(SmartPtr::Box(self))
+ }
+
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer
+ {
+ PtrBuffer::new_from(SmartPtr::Rc(self))
+ }
+
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer
+ {
+ PtrBuffer::new_from(SmartPtr::Arc(self))
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index d93acc8..f9923f1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -93,6 +93,7 @@ pub mod di_container;
pub mod errors;
pub mod interfaces;
pub mod ptr;
+pub mod ptr_buffer;
#[cfg(feature = "async")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "async")))]
@@ -102,10 +103,7 @@ pub mod future;
#[cfg_attr(doc_cfg, doc(cfg(feature = "async")))]
pub use di_container::asynchronous::AsyncDIContainer;
pub use di_container::blocking::DIContainer;
-pub use syrette_macros::{declare_interface, injectable, named};
-
-#[doc(hidden)]
-pub mod private;
+pub use syrette_macros::{injectable, named};
mod provider;
mod util;
@@ -157,8 +155,9 @@ mod test_utils;
#[macro_export]
macro_rules! di_container_bind {
($interface: path => $implementation: ty, $di_container: ident) => {
- $di_container.bind::<dyn $interface>().to::<$implementation>().unwrap();
-
- syrette::declare_interface!($implementation -> $interface);
+ $di_container
+ .bind::<dyn $interface>()
+ .to::<$implementation>()
+ .unwrap();
};
}
diff --git a/src/private/cast/arc.rs b/src/private/cast/arc.rs
deleted file mode 100644
index 1fbdf8b..0000000
--- a/src/private/cast/arc.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-//! 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::type_name;
-use std::sync::Arc;
-
-use crate::private::cast::error::CastError;
-use crate::private::cast::{get_caster, CastFromArc};
-
-pub trait CastArc
-{
- /// Casts an `Arc` with `Self` into an `Arc` with `Dest`.
- fn cast<Dest: ?Sized + 'static>(self: Arc<Self>) -> Result<Arc<Dest>, CastError>;
-}
-
-/// A blanket implementation of `CastArc` for traits extending `CastFrom`, `Sync`, and
-/// `Send`.
-impl<CastFromSelf: ?Sized + CastFromArc> CastArc for CastFromSelf
-{
- fn cast<Dest: ?Sized + 'static>(self: Arc<Self>) -> Result<Arc<Dest>, CastError>
- {
- let caster =
- get_caster::<Dest>((*self).type_id()).map_err(CastError::GetCasterFailed)?;
-
- let cast_arc = caster
- .opt_cast_arc
- .ok_or(CastError::NotArcCastable(type_name::<Dest>()))?;
-
- cast_arc(self.arc_any()).map_err(|err| CastError::CastFailed {
- source: err,
- from: type_name::<Self>(),
- to: type_name::<Dest>(),
- })
- }
-}
-
-#[cfg(test)]
-mod tests
-{
- use std::any::Any;
- use std::fmt::{Debug, Display};
- use std::sync::Arc;
-
- use super::*;
- use crate::test_utils::subjects;
-
- #[test]
- fn can_cast_arc()
- {
- let concrete_ninja = Arc::new(subjects::Ninja);
-
- let abstract_ninja: Arc<dyn subjects::INinja> = concrete_ninja;
-
- let debug_ninja_result = abstract_ninja.cast::<dyn Debug>();
-
- assert!(debug_ninja_result.is_ok());
- }
-
- #[test]
- fn cannot_cast_arc_wrong()
- {
- let concrete_ninja = Arc::new(subjects::Ninja);
-
- let abstract_ninja: Arc<dyn subjects::INinja> = concrete_ninja;
-
- let display_ninja_result = abstract_ninja.cast::<dyn Display>();
-
- assert!(matches!(
- display_ninja_result,
- Err(CastError::GetCasterFailed(_))
- ));
- }
-
- #[test]
- fn can_cast_arc_from_any()
- {
- let concrete_ninja = Arc::new(subjects::Ninja);
-
- let any_ninja: Arc<dyn Any + Send + Sync> = concrete_ninja;
-
- let debug_ninja_result = any_ninja.cast::<dyn Debug>();
-
- assert!(debug_ninja_result.is_ok());
- }
-}
diff --git a/src/private/cast/boxed.rs b/src/private/cast/boxed.rs
deleted file mode 100644
index 074346c..0000000
--- a/src/private/cast/boxed.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-//! 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::type_name;
-
-use crate::private::cast::error::CastError;
-use crate::private::cast::{get_caster, CastFrom};
-
-pub trait CastBox
-{
- /// Casts a `Box` with `Self` into a `Box` with `Dest`.
- fn cast<Dest: ?Sized + 'static>(self: Box<Self>) -> Result<Box<Dest>, CastError>;
-}
-
-/// A blanket implementation of `CastBox` for traits extending `CastFrom`.
-impl<CastFromSelf: ?Sized + CastFrom> CastBox for CastFromSelf
-{
- fn cast<Dest: ?Sized + 'static>(self: Box<Self>) -> Result<Box<Dest>, CastError>
- {
- let caster =
- get_caster::<Dest>((*self).type_id()).map_err(CastError::GetCasterFailed)?;
-
- (caster.cast_box)(self.box_any()).map_err(|err| CastError::CastFailed {
- source: err,
- from: type_name::<Self>(),
- to: type_name::<Dest>(),
- })
- }
-}
-
-#[cfg(test)]
-mod tests
-{
- use std::any::Any;
- use std::fmt::{Debug, Display};
-
- use super::*;
- use crate::test_utils::subjects;
-
- #[test]
- fn can_cast_box()
- {
- let concrete_ninja = Box::new(subjects::Ninja);
-
- let abstract_ninja: Box<dyn subjects::INinja> = concrete_ninja;
-
- let debug_ninja_result = abstract_ninja.cast::<dyn Debug>();
-
- assert!(debug_ninja_result.is_ok());
- }
-
- #[test]
- fn cannot_cast_box_wrong()
- {
- let concrete_ninja = Box::new(subjects::Ninja);
-
- let abstract_ninja: Box<dyn subjects::INinja> = concrete_ninja;
-
- let display_ninja_result = abstract_ninja.cast::<dyn Display>();
-
- assert!(matches!(
- display_ninja_result,
- Err(CastError::GetCasterFailed(_))
- ));
- }
-
- #[test]
- fn can_cast_box_from_any()
- {
- let concrete_ninja = Box::new(subjects::Ninja);
-
- let any_ninja: Box<dyn Any> = concrete_ninja;
-
- let debug_ninja_result = any_ninja.cast::<dyn Debug>();
-
- assert!(debug_ninja_result.is_ok());
- }
-}
diff --git a/src/private/cast/error.rs b/src/private/cast/error.rs
deleted file mode 100644
index c6ed01d..0000000
--- a/src/private/cast/error.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use crate::private::cast::{CasterError, GetCasterError};
-
-#[derive(thiserror::Error, Debug)]
-pub enum CastError
-{
- #[error("Failed to get caster")]
- GetCasterFailed(#[from] GetCasterError),
-
- #[error("Failed to cast from {from} to {to}")]
- CastFailed
- {
- #[source]
- source: CasterError,
- from: &'static str,
- to: &'static str,
- },
-
- #[error("'{0}' can't be cast to an Arc")]
- NotArcCastable(&'static str),
-}
diff --git a/src/private/cast/mod.rs b/src/private/cast/mod.rs
deleted file mode 100644
index ddff2a4..0000000
--- a/src/private/cast/mod.rs
+++ /dev/null
@@ -1,273 +0,0 @@
-//! 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::rc::Rc;
-use std::sync::Arc;
-
-use ahash::AHashMap;
-use linkme::distributed_slice;
-use once_cell::sync::Lazy;
-
-pub mod arc;
-pub mod boxed;
-pub mod error;
-pub mod rc;
-
-pub type BoxedCaster = Box<dyn Any + Send + Sync>;
-
-/// A distributed slice gathering constructor functions for [`Caster`]s.
-///
-/// A constructor function returns `TypeId` of a concrete type involved in the casting
-/// and a `Box` of a type or trait backed by a [`Caster`].
-#[distributed_slice]
-pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..];
-
-/// A `HashMap` mapping `TypeId` of a [`Caster`] to an instance of it.
-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()
-});
-
-type CastBoxFn<Dest> = fn(from: Box<dyn Any>) -> Result<Box<Dest>, CasterError>;
-
-type CastRcFn<Dest> = fn(from: Rc<dyn Any>) -> Result<Rc<Dest>, CasterError>;
-
-type CastArcFn<Dest> =
- fn(from: Arc<dyn Any + Sync + Send + 'static>) -> Result<Arc<Dest>, CasterError>;
-
-/// A `Caster` knows how to cast a type or trait to the type or trait `Dest`. Each
-/// `Caster` instance is specific to a concrete type. That is, it knows how to cast to
-/// single specific type or trait implemented by single specific type.
-pub struct Caster<Dest: ?Sized + 'static>
-{
- /// Casts a `Box` holding a type or trait object for `Any` to another `Box` holding a
- /// type or trait `Dest`.
- pub cast_box: CastBoxFn<Dest>,
-
- /// Casts an `Rc` holding a type or trait for `Any` to another `Rc` holding a type or
- /// trait `Dest`.
- pub cast_rc: CastRcFn<Dest>,
-
- /// Casts an `Arc` holding a type or trait for `Any + Sync + Send + 'static` to
- /// another `Arc` holding a type or trait for `Dest`.
- pub opt_cast_arc: Option<CastArcFn<Dest>>,
-}
-
-impl<Dest: ?Sized + 'static> Caster<Dest>
-{
- pub fn new(cast_box: CastBoxFn<Dest>, cast_rc: CastRcFn<Dest>) -> Caster<Dest>
- {
- Caster::<Dest> {
- cast_box,
- cast_rc,
- opt_cast_arc: None,
- }
- }
-
- #[allow(clippy::similar_names)]
- pub fn new_sync(
- cast_box: CastBoxFn<Dest>,
- cast_rc: CastRcFn<Dest>,
- cast_arc: CastArcFn<Dest>,
- ) -> Caster<Dest>
- {
- Caster::<Dest> {
- cast_box,
- cast_rc,
- opt_cast_arc: Some(cast_arc),
- }
- }
-}
-
-#[derive(Debug, thiserror::Error)]
-pub enum CasterError
-{
- #[error("Failed to cast Box")]
- CastBoxFailed,
-
- #[error("Failed to cast Rc")]
- CastRcFailed,
-
- #[error("Failed to cast Arc")]
- CastArcFailed,
-}
-
-/// Returns a `Caster<Dest>` from a concrete type with the id `type_id` to a type or trait
-/// `Dest`.
-fn get_caster<Dest: ?Sized + 'static>(
- type_id: TypeId,
-) -> Result<&'static Caster<Dest>, GetCasterError>
-{
- let any_caster = CASTER_MAP
- .get(&(type_id, TypeId::of::<Caster<Dest>>()))
- .ok_or(GetCasterError::NotFound)?;
-
- any_caster
- .downcast_ref::<Caster<Dest>>()
- .ok_or(GetCasterError::DowncastFailed)
-}
-
-#[derive(Debug, thiserror::Error)]
-pub enum GetCasterError
-{
- #[error("Caster not found")]
- NotFound,
-
- #[error("Failed to downcast caster")]
- DowncastFailed,
-}
-
-/// `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>;
-}
-
-/// This trait must be extended by a trait that is `Any + Sync + Send + 'static`
-/// and wants to allow for casting into another trait behind references and smart pointers
-/// especially including `Arc`.
-///
-/// It is used for obtaining a trait object for [`Any + Sync + Send + 'static`] from an
-/// object for its sub-trait, and blanket implemented for all `Sized + Sync + Send +
-/// 'static` types.
-///
-/// # Examples
-/// ```ignore
-/// trait Source: CastFromArc {
-/// ...
-/// }
-/// ```
-pub trait CastFromArc: CastFrom + Sync + Send + 'static
-{
- fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>;
-}
-
-impl<Source: Sized + Any + 'static> CastFrom for Source
-{
- 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<Source: Sized + Sync + Send + 'static> CastFromArc for Source
-{
- fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>
- {
- 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
- }
-}
-
-impl CastFromArc for dyn Any + Sync + Send + 'static
-{
- fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>
- {
- self
- }
-}
-
-#[cfg(test)]
-mod tests
-{
- use std::any::TypeId;
- use std::fmt::Debug;
-
- use linkme::distributed_slice;
-
- use super::*;
- use crate::test_utils::subjects;
-
- #[distributed_slice(super::CASTERS)]
- static TEST_CASTER: fn() -> (TypeId, BoxedCaster) = create_test_caster;
-
- fn create_test_caster() -> (TypeId, BoxedCaster)
- {
- let type_id = TypeId::of::<subjects::Ninja>();
-
- let caster = Box::new(Caster::<dyn Debug> {
- cast_box: |from| {
- let concrete = from
- .downcast::<subjects::Ninja>()
- .map_err(|_| CasterError::CastBoxFailed)?;
-
- Ok(concrete as Box<dyn Debug>)
- },
- cast_rc: |from| {
- let concrete = from
- .downcast::<subjects::Ninja>()
- .map_err(|_| CasterError::CastRcFailed)?;
-
- Ok(concrete as Rc<dyn Debug>)
- },
- opt_cast_arc: Some(|from| {
- let concrete = from
- .downcast::<subjects::Ninja>()
- .map_err(|_| CasterError::CastArcFailed)?;
-
- Ok(concrete as Arc<dyn Debug>)
- }),
- });
- (type_id, caster)
- }
-}
diff --git a/src/private/cast/rc.rs b/src/private/cast/rc.rs
deleted file mode 100644
index 11d137a..0000000
--- a/src/private/cast/rc.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-//! 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::type_name;
-use std::rc::Rc;
-
-use crate::private::cast::error::CastError;
-use crate::private::cast::{get_caster, CastFrom};
-
-pub trait CastRc
-{
- /// Casts an `Rc` with `Self `into a `Rc` with `Dest`.
- fn cast<Dest: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<Dest>, CastError>;
-}
-
-/// A blanket implementation of `CastRc` for traits extending `CastFrom`.
-impl<CastFromSelf: ?Sized + CastFrom> CastRc for CastFromSelf
-{
- fn cast<Dest: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<Dest>, CastError>
- {
- let caster =
- get_caster::<Dest>((*self).type_id()).map_err(CastError::GetCasterFailed)?;
-
- (caster.cast_rc)(self.rc_any()).map_err(|err| CastError::CastFailed {
- source: err,
- from: type_name::<Self>(),
- to: type_name::<Dest>(),
- })
- }
-}
-
-#[cfg(test)]
-mod tests
-{
- use std::any::Any;
- use std::fmt::{Debug, Display};
-
- use super::*;
- use crate::test_utils::subjects;
-
- #[test]
- fn can_cast_rc()
- {
- let concrete_ninja = Rc::new(subjects::Ninja);
-
- let abstract_ninja: Rc<dyn subjects::INinja> = concrete_ninja;
-
- let debug_ninja_result = abstract_ninja.cast::<dyn Debug>();
-
- assert!(debug_ninja_result.is_ok());
- }
-
- #[test]
- fn cannot_cast_rc_wrong()
- {
- let concrete_ninja = Rc::new(subjects::Ninja);
-
- let abstract_ninja: Rc<dyn subjects::INinja> = concrete_ninja;
-
- let display_ninja_result = abstract_ninja.cast::<dyn Display>();
-
- assert!(matches!(
- display_ninja_result,
- Err(CastError::GetCasterFailed(_))
- ));
- }
-
- #[test]
- fn can_cast_rc_from_any()
- {
- let concrete_ninja = Rc::new(subjects::Ninja);
-
- let any_ninja: Rc<dyn Any> = concrete_ninja;
-
- let debug_ninja_result = any_ninja.cast::<dyn Debug>();
-
- assert!(debug_ninja_result.is_ok());
- }
-}
diff --git a/src/private/mod.rs b/src/private/mod.rs
deleted file mode 100644
index 9b03ce8..0000000
--- a/src/private/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! This module contains items that's not in the public API but is used by the
-//! library user with the expansions of the macros in the syrette_macros crate.
-
-pub mod cast;
-
-pub extern crate linkme;
diff --git a/src/ptr_buffer.rs b/src/ptr_buffer.rs
new file mode 100644
index 0000000..e1e2fc6
--- /dev/null
+++ b/src/ptr_buffer.rs
@@ -0,0 +1,341 @@
+//! Pointer buffer;
+
+use std::any::TypeId;
+use std::mem::{size_of, MaybeUninit};
+use std::ptr::addr_of;
+use std::rc::Rc;
+use std::sync::Arc;
+
+/// Pointer buffer;
+pub struct PtrBuffer
+{
+ buf: Box<[MaybeUninit<u8>]>,
+ type_id: TypeId,
+ kind: Kind,
+}
+
+impl PtrBuffer
+{
+ /// AA.
+ #[must_use]
+ pub fn new_from<Value, ValuePtr>(value: ValuePtr) -> Self
+ where
+ Value: ?Sized + 'static,
+ ValuePtr: Into<SmartPtr<Value>>,
+ {
+ let value = value.into();
+
+ let kind = value.kind();
+
+ let buf = ptr_to_byte_buf(value.into_raw());
+
+ Self {
+ buf,
+ type_id: TypeId::of::<Value>(),
+ kind,
+ }
+ }
+
+ pub(crate) fn cast_into_boxed<Dest>(self) -> Option<Box<Dest>>
+ where
+ Dest: ?Sized + 'static,
+ {
+ if !matches!(self.kind, Kind::Box) {
+ return None;
+ }
+
+ let dest_ptr = self.cast_into()?;
+
+ // SAFETY: We know the pointer was retrieved using Box::into_raw in the
+ // new_from function since the kind is Kind::Box (checked above). We
+ // also know it was the exact same pointed to type since this is checked in the
+ // cast_into function
+ Some(unsafe { Box::from_raw(dest_ptr) })
+ }
+
+ pub(crate) fn cast_into_rc<Dest>(self) -> Option<Rc<Dest>>
+ where
+ Dest: ?Sized + 'static,
+ {
+ if !matches!(self.kind, Kind::Rc) {
+ return None;
+ }
+
+ let dest_ptr = self.cast_into()?;
+
+ // SAFETY: We know the pointer was retrieved using Rc::into_raw in the
+ // new_from function since the kind is Kind::Rc (checked above). We
+ // also know it was the exact same pointed to type since this is checked in the
+ // cast_into function
+ Some(unsafe { Rc::from_raw(dest_ptr) })
+ }
+
+ #[cfg(feature = "async")]
+ pub(crate) fn cast_into_arc<Dest>(self) -> Option<Arc<Dest>>
+ where
+ Dest: ?Sized + 'static,
+ {
+ if !matches!(self.kind, Kind::Arc) {
+ return None;
+ }
+
+ let dest_ptr = self.cast_into()?;
+
+ // SAFETY: We know the pointer was retrieved using Arc::into_raw in the
+ // new_from function since the kind is Kind::Arc (checked above). We
+ // also know it was the exact same pointed to type since this is checked in the
+ // cast_into function
+ Some(unsafe { Arc::from_raw(dest_ptr) })
+ }
+
+ fn cast_into<Dest>(self) -> Option<*mut Dest>
+ where
+ Dest: ?Sized + 'static,
+ {
+ if TypeId::of::<Dest>() != self.type_id {
+ return None;
+ }
+
+ if size_of::<*mut Dest>() != self.buf.len() {
+ // Pointer kinds are different so continuing would cause UB. This should
+ // not be possible since the type IDs are the same but we check it just to
+ // be extra safe
+ return None;
+ }
+
+ let mut ptr = MaybeUninit::<*mut Dest>::uninit();
+
+ // SAFETY:
+ // - We know the source buffer is valid for reads the number of bytes since it is
+ // ensured by the array primitive
+ // - We know the destination is valid for writes the number of bytes since we
+ // check above if the buffer length is the same as the size of *mut Dest
+ unsafe {
+ std::ptr::copy_nonoverlapping(
+ self.buf.as_ptr().cast::<u8>(),
+ ptr.as_mut_ptr().cast::<u8>(),
+ self.buf.len(),
+ );
+ }
+
+ // SAFETY: We initialize the value above by copying the buffer to it
+ Some(unsafe { ptr.assume_init() })
+ }
+}
+
+/// Smart pointers supported as input to [`PtrBuffer`].
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum SmartPtr<Value: ?Sized + 'static>
+{
+ /// Box.
+ Box(Box<Value>),
+
+ /// Rc.
+ Rc(Rc<Value>),
+
+ /// Arc.
+ Arc(Arc<Value>),
+}
+
+impl<Value: ?Sized + 'static> SmartPtr<Value>
+{
+ fn into_raw(self) -> *const Value
+ {
+ match self {
+ Self::Box(value) => Box::into_raw(value),
+ Self::Rc(value) => Rc::into_raw(value),
+ Self::Arc(value) => Arc::into_raw(value),
+ }
+ }
+
+ fn kind(&self) -> Kind
+ {
+ match self {
+ Self::Box(_) => Kind::Box,
+ Self::Rc(_) => Kind::Rc,
+ Self::Arc(_) => Kind::Arc,
+ }
+ }
+}
+
+impl<Value> From<Box<Value>> for SmartPtr<Value>
+where
+ Value: ?Sized + 'static,
+{
+ fn from(value: Box<Value>) -> Self
+ {
+ Self::Box(value)
+ }
+}
+
+impl<Value> From<Rc<Value>> for SmartPtr<Value>
+where
+ Value: ?Sized + 'static,
+{
+ fn from(value: Rc<Value>) -> Self
+ {
+ Self::Rc(value)
+ }
+}
+
+impl<Value> From<Arc<Value>> for SmartPtr<Value>
+where
+ Value: ?Sized + 'static,
+{
+ fn from(value: Arc<Value>) -> Self
+ {
+ Self::Arc(value)
+ }
+}
+
+enum Kind
+{
+ Box,
+ Rc,
+ Arc,
+}
+
+fn ptr_to_byte_buf<Value>(value_ptr: *const Value) -> Box<[MaybeUninit<u8>]>
+where
+ Value: ?Sized + 'static,
+{
+ // Transform the full pointer (data pointer + (optional) metadata) into a byte
+ // slice
+ let value_ptr_bytes = unsafe {
+ std::slice::from_raw_parts::<u8>(
+ addr_of!(value_ptr).cast::<u8>(),
+ size_of::<*const Value>(),
+ )
+ };
+
+ value_ptr_bytes
+ .iter()
+ .map(|byte| MaybeUninit::new(*byte))
+ .collect::<Vec<_>>()
+ .into()
+}
+
+#[cfg(test)]
+mod tests
+{
+ use std::mem::{size_of, transmute, MaybeUninit};
+ use std::path::PathBuf;
+ use std::rc::Rc;
+
+ use crate::ptr_buffer::{ptr_to_byte_buf, PtrBuffer};
+
+ trait Anything
+ {
+ fn get_value(&self) -> u32;
+ }
+
+ struct Something;
+
+ impl Anything for Something
+ {
+ fn get_value(&self) -> u32
+ {
+ 1234
+ }
+ }
+
+ #[test]
+ fn works_with_thin()
+ {
+ let text = Box::new("Hello there".to_string());
+
+ let ptr_buf = PtrBuffer::new_from(text);
+
+ assert!(ptr_buf
+ .cast_into_boxed::<String>()
+ .map_or_else(|| false, |text| *text == "Hello there"));
+ }
+
+ #[test]
+ fn works_with_dyn()
+ {
+ let text: Box<dyn Anything> = Box::new(Something);
+
+ let ptr_buf = PtrBuffer::new_from(text);
+
+ assert!(ptr_buf
+ .cast_into_boxed::<dyn Anything>()
+ .map_or_else(|| false, |anything| anything.get_value() == 1234));
+ }
+
+ #[test]
+ fn cast_box_when_wrong_kind_fails()
+ {
+ let text = Rc::new("Hello there".to_string());
+
+ let ptr_buf = PtrBuffer::new_from(text);
+
+ assert!(ptr_buf.cast_into_boxed::<String>().is_none());
+ }
+
+ #[test]
+ fn cast_rc_when_wrong_kind_fails()
+ {
+ let text = Box::new("Hello there".to_string());
+
+ let ptr_buf = PtrBuffer::new_from(text);
+
+ assert!(ptr_buf.cast_into_rc::<String>().is_none());
+ }
+
+ #[test]
+ #[cfg(feature = "async")]
+ fn cast_arc_when_wrong_kind_fails()
+ {
+ let text = Box::new("Hello there".to_string());
+
+ let ptr_buf = PtrBuffer::new_from(text);
+
+ assert!(ptr_buf.cast_into_arc::<String>().is_none());
+ }
+
+ #[test]
+ fn cast_into_fails_when_wrong_type()
+ {
+ let text = Box::new(123_456u64);
+
+ let ptr_buf = PtrBuffer::new_from(text);
+
+ assert!(ptr_buf.cast_into::<PathBuf>().is_none());
+ }
+
+ #[test]
+ fn ptr_to_byte_buf_works()
+ {
+ let thin_ptr_addr = 123_456_789usize;
+
+ assert_eq!(
+ unsafe {
+ slice_assume_init_ref(&ptr_to_byte_buf(thin_ptr_addr as *const u32))
+ },
+ thin_ptr_addr.to_ne_bytes()
+ );
+
+ let fat_ptr_addr_buf: [u8; size_of::<*const dyn Send>()] =
+ [26, 88, 91, 77, 2, 0, 0, 0, 12, 34, 56, 78, 90, 9, 98, 87];
+
+ let fat_ptr_addr: *const dyn Send = unsafe { transmute(fat_ptr_addr_buf) };
+
+ assert_eq!(
+ unsafe { slice_assume_init_ref(&ptr_to_byte_buf(fat_ptr_addr)) },
+ &fat_ptr_addr_buf
+ );
+ }
+
+ /// TODO: Remove when `MaybeUninit::slice_assume_init_ref` is stabilized
+ const unsafe fn slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T]
+ {
+ // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees
+ // that `slice` is initialized, and `MaybeUninit` is guaranteed to have
+ // the same layout as `T`. The pointer obtained is valid since it refers
+ // to memory owned by `slice` which is a reference and thus guaranteed to
+ // be valid for reads.
+ unsafe { &*(slice as *const [MaybeUninit<T>] as *const [T]) }
+ }
+}
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 491e9b4..f0858b5 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -3,11 +3,10 @@ pub mod subjects
//! Test subjects.
use std::fmt::Debug;
-
- use syrette_macros::declare_interface;
+ use std::rc::Rc;
+ use std::sync::Arc;
use crate::interfaces::injectable::Injectable;
- use crate::private::cast::CastFromArc;
use crate::ptr::TransientPtr;
use_double!(crate::dependency_history::DependencyHistory);
@@ -42,11 +41,9 @@ pub mod subjects
}
}
- use crate as syrette;
+ use crate::ptr_buffer::PtrBuffer;
use crate::util::use_double;
- declare_interface!(UserManager -> IUserManager);
-
impl<DIContainerT> Injectable<DIContainerT> for UserManager
{
fn resolve(
@@ -58,6 +55,27 @@ pub mod subjects
{
Ok(TransientPtr::new(Self::new()))
}
+
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer
+ {
+ let me: Box<dyn IUserManager> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer
+ {
+ let me: Rc<dyn IUserManager> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer
+ {
+ let me: Arc<dyn IUserManager> = self;
+
+ PtrBuffer::new_from(me)
+ }
}
pub trait INumber
@@ -109,8 +127,6 @@ pub mod subjects
}
}
- declare_interface!(Number -> INumber);
-
impl<DIContainerT> Injectable<DIContainerT> for Number
{
fn resolve(
@@ -122,12 +138,33 @@ pub mod subjects
{
Ok(TransientPtr::new(Self::new()))
}
+
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer
+ {
+ let me: Box<dyn INumber> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer
+ {
+ let me: Rc<dyn INumber> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer
+ {
+ let me: Arc<dyn INumber> = self;
+
+ PtrBuffer::new_from(me)
+ }
}
#[derive(Debug)]
pub struct Ninja;
- pub trait INinja: CastFromArc {}
+ pub trait INinja {}
impl INinja for Ninja {}
}
@@ -138,9 +175,10 @@ pub mod subjects_async
//! Test subjects.
use std::fmt::Debug;
+ use std::rc::Rc;
+ use std::sync::Arc;
use async_trait::async_trait;
- use syrette_macros::declare_interface;
use crate::interfaces::async_injectable::AsyncInjectable;
use crate::ptr::TransientPtr;
@@ -177,11 +215,9 @@ pub mod subjects_async
}
}
- use crate as syrette;
+ use crate::ptr_buffer::PtrBuffer;
use crate::util::use_double;
- declare_interface!(UserManager -> IUserManager);
-
#[async_trait]
impl<DIContainerType> AsyncInjectable<DIContainerType> for UserManager
{
@@ -194,6 +230,27 @@ pub mod subjects_async
{
Ok(TransientPtr::new(Self::new()))
}
+
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer
+ {
+ let me: Box<dyn IUserManager> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer
+ {
+ let me: Rc<dyn IUserManager> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer
+ {
+ let me: Arc<dyn IUserManager> = self;
+
+ PtrBuffer::new_from(me)
+ }
}
pub trait INumber: Send + Sync
@@ -245,8 +302,6 @@ pub mod subjects_async
}
}
- declare_interface!(Number -> INumber, threadsafe_sharable = true);
-
#[async_trait]
impl<DIContainerType> AsyncInjectable<DIContainerType> for Number
{
@@ -259,6 +314,27 @@ pub mod subjects_async
{
Ok(TransientPtr::new(Self::new()))
}
+
+ fn into_ptr_buffer_box(self: Box<Self>) -> PtrBuffer
+ {
+ let me: Box<dyn INumber> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_rc(self: Rc<Self>) -> PtrBuffer
+ {
+ let me: Rc<dyn INumber> = self;
+
+ PtrBuffer::new_from(me)
+ }
+
+ fn into_ptr_buffer_arc(self: Arc<Self>) -> PtrBuffer
+ {
+ let me: Arc<dyn INumber> = self;
+
+ PtrBuffer::new_from(me)
+ }
}
}