diff --git a/src/async_constructible.rs b/src/async_constructible.rs index 2a66727..73dae72 100644 --- a/src/async_constructible.rs +++ b/src/async_constructible.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{any::Any, sync::Arc}; use async_trait::async_trait; @@ -12,11 +12,20 @@ use crate::{ /// Implemented for values which can be constructed asynchronously from other /// resources. Requires feature `async`. #[async_trait] -pub trait AsyncConstructible: Sized { +pub trait AsyncConstructible: Sized + Any + Send + Sync { /// Error type for when resource fails to be constructed. type Error: Into + Send + Sync; /// Construct the resource with the provided application state. async fn construct_async(aero: &Aerosol) -> Result; + /// Called after construction with the concrete resource to allow the callee + /// to provide additional resources. Can be used by eg. an `Arc` to also + /// provide an implementation of `Arc`. + async fn after_construction_async( + _this: &(dyn Any + Send + Sync), + _aero: &Aerosol, + ) -> Result<(), Self::Error> { + Ok(()) + } } #[async_trait] @@ -25,16 +34,31 @@ impl AsyncConstructible for T { async fn construct_async(aero: &Aerosol) -> Result { Self::construct(aero) } + async fn after_construction_async( + this: &(dyn Any + Send + Sync), + aero: &Aerosol, + ) -> Result<(), Self::Error> { + Self::after_construction(this, aero) + } } /// Automatically implemented for values which can be indirectly asynchronously constructed from other resources. /// Requires feature `async`. #[async_trait] -pub trait IndirectlyAsyncConstructible: Sized { +pub trait IndirectlyAsyncConstructible: Sized + Any + Send + Sync { /// Error type for when resource fails to be constructed. type Error: Into + Send + Sync; /// Construct the resource with the provided application state. async fn construct_async(aero: &Aerosol) -> Result; + /// Called after construction with the concrete resource to allow the callee + /// to provide additional resources. Can be used by eg. an `Arc` to also + /// provide an implementation of `Arc`. + async fn after_construction_async( + _this: &(dyn Any + Send + Sync), + _aero: &Aerosol, + ) -> Result<(), Self::Error> { + Ok(()) + } } #[async_trait] @@ -42,7 +66,15 @@ impl IndirectlyAsyncConstructible for T { type Error = T::Error; async fn construct_async(aero: &Aerosol) -> Result { - T::construct_async(aero).await + let res = ::construct_async(aero).await?; + ::after_construction_async(&res, aero).await?; + Ok(res) + } + async fn after_construction_async( + this: &(dyn Any + Send + Sync), + aero: &Aerosol, + ) -> Result<(), Self::Error> { + ::after_construction_async(this, aero).await } } @@ -54,7 +86,13 @@ macro_rules! impl_async_constructible { type Error = $t::Error; async fn construct_async(aero: &Aerosol) -> Result { - $t::construct_async(aero).await.map($y) + let res = $y($t::construct_async(aero).await?); + <$t as IndirectlyAsyncConstructible>::after_construction_async(&res, aero).await?; + Ok(res) + } + + async fn after_construction_async(this: &(dyn Any + Send + Sync), aero: &Aerosol) -> Result<(), Self::Error> { + <$t as IndirectlyAsyncConstructible>::after_construction_async(this, aero).await } } )* @@ -271,4 +309,37 @@ mod tests { let state = Aerosol::new(); state.obtain_async::>().await; } + + trait DummyTrait: Send + Sync {} + + #[derive(Debug)] + struct DummyImpl; + + impl DummyTrait for DummyImpl {} + + #[async_trait] + impl AsyncConstructible for DummyImpl { + type Error = Infallible; + + async fn construct_async(_app_state: &Aerosol) -> Result { + Ok(Self) + } + + async fn after_construction_async( + this: &(dyn Any + Send + Sync), + aero: &Aerosol, + ) -> Result<(), Self::Error> { + if let Some(arc) = this.downcast_ref::>() { + aero.insert(arc.clone() as Arc) + } + Ok(()) + } + } + + #[tokio::test] + async fn obtain_impl() { + let state = Aerosol::new(); + state.init_async::>().await; + state.get_async::>().await; + } } diff --git a/src/sync_constructible.rs b/src/sync_constructible.rs index 0ece9a6..bffacfd 100644 --- a/src/sync_constructible.rs +++ b/src/sync_constructible.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{any::Any, sync::Arc}; use crate::{ resource::{unwrap_constructed, Resource}, @@ -7,39 +7,73 @@ use crate::{ }; /// Implemented for values which can be constructed from other resources. -pub trait Constructible: Sized { +pub trait Constructible: Sized + Any + Send + Sync { /// Error type for when resource fails to be constructed. type Error: Into + Send + Sync; /// Construct the resource with the provided application state. fn construct(aero: &Aerosol) -> Result; + + /// Called after construction with the concrete resource to allow the callee + /// to provide additional resources. Can be used by eg. an `Arc` to also + /// provide an implementation of `Arc`. + fn after_construction( + _this: &(dyn Any + Send + Sync), + _aero: &Aerosol, + ) -> Result<(), Self::Error> { + Ok(()) + } } /// Automatically implemented for values which can be indirectly constructed from other resources. -pub trait IndirectlyConstructible: Sized { +pub trait IndirectlyConstructible: Sized + Any + Send + Sync { /// Error type for when resource fails to be constructed. type Error: Into + Send + Sync; /// Construct the resource with the provided application state. fn construct(aero: &Aerosol) -> Result; + /// Called after construction with the concrete resource to allow the callee + /// to provide additional resources. Can be used by eg. an `Arc` to also + /// provide an implementation of `Arc`. + fn after_construction( + _this: &(dyn Any + Send + Sync), + _aero: &Aerosol, + ) -> Result<(), Self::Error> { + Ok(()) + } } impl IndirectlyConstructible for T { type Error = T::Error; fn construct(aero: &Aerosol) -> Result { - T::construct(aero) + let res = ::construct(aero)?; + ::after_construction(&res, aero)?; + Ok(res) + } + + fn after_construction( + this: &(dyn Any + Send + Sync), + aero: &Aerosol, + ) -> Result<(), Self::Error> { + ::after_construction(this, aero) } } macro_rules! impl_constructible { (<$t:ident>; $($x:ty: $y:expr;)*) => { $( - impl<$t: IndirectlyConstructible> IndirectlyConstructible for $x { - type Error = $t::Error; + impl<$t: IndirectlyConstructible> IndirectlyConstructible for $x { + type Error = $t::Error; - fn construct(aero: &Aerosol) -> Result { - $t::construct(aero).map($y) + fn construct(aero: &Aerosol) -> Result { + let res = $y($t::construct(aero)?); + <$t as IndirectlyConstructible>::after_construction(&res, aero)?; + Ok(res) + } + + fn after_construction(this: &(dyn Any + Send + Sync), aero: &Aerosol) -> Result<(), Self::Error> { + <$t as IndirectlyConstructible>::after_construction(this, aero) + } } - } )* }; } @@ -200,4 +234,36 @@ mod tests { let state = Aerosol::new(); state.obtain::>(); } + + trait DummyTrait: Send + Sync {} + + #[derive(Debug)] + struct DummyImpl; + + impl DummyTrait for DummyImpl {} + + impl Constructible for DummyImpl { + type Error = Infallible; + + fn construct(_app_state: &Aerosol) -> Result { + Ok(Self) + } + + fn after_construction( + this: &(dyn Any + Send + Sync), + aero: &Aerosol, + ) -> Result<(), Self::Error> { + if let Some(arc) = this.downcast_ref::>() { + aero.insert(arc.clone() as Arc) + } + Ok(()) + } + } + + #[test] + fn obtain_impl() { + let state = Aerosol::new(); + state.init::>(); + state.get::>(); + } }