use std::collections::{HashMap};
use std::fmt::{Debug};
use super::{Switch, Node};
enum CaseAdapter<C> {
Hot,
Cold(C),
}
impl<C: Debug> Debug for CaseAdapter<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
if let CaseAdapter::Cold(ref c) = self {
c.fmt(f)
} else {
f.write_str("(hot path)")
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Cold<C> {
pub hot_index: usize,
pub colds: Box<[C]>,
}
impl<C> Cold<C> {
pub fn new(switch: Switch<C>, hot_index: usize) -> (C, Self) {
let Switch {cases, default_} = switch;
let mut cases = cases.into_vec();
let hot = if hot_index == usize::MAX {
*default_
} else {
let hot = cases.remove(hot_index);
cases.push(*default_);
hot
};
let colds = cases.into_boxed_slice();
(hot, Cold {hot_index, colds})
}
pub fn map<'a, D>(&'a self, mut callback: impl FnMut(&'a C) -> D) -> Cold<D> {
let Cold {hot_index, ref colds} = *self;
let colds = colds.iter().map(&mut callback).collect();
Cold {hot_index, colds}
}
pub fn finish(self, hot: C) -> Switch<C> {
let Cold {hot_index, colds} = self;
let mut colds: Vec<C> = colds.into_vec();
let default_ = Box::new(if hot_index == usize::MAX {
hot
} else {
let default_ = colds.pop().unwrap();
colds.insert(hot_index, hot);
default_
});
let cases = colds.into_boxed_slice();
Switch {cases, default_}
}
pub fn debug(&self) -> Switch<impl '_ + Debug> where C: Debug {
self.map(CaseAdapter::Cold).finish(CaseAdapter::Hot)
}
}
impl<C: Debug> Debug for Cold<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let switch = self.debug();
f.debug_struct("Cold")
.field("cases", &switch.cases)
.field("default_", &switch.default_)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct Exit {
pub sequence: Node,
pub outputs: Box<[Node]>,
}
#[derive(Debug, Clone)]
pub enum CFT<L: Clone> {
Merge {
exit: Exit,
leaf: L,
},
Switch {
guard: Node,
switch: Switch<CFT<L>>,
hot_index: usize,
},
}
impl<L: Clone> CFT<L> {
pub fn switch(
guard: Node,
cases: impl Into<Box<[CFT<L>]>>,
default_: impl Into<Box<CFT<L>>>,
hot_index: usize,
) -> Self {
let switch = Switch {cases: cases.into(), default_: default_.into()};
CFT::Switch {guard, switch, hot_index}
}
pub fn exits(&self) -> impl '_ + Iterator<Item=&'_ Exit> {
ExitIter(vec![self])
}
pub fn hot_path(&self) -> (HashMap<Node, Cold<&Self>>, &Exit, L) {
let mut cft = self;
let mut colds = HashMap::new();
loop {
match *cft {
CFT::Merge {ref exit, ref leaf} => {
return (colds, exit, leaf.clone());
},
CFT::Switch {guard, ref switch, hot_index} => {
let (hot, cold) = Cold::new(switch.map(|t| t), hot_index);
cft = hot;
colds.insert(guard, cold);
},
}
}
}
}
struct ExitIter<'a, L: Clone>(Vec<&'a CFT<L>>);
impl<'a, L: Clone> Iterator for ExitIter<'a, L> {
type Item = &'a Exit;
fn next(&mut self) -> Option<Self::Item> {
while let Some(cft) = self.0.pop() {
match *cft {
CFT::Merge {ref exit, leaf: _} => {
return Some(exit);
},
CFT::Switch {guard: _, ref switch, hot_index: _} => {
let _ = switch.map(|child| self.0.push(child));
},
}
}
None
}
}