use dyn_any::DynAny; use std::any::Any; use std::future::Future; use std::pin::Pin; use std::sync::{Arc, OnceLock}; use crate::WgpuExecutor; pub type PipelineFuture<'a, T> = Pin + Send + 'a>>; pub trait Pipeline: Any + Send + Sync + Sized { type Args<'a>; type Out: Send; fn create(executor: &WgpuExecutor) -> Self; fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> PipelineFuture<'a, Self::Out>; } pub trait AsyncPipeline: Any + Send + Sync + Sized { type Args<'a>; type Out: Send; fn create(executor: &WgpuExecutor) -> Self; fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> impl Future + Send + 'a; } impl Pipeline for P { type Args<'a> =

::Args<'a>; type Out =

::Out; fn create(executor: &WgpuExecutor) -> Self {

::create(executor) } fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> PipelineFuture<'a, Self::Out> { Box::pin(

::run(self, executor, args)) } } #[derive(Default, Clone, DynAny)] pub struct PipelineCache { pipeline: Arc>>, executor: Arc>, } impl PipelineCache { pub(super) fn init(&self, executor: &WgpuExecutor) { self.executor.get_or_init(|| executor.clone()); self.pipeline.get_or_init(|| Box::new(P::create(executor))); } pub async fn run(&self, args: &P::Args<'_>) -> P::Out { let executor = self.executor.get().expect("PipelineCache not initialized"); let entry = self.pipeline.get().expect("PipelineCache not initialized"); let pipeline = (&**entry) .downcast_ref::

() .unwrap_or_else(|| panic!("PipelineCache type mismatch: run::<{}>() but init used a different pipeline type", std::any::type_name::

(),)); pipeline.run(executor, args).await } } impl std::fmt::Debug for PipelineCache { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("PipelineCache").field("initialized", &self.pipeline.get().is_some()).finish() } }