Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Leandros committed Oct 18, 2024
1 parent 7a688cc commit 6589bec
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 15 deletions.
44 changes: 44 additions & 0 deletions ferrunix-core/src/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ pub trait Dep: Registerable + private::Sealed {
/// This function is allowed to panic, if the type isn't registered.
fn new(registry: &Registry) -> Self;

/// Looks up the dependency in `registry`, and constructs a new [`Dep`].
///
/// This function is allowed to panic, if the type isn't registered.
#[cfg(feature = "tokio")]
fn new_async(
registry: &Registry,
) -> impl std::future::Future<Output = Self> + Send + Sync;

/// Returns [`std::any::TypeId`] of the dependency type.
fn type_id() -> TypeId;
}
Expand Down Expand Up @@ -115,6 +123,24 @@ impl<T: Registerable> Dep for Transient<T> {
}
}

/// Create a new [`Transient`], asynchronously.
///
/// # Panic
/// This function panics if the `T` isn't registered.
#[cfg(feature = "tokio")]
fn new_async(
registry: &Registry,
) -> impl std::future::Future<Output = Self> + Send + Sync {
async move {
Self {
inner: registry.get_transient_async::<T>().await.expect(
"transient dependency must only be constructed if it's \
fulfillable",
),
}
}
}

/// Returns [`std::any::TypeId`] of the inner type `T`.
fn type_id() -> TypeId {
TypeId::of::<T>()
Expand Down Expand Up @@ -184,6 +210,24 @@ impl<T: Registerable> Dep for Singleton<T> {
}
}

/// Create a new [`Singleton`], asynchronously.
///
/// # Panic
/// This function panics if the `T` isn't registered.
#[cfg(feature = "tokio")]
fn new_async(
registry: &Registry,
) -> impl std::future::Future<Output = Self> + Send + Sync {
async move {
Self {
inner: registry.get_singleton_async::<T>().await.expect(
"singleton dependency must only be constructed if it's \
fulfillable",
),
}
}
}

/// Returns [`std::any::TypeId`] of the inner type `T`.
fn type_id() -> TypeId {
TypeId::of::<T>()
Expand Down
69 changes: 69 additions & 0 deletions ferrunix-core/src/dependency_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,33 @@ pub trait DepBuilder<R> {
where
R: Sized;

/// When implemented, this should validate that all dependencies which are
/// part of `Self` exist to construct the type `R`. If the dependencies
/// cannot be fulfilled, `None` must be returned.
///
/// If the dependencies can be fulfilled, they must be constructed as an
/// N-ary tuple (same length and types as `Self`) and passed as the
/// argument to `ctor`. `ctor` is a user provided constructor for the
/// type `R`.
///
/// An implementation for tuples is provided by `DepBuilderImpl!`.
///
/// We advise against *manually* implementing `build`.
#[cfg(feature = "tokio")]
fn build_async(
registry: &Registry,
ctor: fn(
Self,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = R> + Send + Sync>,
>,
_: private::SealToken,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Option<R>> + Send + Sync + '_>,
>
where
R: Sized;

/// Constructs a [`Vec`] of [`std::any::TypeId`]s from the types in `Self`.
/// The resulting vector must have the same length as `Self`.
///
Expand All @@ -66,6 +93,21 @@ where
Some(ctor(()))
}

#[cfg(feature = "tokio")]
fn build_async(
_registry: &Registry,
ctor: fn(
Self,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = R> + Send + Sync>,
>,
_: private::SealToken,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Option<R>> + Send + Sync + '_>,
> {
Box::pin(async move { Some(ctor(()).await) })
}

fn as_typeids(_: private::SealToken) -> Vec<TypeId> {
Vec::new()
}
Expand Down Expand Up @@ -93,6 +135,33 @@ macro_rules! DepBuilderImpl {
Some(ctor(deps))
}

#[cfg(feature = "tokio")]
fn build_async(
registry: &Registry,
ctor: fn(
Self,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = R> + Send + Sync>,
>,
_: private::SealToken,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Option<R>> + Send + Sync + '_>,
> {
if !registry.validate::<R>() {
return Box::pin(async move { None });
}

Box::pin(async move {
let deps = (
$(
<$ts>::new_async(registry).await,
)*
);

Some(ctor(deps).await)
})
}

fn as_typeids(_: private::SealToken) -> ::std::vec::Vec<::std::any::TypeId> {
::std::vec![ $(<$ts>::type_id(),)* ]
}
Expand Down
43 changes: 28 additions & 15 deletions ferrunix-core/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,23 +473,36 @@ where
&self,
ctor: fn(
Deps,
)
-> Box<dyn std::future::Future<Output = T> + Send + Sync>,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = T> + Send + Sync>,
>,
) {
let transient =
Object::Transient(Box::new(move |this| -> Option<BoxedAny> {
#[allow(clippy::option_if_let_else)]
match Deps::build(
this,
ctor,
dependency_builder::private::SealToken,
) {
Some(obj) => Some(Box::new(obj)),
None => None,
}
}));
let transient = AsyncObject::AsyncTransient(Box::new(
move |this: &'_ Registry| -> std::pin::Pin<
Box<
dyn std::future::Future<Output = Option<BoxedAny>>
+ Send
+ Sync
+ '_,
>,
> {
Box::pin(async move {
#[allow(clippy::option_if_let_else)]
match Deps::build_async(
this,
ctor,
dependency_builder::private::SealToken,
)
.await
{
Some(obj) => Some(Box::new(obj) as BoxedAny),
None => None,
}
})
},
));
{
let mut lock = self.registry.objects.write();
let mut lock = self.registry.objects_async.write().await;
lock.insert(TypeId::of::<T>(), transient);
}

Expand Down

0 comments on commit 6589bec

Please sign in to comment.