#![allow(clippy::useless_conversion)]
use batch_impl::batch_impl;
#[batch_impl(
()^1..=4 where{@all_fresh: Magma} impl{(A@..,)}
#combine{( @(@A::combine(&self.@0, &rhs.@0),).. )}
)]
trait Magma {
fn combine(&self, rhs: &Self) -> Self;
}
impl Magma for u8 {
fn combine(&self, rhs: &Self) -> Self {
*self + *rhs
}
}
impl Magma for u16 {
fn combine(&self, rhs: &Self) -> Self {
*self + *rhs
}
}
impl Magma for u32 {
fn combine(&self, rhs: &Self) -> Self {
*self + *rhs
}
}
#[test]
fn tuple_magma_combine_all_arities() {
assert_eq!((1u8,).combine(&(10u8,)), (11u8,));
assert_eq!((1u8, 2u16).combine(&(10u8, 20u16)), (11u8, 22u16));
assert_eq!((1u8, 2u16, 3u32).combine(&(10u8, 20u16, 30u32)), (11u8, 22u16, 33u32));
assert_eq!(
(1u8, 2u16, 3u32, 4u32).combine(&(10u8, 20u16, 30u32, 40u32)),
(11u8, 22u16, 33u32, 44u32)
);
}
#[batch_impl((u8, u16, u32) impl{(u8, A@..,)} { fn tail(&self) -> (u16, u32) { (@(@A::from(self.@1),)..) } })]
trait ShapeTail {
fn tail(&self) -> (u16, u32);
}
#[test]
fn offset_start_segment() {
let t = (1u8, 2u16, 3u32);
assert_eq!(t.tail(), (2u16, 3u32));
}
#[batch_impl(((u8, u16), (u32,)) impl{((A@..,),(B@..,))} { fn flat(&self) -> (u8, u16, u32) { (@(@A::from(self.0.@0),).. @(@B::from(self.1.@0),)..) } })]
trait ShapeFlat {
fn flat(&self) -> (u8, u16, u32);
}
#[test]
fn nested_segments() {
let t = ((1u8, 2u16), (3u32,));
assert_eq!(t.flat(), (1u8, 2u16, 3u32));
}
#[batch_impl((u8, u16, u32, u32) impl{(A@.., B@..,)} { fn pairs(&self) -> (u64, u64) { (@(@A::from(self.@0) as u64 + @B::from(self.@2) as u64,)..) } })]
trait ShapePairs {
fn pairs(&self) -> (u64, u64);
}
#[test]
fn multi_segment_parallel_rounds() {
let t = (1u8, 2u16, 3u32, 4u32);
assert_eq!(t.pairs(), (4, 6));
}
#[batch_impl((u8,) impl{(A@..,)} { fn get(&self) -> A0 { self.0 } })]
trait ShapeOne {
fn get(&self) -> u8;
}
#[test]
fn single_element_segment_direct_name() {
assert_eq!((7u8,).get(), 7);
}
#[batch_impl(
Module<(), ()> ()^1..=4 where{
@all_fresh: Module<(), (), Scalar: Copy>,
@1..: Module<(), (), Scalar = @0::Scalar>,
} impl{(A@..,)}
#Scalar{A0::Scalar}
#scale{( @(@A::scale(&self.@0, s),).. )}
)]
trait Module<Add, Mul> {
type Scalar;
fn scale(&self, s: Self::Scalar) -> Self;
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct S<T>(T);
impl<T: Copy + std::ops::Mul<Output = T>> Module<(), ()> for S<T> {
type Scalar = T;
fn scale(&self, s: T) -> Self {
S(self.0 * s)
}
}
#[test]
fn tuple_module_shared_scalar() {
assert_eq!((S(2u8),).scale(4u8), (S(8u8),));
assert_eq!((S(2u8), S(3u8)).scale(4u8), (S(8u8), S(12u8)));
assert_eq!((S(2u8), S(3u8), S(4u8)).scale(4u8), (S(8u8), S(12u8), S(16u8)));
}
#[batch_impl((u8, u16, u32) impl{(A@..,)} { fn elems(&self) -> (u8, u16, u32) { (@(self.@0,)..) } })]
trait ShapeElems {
fn elems(&self) -> (u8, u16, u32);
}
#[batch_impl((u8, u16, u32) impl{(A@..,)} { fn elems2(&self) -> (u8, u16, u32) { (@A(self.@0,)..) } })]
trait ShapeElemsDeclared {
fn elems2(&self) -> (u8, u16, u32);
}
#[test]
fn cursor_only_blocks() {
let t = (1u8, 2u16, 3u32);
assert_eq!(t.elems(), (1u8, 2u16, 3u32));
assert_eq!(t.elems2(), (1u8, 2u16, 3u32));
}