use bevy_utils::all_tuples;
use smallvec::SmallVec;
use crate::{
AddOperation, Buffer, BufferSettings, Buffered, Builder, Chain, CleanupWorkflowConditions,
CloneFromBuffer, Join, Listen, Output, Scope, ScopeSettings, UnusedTarget,
};
pub type BufferKeys<B> = <<B as Bufferable>::BufferType as Buffered>::Key;
pub type BufferItem<B> = <<B as Bufferable>::BufferType as Buffered>::Item;
pub trait Bufferable {
type BufferType: Buffered;
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType;
fn join<'w, 's, 'a, 'b>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, BufferItem<Self>>
where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
BufferItem<Self>: 'static + Send + Sync,
{
let scope = builder.scope();
let buffers = self.into_buffer(builder);
buffers.verify_scope(scope);
let join = builder.commands.spawn(()).id();
let target = builder.commands.spawn(UnusedTarget).id();
builder.commands.add(AddOperation::new(
Some(scope),
join,
Join::new(buffers, target),
));
Output::new(scope, target).chain(builder)
}
fn listen<'w, 's, 'a, 'b>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, BufferKeys<Self>>
where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
BufferKeys<Self>: 'static + Send + Sync,
{
let scope = builder.scope();
let buffers = self.into_buffer(builder);
buffers.verify_scope(scope);
let listen = builder.commands.spawn(()).id();
let target = builder.commands.spawn(UnusedTarget).id();
builder.commands.add(AddOperation::new(
Some(scope),
listen,
Listen::new(buffers, target),
));
Output::new(scope, target).chain(builder)
}
fn on_cleanup<Settings>(
self,
builder: &mut Builder,
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
) where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
BufferKeys<Self>: 'static + Send + Sync,
Settings: Into<ScopeSettings>,
{
builder.on_cleanup(self, build)
}
fn on_cancel<Settings>(
self,
builder: &mut Builder,
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
) where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
BufferKeys<Self>: 'static + Send + Sync,
Settings: Into<ScopeSettings>,
{
builder.on_cancel(self, build)
}
fn on_terminate<Settings>(
self,
builder: &mut Builder,
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
) where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
BufferKeys<Self>: 'static + Send + Sync,
Settings: Into<ScopeSettings>,
{
builder.on_terminate(self, build)
}
fn on_cleanup_if<Settings>(
self,
builder: &mut Builder,
conditions: CleanupWorkflowConditions,
build: impl FnOnce(Scope<BufferKeys<Self>, (), ()>, &mut Builder) -> Settings,
) where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
BufferKeys<Self>: 'static + Send + Sync,
Settings: Into<ScopeSettings>,
{
builder.on_cleanup_if(conditions, self, build)
}
}
impl<T: 'static + Send + Sync> Bufferable for Buffer<T> {
type BufferType = Self;
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType {
assert_eq!(self.scope, builder.scope());
self
}
}
impl<T: 'static + Send + Sync + Clone> Bufferable for CloneFromBuffer<T> {
type BufferType = Self;
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType {
assert_eq!(self.scope, builder.scope());
self
}
}
impl<T: 'static + Send + Sync> Bufferable for Output<T> {
type BufferType = Buffer<T>;
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType {
assert_eq!(self.scope(), builder.scope());
let buffer = builder.create_buffer::<T>(BufferSettings::default());
builder.connect(self, buffer.input_slot());
buffer
}
}
macro_rules! impl_bufferable_for_tuple {
($($T:ident),*) => {
#[allow(non_snake_case)]
impl<$($T: Bufferable),*> Bufferable for ($($T,)*)
{
type BufferType = ($($T::BufferType,)*);
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType {
let ($($T,)*) = self;
($(
$T.into_buffer(builder),
)*)
}
}
}
}
all_tuples!(impl_bufferable_for_tuple, 2, 12, T);
impl<T: Bufferable, const N: usize> Bufferable for [T; N] {
type BufferType = [T::BufferType; N];
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType {
self.map(|b| b.into_buffer(builder))
}
}
pub trait IterBufferable {
type BufferType: Buffered;
fn into_buffer_vec<const N: usize>(
self,
builder: &mut Builder,
) -> SmallVec<[Self::BufferType; N]>;
fn join_vec<const N: usize>(
self,
builder: &mut Builder,
) -> Output<SmallVec<[<Self::BufferType as Buffered>::Item; N]>>
where
Self: Sized,
Self::BufferType: 'static + Send + Sync,
<Self::BufferType as Buffered>::Item: 'static + Send + Sync,
{
let buffers = self.into_buffer_vec::<N>(builder);
let join = builder.commands.spawn(()).id();
let target = builder.commands.spawn(UnusedTarget).id();
builder.commands.add(AddOperation::new(
Some(builder.scope()),
join,
Join::new(buffers, target),
));
Output::new(builder.scope, target)
}
}