use crate::number::Num;
use std::cmp::Ordering;
use std::fmt;
#[derive(Clone)]
pub enum Area {
Val {
type_: u8,
left: Box<Area>,
right: Box<Area>,
},
Nil,
}
impl Area {
pub fn new(type_: u8) -> Area {
Area::Val {
type_,
left: Box::new(Area::Nil),
right: Box::new(Area::Nil),
}
}
}
pub fn calc<T>(area: &Area, area_value: usize, mut pop: T) -> Option<u8>
where
T: FnMut() -> Option<Num>,
{
let mut area = area;
loop {
match area {
Area::Val { type_, left, right } => {
if *type_ == 0 {
let v = pop();
area = match match v {
Some(value) => value,
None => return Option::None,
}
.partial_cmp(&Num::from_num(area_value as isize))
{
Some(Ordering::Less) => left,
_ => right,
}
} else if *type_ == 1 {
let v = pop();
area = match match v {
Some(value) => value,
None => return Option::None,
}
.partial_cmp(&Num::from_num(area_value as isize))
{
Some(Ordering::Equal) => left,
_ => right,
}
} else {
break Option::Some(*type_);
}
}
Area::Nil => {
break Option::Some(0);
}
}
}
}
pub fn area_to_string_debug(s: &mut String, area: &Area) {
match area {
Area::Val {
ref type_,
ref left,
ref right,
} => {
let c = "?!♥❤💕💖💗💘💙💚💛💜💝♡".chars().collect::<Vec<char>>()[*type_ as usize];
s.push(c);
if *type_ <= 1 {
area_to_string_debug(s, left);
area_to_string_debug(s, right);
}
}
Area::Nil => {
s.push('_');
}
}
}
impl fmt::Debug for Area {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::new();
area_to_string_debug(&mut s, self);
write!(f, "{}", s)
}
}
pub fn area_to_string_display(s: &mut String, area: &Area) {
match area {
Area::Val {
ref type_,
ref left,
ref right,
} => {
let c = "?!♥❤💕💖💗💘💙💚💛💜💝♡".chars().collect::<Vec<char>>()[*type_ as usize];
if *type_ <= 1 {
s.push('[');
area_to_string_display(s, left);
s.push(']');
s.push(c);
s.push('[');
area_to_string_display(s, right);
s.push(']');
} else {
s.push(c);
}
}
Area::Nil => {
s.push('_');
}
}
}
impl fmt::Display for Area {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::new();
area_to_string_display(&mut s, self);
write!(f, "{}", s)
}
}