use std::marker::PhantomData;
use std::ops::{Add, Sub};
use crate::Construct;
use crate::space::Space;
pub struct Either<T, U>(PhantomData<T>, PhantomData<U>);
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Select<T, U> {
Fst(T),
Snd(U),
}
impl<T, U> Construct for Either<T, U> {
fn new() -> Self { Either(PhantomData, PhantomData) }
}
impl<T, U, N> Space<N> for Either<T, U>
where T: Space<N>,
U: Space<N>,
N: Add<Output = N> +
Sub<Output = N> +
PartialOrd,
{
type Dim = (T::Dim, U::Dim);
type Pos = Select<T::Pos, U::Pos>;
fn count(&self, &(ref dim_t, ref dim_u): &Self::Dim) -> N {
let t: T = Construct::new();
let u: U = Construct::new();
t.count(dim_t) + u.count(dim_u)
}
fn zero(&self, &(ref dim_t, _): &Self::Dim) -> Self::Pos {
let t: T = Construct::new();
Select::Fst(t.zero(dim_t))
}
fn to_index(
&self,
&(ref dim_t, ref dim_u): &Self::Dim,
s: &Self::Pos
) -> N {
let t: T = Construct::new();
let u: U = Construct::new();
match *s {
Select::Fst(ref pt) => {
t.to_index(dim_t, pt)
}
Select::Snd(ref pu) => {
let count = t.count(dim_t);
count + u.to_index(dim_u, pu)
}
}
}
fn to_pos(
&self,
&(ref dim_t, ref dim_u): &Self::Dim,
ind: N,
pos: &mut Self::Pos,
) {
let t: T = Construct::new();
let u: U = Construct::new();
let count = t.count(dim_t);
if ind < count {
let mut zero = t.zero(dim_t);
t.to_pos(dim_t, ind, &mut zero);
*pos = Select::Fst(zero)
} else {
let mut zero = u.zero(dim_u);
u.to_pos(dim_u, ind - count, &mut zero);
*pos = Select::Snd(zero)
}
}
}