use paste::paste;
use std::any::Any;
use std::sync::Arc;
use crate::AnyResource;
use crate::assembly::{ProduceContext, RegisterContext};
type ProduceError = Box<dyn std::error::Error>;
pub trait ResourceDependencies: Sized {
#[doc(hidden)]
fn register(cx: &mut RegisterContext);
#[doc(hidden)]
fn produce(cx: &mut ProduceContext) -> Result<Self, ProduceError>;
}
pub use comprehensive_macros::ResourceDependencies;
pub type NoDependencies = ();
pub(crate) mod sealed {
use super::*;
pub trait AvailableResource {
type ResourceType;
fn register(cx: &mut RegisterContext);
fn register_without_dependency(cx: &mut RegisterContext);
fn produce(cx: &mut ProduceContext) -> Result<Arc<Self::ResourceType>, ProduceError>;
}
pub struct SealedMarker;
}
pub struct MayFail<T>(T);
impl<T> std::ops::Deref for MayFail<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> std::ops::DerefMut for MayFail<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T> From<T> for MayFail<T> {
fn from(v: T) -> Self {
Self(v)
}
}
impl<T> MayFail<T> {
pub fn into_inner(self) -> T {
self.0
}
}
pub trait ResourceDependency: Sized {
#[doc(hidden)]
type Intermediate;
#[doc(hidden)]
fn register(cx: &mut RegisterContext);
#[doc(hidden)]
fn produce_early(cx: &mut ProduceContext) -> Result<Self::Intermediate, ProduceError>;
#[doc(hidden)]
fn produce_late(cx: &mut ProduceContext, i: Self::Intermediate) -> Result<Self, ProduceError>;
#[doc(hidden)]
fn sealed_impl() -> sealed::SealedMarker;
}
impl ResourceDependency for () {
type Intermediate = ();
fn register(_: &mut RegisterContext<'_>) {}
fn produce_early(_: &mut ProduceContext) -> Result<(), ProduceError> {
Ok(())
}
fn produce_late(_: &mut ProduceContext, _: ()) -> Result<Self, ProduceError> {
Ok(())
}
fn sealed_impl() -> sealed::SealedMarker {
sealed::SealedMarker
}
}
impl<T: AnyResource> ResourceDependency for Arc<T> {
type Intermediate = Self;
fn register(cx: &mut RegisterContext<'_>) {
<T::Target as sealed::AvailableResource>::register(cx);
}
fn produce_early(cx: &mut ProduceContext) -> Result<Self, ProduceError> {
<T::Target as sealed::AvailableResource>::produce(cx)
}
fn produce_late(_: &mut ProduceContext, i: Self) -> Result<Self, ProduceError> {
Ok(i)
}
fn sealed_impl() -> sealed::SealedMarker {
sealed::SealedMarker
}
}
impl<T: AnyResource> ResourceDependency for Option<Arc<T>> {
type Intermediate = ();
fn register(cx: &mut RegisterContext<'_>) {
<T::Target as sealed::AvailableResource>::register(cx);
}
fn produce_early(_: &mut ProduceContext) -> Result<(), ProduceError> {
Ok(())
}
fn produce_late(cx: &mut ProduceContext, _: ()) -> Result<Self, ProduceError> {
Ok(<T::Target as sealed::AvailableResource>::produce(cx).ok())
}
fn sealed_impl() -> sealed::SealedMarker {
sealed::SealedMarker
}
}
impl<T: Any + ?Sized> ResourceDependency for Vec<Arc<T>> {
type Intermediate = Self;
fn register(cx: &mut RegisterContext<'_>) {
cx.require_trait::<T>();
}
fn produce_early(cx: &mut ProduceContext) -> Result<Self, ProduceError> {
Ok(cx.produce_trait_fallible::<T>()?)
}
fn produce_late(_: &mut ProduceContext, i: Self) -> Result<Self, ProduceError> {
Ok(i)
}
fn sealed_impl() -> sealed::SealedMarker {
sealed::SealedMarker
}
}
impl<T: Any + ?Sized> ResourceDependency for MayFail<Vec<Arc<T>>> {
type Intermediate = ();
fn register(cx: &mut RegisterContext<'_>) {
cx.require_trait::<T>();
}
fn produce_early(_: &mut ProduceContext) -> Result<(), ProduceError> {
Ok(())
}
fn produce_late(cx: &mut ProduceContext, _: ()) -> Result<Self, ProduceError> {
Ok(cx.produce_trait::<T>().into())
}
fn sealed_impl() -> sealed::SealedMarker {
sealed::SealedMarker
}
}
impl<T: AnyResource> ResourceDependency for std::marker::PhantomData<T> {
type Intermediate = ();
fn register(cx: &mut RegisterContext<'_>) {
<T::Target as sealed::AvailableResource>::register_without_dependency(cx);
}
fn produce_early(_: &mut ProduceContext) -> Result<(), ProduceError> {
Ok(())
}
fn produce_late(_: &mut ProduceContext, _: ()) -> Result<Self, ProduceError> {
Ok(Self)
}
fn sealed_impl() -> sealed::SealedMarker {
sealed::SealedMarker
}
}
macro_rules! impl_r_d_tuple {
( $($g:literal),* ) => {
paste! {
impl<$( [< D $g >] , )*> ResourceDependencies for ($( [< D $g >] , )*)
where
$( [< D $g >] : ResourceDependency, )*
{
#[allow(unused_variables)]
fn register(cx: &mut RegisterContext) {
$( [< D $g >] ::register(cx); )*
}
#[allow(unused_variables)]
fn produce(cx: &mut ProduceContext) -> Result<Self, ProduceError> {
$( let [< dep_ $g >] = [< D $g >] ::produce_early(cx); )*
$( let [< dep_ $g >] = [< dep_ $g >] ?; )*
Ok((
$( [< D $g >] ::produce_late(cx, [< dep_ $g >] )?, )*
))
}
}
}
}
}
impl_r_d_tuple!();
impl_r_d_tuple!(0);
impl_r_d_tuple!(0, 1);
impl_r_d_tuple!(0, 1, 2);
impl_r_d_tuple!(0, 1, 2, 3);
impl_r_d_tuple!(0, 1, 2, 3, 4);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
impl_r_d_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);