use basenum::Primitive;
use super::vec::{ Vector2, Vector3, Vector4 };
macro_rules! def_swizzle2 {
(
{$($f1: ident, $field1: ident),+},
{$($f2: ident, {$($field2: ident),+}),+}
) => {
pub trait Swizzle2<T: Primitive> {
fn x(&self) -> T;
fn y(&self) -> T;
$(
#[inline(always)]
fn $f1(&self) -> T { self.$field1() }
)+
$(
#[inline(always)]
fn $f2(&self) -> Vector2<T> {
Vector2::new($(self.$field2()),+)
}
)+
}
}
}
macro_rules! gen_swizzle2 {
(
{$($fx: ident),+},
{$($fy: ident),+},
{
$({$($f2x: ident),+}, {$($f2y: ident),+}),+
}
) => {
def_swizzle2! {
{ $($fx, x),+, $($fy, y),+ },
{
$(
$(
concat_idents!($f2x, $f2y), { $f2x, $f2y }
),+
)+
}
}
}
}
gen_swizzle2! {
{ r, u },
{ g, v },
{
{ x, y }, { x, y },
{ r, g }, { r, g },
{ u, v }, { u, v }
}
}
macro_rules! def_swizzle3 {
() => {
pub trait Swizzle3<T: Primitive>: Swizzle2<T> {
fn z(&self) -> T;
}
}
}
macro_rules! def_swizzle4 {
() => {
pub trait Swizzle4<T: Primitive>: Swizzle3<T> {
fn w(&self) -> T;
}
}
}
def_swizzle3! {}
def_swizzle4! {}
macro_rules! impl_swizzle2 {
($($v: ident),+) => {
$(
impl<T: Primitive> Swizzle2<T> for $v<T> {
#[inline(always)]
fn x(&self) -> T { self.x }
#[inline(always)]
fn y(&self) -> T { self.y }
}
)+
}
}
macro_rules! impl_swizzle3 {
($($v: ident),+) => {
$(
impl<T: Primitive> Swizzle3<T> for $v<T> {
#[inline(always)]
fn z(&self) -> T { self.z }
}
)+
}
}
impl_swizzle2! { Vector2, Vector3, Vector4 }
impl_swizzle3! { Vector3, Vector4 }
impl<T: Primitive> Swizzle4<T> for Vector4<T> {
#[inline(always)]
fn w(&self) -> T { self.w }
}
#[cfg(test)]
mod test {
use vec::vec::*;
use super::*;
#[test]
fn test_swizzle2() {
let v = ivec4(1, 2, 3, 4);
assert_eq!(v.xy(), ivec2(1, 2));
assert_eq!(v.ww(), ivec2(4, 4));
assert_eq!(v.zy(), ivec2(3, 2));
assert_eq!(v.gb(), ivec2(2, 3));
assert_eq!(v.ts(), ivec2(4, 3));
assert_eq!(v.vv(), ivec2(2, 2));
assert_eq!(v.bb(), v.ss());
}
#[test]
fn test_swizzle3() {
let v = vec3(0., 1., 2.);
}
#[test]
fn test_swizzle4() {
let v = uvec4(0, 7, 5, 2);
}
}