use super::{AnimatedJoin, AnimationDomain, Render, RenderTarget};
macro_rules! impl_join_for_collections {
($(($n:tt, $type:ident)),+) => {
impl<$($type: crate::render::AnimatedJoin),+> crate::render::AnimatedJoin for ($($type),+) {
fn join_from(
&mut self,
source: &Self,
domain: &crate::render::AnimationDomain
) {
$(
self.$n.join_from(
&source.$n,
domain
);
)+
}
}
};
}
#[rustfmt::skip]
mod impl_join {
impl_join_for_collections!((0, T0), (1, T1));
impl_join_for_collections!((0, T0), (1, T1), (2, T2));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7), (8, T8));
impl_join_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7), (8, T8), (9, T9));
}
impl<T: AnimatedJoin, const N: usize> AnimatedJoin for heapless::Vec<T, N> {
fn join_from(&mut self, source: &Self, domain: &AnimationDomain) {
self.iter_mut().zip(source).for_each(|(target, source)| {
target.join_from(source, domain);
});
}
}
macro_rules! impl_render_for_collections {
($(($n:tt, $type:ident)),+) => {
impl<Color, $($type: crate::render::Render<Color> ),+> crate::render::Render<Color> for ($($type),+) {
fn render(
&self,
target: &mut impl crate::render_target::RenderTarget<ColorFormat = Color>,
style: &Color,
) {
$(
self.$n.render(target, style);
)+
}
fn render_animated(
render_target: &mut impl crate::render_target::RenderTarget<ColorFormat = Color>,
source: &Self,
target: &Self,
style: &Color,
domain: &crate::render::AnimationDomain,
) {
$(
$type::render_animated(
render_target,
&source.$n,
&target.$n,
style,
domain,
);
)+
}
}
};
}
#[rustfmt::skip]
mod impl_render {
impl_render_for_collections!((0, T0), (1, T1));
impl_render_for_collections!((0, T0), (1, T1), (2, T2));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7), (8, T8));
impl_render_for_collections!((0, T0), (1, T1), (2, T2), (3, T3), (4, T4), (5, T5), (6, T6), (7, T7), (8, T8), (9, T9));
}
impl<Color, T: Render<Color>, const N: usize> Render<Color> for heapless::Vec<T, N> {
fn render(&self, render_target: &mut impl RenderTarget<ColorFormat = Color>, style: &Color) {
self.iter()
.for_each(|item| item.render(render_target, style));
}
fn render_animated(
render_target: &mut impl RenderTarget<ColorFormat = Color>,
source: &Self,
target: &Self,
style: &Color,
domain: &AnimationDomain,
) {
source
.iter()
.zip(target.iter())
.for_each(|(source, target)| {
T::render_animated(render_target, source, target, style, domain);
});
}
}
#[cfg(test)]
mod render_order_tests {
use crate::render::{AnimationDomain, Render};
use std;
use std::vec;
use std::{cell::RefCell, rc::Rc, vec::Vec};
#[derive(Debug, Clone)]
struct OrderTracker {
order: Rc<RefCell<Vec<usize>>>,
id: usize,
}
impl OrderTracker {
fn new(id: usize, order: Rc<RefCell<Vec<usize>>>) -> Self {
Self { order, id }
}
}
impl super::AnimatedJoin for OrderTracker {
fn join_from(&mut self, _source: &Self, _domain: &AnimationDomain) {}
}
impl Render<char> for OrderTracker {
fn render(
&self,
_render_target: &mut impl crate::render_target::RenderTarget<ColorFormat = char>,
_style: &char,
) {
self.order.borrow_mut().push(self.id);
}
fn render_animated(
_render_target: &mut impl crate::render_target::RenderTarget<ColorFormat = char>,
source: &Self,
target: &Self,
_style: &char,
_domain: &AnimationDomain,
) {
source.order.borrow_mut().push(source.id);
target.order.borrow_mut().push(target.id);
}
}
macro_rules! test_tuple_render_order {
($($n:tt),+) => {
paste::paste! {
#[test]
fn [<tuple_render_order_$($n)*>]() {
let order = Rc::new(RefCell::new(Vec::new()));
let tuple = (
$(
OrderTracker::new($n, order.clone()),
)+
);
let mut mock_target = crate::render_target::FixedTextBuffer::<10, 10>::default();
tuple.render(&mut mock_target, &'x');
let expected_order: Vec<usize> = vec![$($n),+];
assert_eq!(*order.borrow(), expected_order);
}
#[test]
fn [<tuple_animated_render_order_$($n)*>]() {
let order = Rc::new(RefCell::new(Vec::new()));
let mut mock_target = crate::render_target::FixedTextBuffer::<10, 10>::default();
let source_tuple = (
$(
OrderTracker::new($n, order.clone()),
)+
);
let target_tuple = (
$(
OrderTracker::new($n + 100, order.clone()),
)+
);
let domain = AnimationDomain::new(128, std::time::Duration::from_secs(1));
Render::render_animated(
&mut mock_target,
&source_tuple,
&target_tuple,
&'x',
&domain,
);
let expected_order: Vec<usize> = vec![$($n, $n + 100),+];
assert_eq!(*order.borrow(), expected_order);
}
}
};
}
test_tuple_render_order!(0, 1);
test_tuple_render_order!(0, 1, 2);
test_tuple_render_order!(0, 1, 2, 3);
test_tuple_render_order!(0, 1, 2, 3, 4);
test_tuple_render_order!(0, 1, 2, 3, 4, 5);
test_tuple_render_order!(0, 1, 2, 3, 4, 5, 6);
test_tuple_render_order!(0, 1, 2, 3, 4, 5, 6, 7);
test_tuple_render_order!(0, 1, 2, 3, 4, 5, 6, 7, 8);
test_tuple_render_order!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
}