use smallvec::SmallVec;
use variadics_please::all_tuples;
use crate::{
Accessing, AddOperation, Buffer, BufferSettings, Buffering, Builder, Chain, CloneFromBuffer,
Join, Joining, Output, UnusedTarget,
};
pub type BufferKeys<B> = <<B as Bufferable>::BufferType as Accessing>::Key;
pub type JoinedItem<B> = <<B as Bufferable>::BufferType as Joining>::Item;
pub trait Bufferable {
type BufferType: Buffering;
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType;
}
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
}
}
pub trait Joinable: Bufferable {
type Item: 'static + Send + Sync;
fn join<'w, 's, 'a, 'b>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, Self::Item>;
}
impl<B> Joinable for B
where
B: Bufferable,
B::BufferType: Joining,
{
type Item = JoinedItem<B>;
fn join<'w, 's, 'a, 'b>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, Self::Item> {
self.into_buffer(builder).join(builder)
}
}
pub trait Accessible: Bufferable {
type Keys: 'static + Send + Sync;
fn listen<'w, 's, 'a, 'b>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, Self::Keys>;
}
impl<B> Accessible for B
where
B: Bufferable,
B::BufferType: Accessing,
{
type Keys = BufferKeys<Self>;
fn listen<'w, 's, 'a, 'b>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, Self::Keys> {
self.into_buffer(builder).listen(builder)
}
}
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))
}
}
impl<T: Bufferable> Bufferable for Vec<T> {
type BufferType = Vec<T::BufferType>;
fn into_buffer(self, builder: &mut Builder) -> Self::BufferType {
self.into_iter().map(|b| b.into_buffer(builder)).collect()
}
}
pub trait IterBufferable {
type BufferElement: Buffering + Joining;
fn into_buffer_vec<const N: usize>(
self,
builder: &mut Builder,
) -> SmallVec<[Self::BufferElement; N]>;
fn join_vec<'w, 's, 'a, 'b, const N: usize>(
self,
builder: &'b mut Builder<'w, 's, 'a>,
) -> Chain<'w, 's, 'a, 'b, SmallVec<[<Self::BufferElement as Joining>::Item; N]>>
where
Self: Sized,
Self::BufferElement: 'static + Send + Sync,
<Self::BufferElement as Joining>::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.queue(AddOperation::new(
Some(builder.scope()),
join,
Join::new(buffers, target),
));
Output::new(builder.scope(), target).chain(builder)
}
}
impl<T> IterBufferable for T
where
T: IntoIterator,
T::Item: Bufferable,
<T::Item as Bufferable>::BufferType: Joining,
{
type BufferElement = <T::Item as Bufferable>::BufferType;
fn into_buffer_vec<const N: usize>(
self,
builder: &mut Builder,
) -> SmallVec<[Self::BufferElement; N]> {
SmallVec::<[Self::BufferElement; N]>::from_iter(
self.into_iter().map(|e| e.into_buffer(builder)),
)
}
}