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;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
|
@ -12,11 +12,20 @@ use crate::{
|
||||||
/// Implemented for values which can be constructed asynchronously from other
|
/// Implemented for values which can be constructed asynchronously from other
|
||||||
/// resources. Requires feature `async`.
|
/// resources. Requires feature `async`.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncConstructible: Sized {
|
pub trait AsyncConstructible: Sized + Any + Send + Sync {
|
||||||
/// Error type for when resource fails to be constructed.
|
/// Error type for when resource fails to be constructed.
|
||||||
type Error: Into<anyhow::Error> + Send + Sync;
|
type Error: Into<anyhow::Error> + Send + Sync;
|
||||||
/// Construct the resource with the provided application state.
|
/// Construct the resource with the provided application state.
|
||||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error>;
|
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]
|
#[async_trait]
|
||||||
|
|
@ -25,16 +34,31 @@ impl<T: Constructible> AsyncConstructible for T {
|
||||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error> {
|
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error> {
|
||||||
Self::construct(aero)
|
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.
|
/// Automatically implemented for values which can be indirectly asynchronously constructed from other resources.
|
||||||
/// Requires feature `async`.
|
/// Requires feature `async`.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait IndirectlyAsyncConstructible: Sized {
|
pub trait IndirectlyAsyncConstructible: Sized + Any + Send + Sync {
|
||||||
/// Error type for when resource fails to be constructed.
|
/// Error type for when resource fails to be constructed.
|
||||||
type Error: Into<anyhow::Error> + Send + Sync;
|
type Error: Into<anyhow::Error> + Send + Sync;
|
||||||
/// Construct the resource with the provided application state.
|
/// Construct the resource with the provided application state.
|
||||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::Error>;
|
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]
|
#[async_trait]
|
||||||
|
|
@ -42,7 +66,15 @@ impl<T: AsyncConstructible> IndirectlyAsyncConstructible for T {
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::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;
|
type Error = $t::Error;
|
||||||
|
|
||||||
async fn construct_async(aero: &Aerosol) -> Result<Self, Self::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();
|
let state = Aerosol::new();
|
||||||
state.obtain_async::<Arc<DummyNonClone>>().await;
|
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::{
|
use crate::{
|
||||||
resource::{unwrap_constructed, Resource},
|
resource::{unwrap_constructed, Resource},
|
||||||
|
|
@ -7,39 +7,73 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implemented for values which can be constructed from other resources.
|
/// 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.
|
/// Error type for when resource fails to be constructed.
|
||||||
type Error: Into<anyhow::Error> + Send + Sync;
|
type Error: Into<anyhow::Error> + Send + Sync;
|
||||||
/// Construct the resource with the provided application state.
|
/// Construct the resource with the provided application state.
|
||||||
fn construct(aero: &Aerosol) -> Result<Self, Self::Error>;
|
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.
|
/// 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.
|
/// Error type for when resource fails to be constructed.
|
||||||
type Error: Into<anyhow::Error> + Send + Sync;
|
type Error: Into<anyhow::Error> + Send + Sync;
|
||||||
/// Construct the resource with the provided application state.
|
/// Construct the resource with the provided application state.
|
||||||
fn construct(aero: &Aerosol) -> Result<Self, Self::Error>;
|
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 {
|
impl<T: Constructible> IndirectlyConstructible for T {
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
fn construct(aero: &Aerosol) -> Result<Self, Self::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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_constructible {
|
macro_rules! impl_constructible {
|
||||||
(<$t:ident>; $($x:ty: $y:expr;)*) => {
|
(<$t:ident>; $($x:ty: $y:expr;)*) => {
|
||||||
$(
|
$(
|
||||||
impl<$t: IndirectlyConstructible> IndirectlyConstructible for $x {
|
impl<$t: IndirectlyConstructible> IndirectlyConstructible for $x {
|
||||||
type Error = $t::Error;
|
type Error = $t::Error;
|
||||||
|
|
||||||
fn construct(aero: &Aerosol) -> Result<Self, Self::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();
|
let state = Aerosol::new();
|
||||||
state.obtain::<Arc<DummyNonClone>>();
|
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