use std::fmt::Debug;
use std::hash::{Hash,Hasher};
use std::collections::HashMap;
use adapton::engine::Name;
pub trait RazMeta<E>: Sized+Debug+Clone+Eq+Hash {
type Index: FirstLast;
fn from_none(lev: u32, n: Option<Name>) -> Self;
fn from_vec(vec: &Vec<E>, lev: u32, n: Option<Name>) -> Self;
fn from_meta(l: &Self, r: &Self, lev: u32, n: Option<Name>) -> Self;
fn navigate(l: &Self, r: &Self, index: &Self::Index) -> Navigation<Self::Index>;
fn split_vec<'a>(vec: &'a Vec<E>, index: &Self::Index) -> (&'a [E],&'a [E]);
}
pub enum Navigation<I> {
Left(I), Right(I), Here, Nowhere
}
pub trait FirstLast {
fn first() -> Self;
fn last() -> Self;
}
#[derive(Debug,Clone,Eq,PartialEq,Hash)]
pub enum Position<I> {
Left, Right, Center(I)
}
impl<I> FirstLast for Position<I> {
fn first() -> Self {Position::Left}
fn last() -> Self {Position::Right}
}
impl<I> From<I> for Position<I> {
fn from(index: I) -> Self { Position::Center(index) }
}
impl<E> RazMeta<E> for () {
type Index = Position<()>;
fn from_none(_lev: u32, _n: Option<Name>) -> Self { () }
fn from_vec(_vec: &Vec<E>, _lev: u32, _n: Option<Name>) -> Self { () }
fn from_meta(_l: &Self, _r: &Self, _lev: u32, _n: Option<Name>) -> Self { () }
fn navigate(_l: &Self, _r: &Self, index: &Self::Index) -> Navigation<Self::Index> {
match *index {
Position::Left => Navigation::Left(Position::Left),
Position::Right => Navigation::Right(Position::Right),
_ => panic!("Invalid position"),
}
}
fn split_vec<'a>(vec: &'a Vec<E>, index: &Self::Index) -> (&'a [E],&'a [E]) {
match *index {
Position::Left => vec.split_at(0),
Position::Right => vec.split_at(vec.len()),
_ => panic!("Invalid position"),
}
}
}
#[derive(Clone,Eq,PartialEq,Hash,Debug)]
pub struct Count(pub usize);
impl<E> RazMeta<E> for Count {
type Index = usize;
fn from_none(_lev: u32, _n: Option<Name>) -> Self { Count(0) }
fn from_vec(vec: &Vec<E>, _lev: u32, _n: Option<Name>) -> Self {
Count(vec.len())
}
fn from_meta(&Count(l): &Self, &Count(r): &Self, _l: u32, _n: Option<Name>) -> Self {
Count(l+r)
}
fn navigate(
&Count(l): &Self,
&Count(r): &Self,
index: &Self::Index
) -> Navigation<Self::Index> {
let i = *index;
if i == usize::max_value() { Navigation::Right(i) }
else if i > l + r { Navigation::Nowhere }
else if i > l { Navigation::Right(i - l) }
else if i == l { Navigation::Here }
else { Navigation::Left(i) }
}
fn split_vec<'a>(vec: &'a Vec<E>, index: &Self::Index) -> (&'a [E],&'a [E]) {
if *index == usize::max_value() {
vec.split_at(vec.len())
} else {
vec.split_at(*index)
}
}
}
impl FirstLast for usize {
fn first() -> Self { 0 }
fn last() -> Self { usize::max_value() }
}
#[derive(Clone,Eq,PartialEq,Debug)]
pub struct Names(pub HashMap<Name,()>);
impl Hash for Names {
fn hash<H:Hasher>(&self, _state: &mut H) {}
}
impl<E> RazMeta<E> for Names {
type Index = Position<Name>;
fn from_none(_lev: u32, n: Option<Name>) -> Self {
let mut h = HashMap::new();
match n {None=>{},Some(nm)=>{ h.insert(nm,()); }}
Names(h)
}
fn from_vec(_vec: &Vec<E>, _lev: u32, n: Option<Name>) -> Self {
let mut h = HashMap::new();
match n {None=>{},Some(nm)=>{ h.insert(nm,()); }}
Names(h)
}
fn from_meta(l: &Self, r: &Self, _lev: u32, n: Option<Name>) -> Self {
let mut h = HashMap::new();
for k in l.0.keys() { h.insert(k.clone(),()); }
for k in r.0.keys() { h.insert(k.clone(),()); }
match n {None=>{},Some(nm)=>{ h.insert(nm,()); }}
Names(h)
}
fn navigate(l: &Self, r: &Self, index: &Self::Index) -> Navigation<Self::Index> {
match *index {
Position::Left => Navigation::Left(Position::Left),
Position::Right => Navigation::Right(Position::Right),
Position::Center(ref nm) => {
match (l.0.contains_key(nm),r.0.contains_key(nm)) {
(true,true) => Navigation::Here,
(true,false) => Navigation::Left(index.clone()),
(false,true) => Navigation::Right(index.clone()),
(false,false) => Navigation::Nowhere,
}
}
}
}
fn split_vec<'a>(vec: &'a Vec<E>, index: &Self::Index) -> (&'a [E],&'a [E]) {
match *index {
Position::Left => vec.split_at(0),
Position::Right => vec.split_at(vec.len()),
_ => panic!("There are no names in this region")
}
}
}