mirror of
https://github.com/TECHNOFAB11/aerosol.git
synced 2025-12-11 23:50:07 +01:00
Add "post construction" hooks for adding additional resources
This commit is contained in:
parent
079fbb4654
commit
3d7c0bed49
2 changed files with 151 additions and 14 deletions
|
|
@ -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<anyhow::Error> + Send + Sync;
|
||||
/// Construct the resource with the provided application state.
|
||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error>;
|
||||
/// Called after construction with the concrete resource to allow the callee
|
||||
/// to provide additional resources. Can be used by eg. an `Arc<Foo>` to also
|
||||
/// provide an implementation of `Arc<dyn Bar>`.
|
||||
async fn after_construction_async(
|
||||
_this: &(dyn Any + Send + Sync),
|
||||
_aero: &Aerosol,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
|
@ -25,16 +34,31 @@ impl<T: Constructible> AsyncConstructible for T {
|
|||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error> {
|
||||
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<anyhow::Error> + Send + Sync;
|
||||
/// Construct the resource with the provided application state.
|
||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error>;
|
||||
/// Called after construction with the concrete resource to allow the callee
|
||||
/// to provide additional resources. Can be used by eg. an `Arc<Foo>` to also
|
||||
/// provide an implementation of `Arc<dyn Bar>`.
|
||||
async fn after_construction_async(
|
||||
_this: &(dyn Any + Send + Sync),
|
||||
_aero: &Aerosol,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
|
@ -42,7 +66,15 @@ impl<T: AsyncConstructible> IndirectlyAsyncConstructible for T {
|
|||
type Error = T::Error;
|
||||
|
||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error> {
|
||||
T::construct_async(aero).await
|
||||
let res = <T as AsyncConstructible>::construct_async(aero).await?;
|
||||
<T as AsyncConstructible>::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 AsyncConstructible>::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<Self, Self::Error> {
|
||||
$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::<Arc<DummyNonClone>>().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<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
async fn after_construction_async(
|
||||
this: &(dyn Any + Send + Sync),
|
||||
aero: &Aerosol,
|
||||
) -> Result<(), Self::Error> {
|
||||
if let Some(arc) = this.downcast_ref::<Arc<Self>>() {
|
||||
aero.insert(arc.clone() as Arc<dyn DummyTrait>)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn obtain_impl() {
|
||||
let state = Aerosol::new();
|
||||
state.init_async::<Arc<DummyImpl>>().await;
|
||||
state.get_async::<Arc<dyn DummyTrait>>().await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::{any::Any, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
resource::{unwrap_constructed, Resource},
|
||||
|
|
@ -7,26 +7,54 @@ 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<anyhow::Error> + Send + Sync;
|
||||
/// Construct the resource with the provided application state.
|
||||
fn construct(aero: &Aerosol) -> Result<Self, Self::Error>;
|
||||
|
||||
/// Called after construction with the concrete resource to allow the callee
|
||||
/// to provide additional resources. Can be used by eg. an `Arc<Foo>` to also
|
||||
/// provide an implementation of `Arc<dyn Bar>`.
|
||||
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<anyhow::Error> + Send + Sync;
|
||||
/// Construct the resource with the provided application state.
|
||||
fn construct(aero: &Aerosol) -> Result<Self, Self::Error>;
|
||||
/// Called after construction with the concrete resource to allow the callee
|
||||
/// to provide additional resources. Can be used by eg. an `Arc<Foo>` to also
|
||||
/// provide an implementation of `Arc<dyn Bar>`.
|
||||
fn after_construction(
|
||||
_this: &(dyn Any + Send + Sync),
|
||||
_aero: &Aerosol,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Constructible> IndirectlyConstructible for T {
|
||||
type Error = T::Error;
|
||||
|
||||
fn construct(aero: &Aerosol) -> Result<Self, Self::Error> {
|
||||
T::construct(aero)
|
||||
let res = <T as Constructible>::construct(aero)?;
|
||||
<T as Constructible>::after_construction(&res, aero)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn after_construction(
|
||||
this: &(dyn Any + Send + Sync),
|
||||
aero: &Aerosol,
|
||||
) -> Result<(), Self::Error> {
|
||||
<T as Constructible>::after_construction(this, aero)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +65,13 @@ macro_rules! impl_constructible {
|
|||
type Error = $t::Error;
|
||||
|
||||
fn construct(aero: &Aerosol) -> Result<Self, Self::Error> {
|
||||
$t::construct(aero).map($y)
|
||||
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::<Arc<DummyNonClone>>();
|
||||
}
|
||||
|
||||
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<Self, Self::Error> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn after_construction(
|
||||
this: &(dyn Any + Send + Sync),
|
||||
aero: &Aerosol,
|
||||
) -> Result<(), Self::Error> {
|
||||
if let Some(arc) = this.downcast_ref::<Arc<Self>>() {
|
||||
aero.insert(arc.clone() as Arc<dyn DummyTrait>)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn obtain_impl() {
|
||||
let state = Aerosol::new();
|
||||
state.init::<Arc<DummyImpl>>();
|
||||
state.get::<Arc<dyn DummyTrait>>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue