diff --git a/docs/.configotron-whiteboard.autosave.xopp b/docs/.configotron-whiteboard.autosave.xopp deleted file mode 100644 index c81c7a9..0000000 Binary files a/docs/.configotron-whiteboard.autosave.xopp and /dev/null differ diff --git a/docs/configotron-whiteboard.xopp b/docs/configotron-whiteboard.xopp index 676f255..29556c8 100644 Binary files a/docs/configotron-whiteboard.xopp and b/docs/configotron-whiteboard.xopp differ diff --git a/src/configotron/fsm.rs b/src/configotron/fsm.rs deleted file mode 100644 index 435a8a4..0000000 --- a/src/configotron/fsm.rs +++ /dev/null @@ -1,502 +0,0 @@ -use graphviz_rust::{ - dot_structures::{Attribute, Edge, EdgeTy, Graph, Id, NodeId, Stmt, Vertex}, - exec, - printer::PrinterContext, -}; -use std::{cell::RefCell, rc::Rc}; - -#[derive(Debug, Clone)] -pub struct FSM { - name: String, - states: Vec>>, -} - -impl FSM { - pub fn new(state: Vec>>, name: &str) -> Self { - FSM { - states: state, - name: name.to_string(), - } - } - - fn render_stmts(&self) -> Vec { - let mut stmts: Vec = vec![Stmt::Attribute(Attribute( - Id::Plain("rankdir".to_string()), - Id::Plain("LR".to_string()), - ))]; - for s in &self.states { - let s_borrowed = s.borrow(); - - stmts.push(Stmt::Node(graphviz_rust::dot_structures::Node { - id: NodeId(Id::Plain(s_borrowed.to_graph_label()), None), - attributes: { - let mut res = vec![Attribute( - Id::Plain("label".to_string()), - Id::Plain(s_borrowed.to_graph_label()), - )]; - match s_borrowed.action { - FSMStateAction::NONE => { - res.push(Attribute( - Id::Plain("shape".to_string()), - Id::Plain("circle".to_string()), - )); - } - FSMStateAction::TERMINAL => { - res.push(Attribute( - Id::Plain("shape".to_string()), - Id::Plain("doublecircle".to_string()), - )); - } - } - res - }, - })); - - match &s_borrowed.transition { - None => {} - Some(t) => { - for (t, range) in t.to_targets_vec() { - match t.upgrade() { - None => {} - Some(target) => { - stmts.push(Stmt::Edge(Edge { - ty: EdgeTy::Pair( - Vertex::N(NodeId( - Id::Plain(s_borrowed.to_graph_label()), - None, - )), - Vertex::N(NodeId( - Id::Plain(target.borrow().to_graph_label()), - None, - )), - ), - attributes: vec![Attribute( - Id::Plain("label".to_string()), - Id::Plain(format!("\"{}\"", range.to_string())), - )], - })); - } - } - } - } - } - } - - stmts - } - - fn render_graph(&self, format: graphviz_rust::cmd::Format) -> Result, std::io::Error> { - let g = Graph::DiGraph { - id: Id::Plain("root".to_string()), - strict: false, - stmts: self.render_stmts(), - }; - - let mut ctx: graphviz_rust::printer::PrinterContext = PrinterContext::default(); - - println!("{}", graphviz_rust::print(g.clone(), &mut ctx)); - - let data = exec(g, &mut ctx, vec![format.into()])?; - - Ok(data) - } -} - -#[derive(Debug, Clone, Copy)] -pub enum FSMStateAction { - NONE, - TERMINAL, -} - -#[derive(Debug, Clone)] -pub struct FSMState { - name: String, - action: FSMStateAction, - transition: Option, -} - -impl FSMState { - pub fn new(name: String, action: FSMStateAction) -> Self { - FSMState { - name: name, - action: action, - transition: None, - } - } - - pub fn set_transitions(&mut self, t: tranisitions::FSMTranistion) { - self.transition = Some(t); - } - - pub fn to_graph_label(&self) -> String { - return format!("\"{}\"", self.name); - } - - pub fn to_graph_hash(&self) -> String { - self.to_graph_label() - } -} - -mod tranisitions { - use super::transition_masking::TransitionMask; - use super::FSMState; - use std::collections::HashMap; - use std::rc::Rc; - use std::{cell::RefCell, rc::Weak}; - - type StateRef = Weak>; - - #[derive(Debug, Clone)] - pub struct FSMTranistion { - array: [StateRef; 128], - } - - impl FSMTranistion { - pub fn new_from_mask(mask: TransitionMask, pos: StateRef, default: StateRef) -> Self { - let mut array: [StateRef; 128] = std::array::from_fn(|_| Weak::clone(&default)); - for i in 0..128 { - if mask.get_bit(i) { - array[i] = Weak::clone(&pos); - } - } - - FSMTranistion { array } - } - - pub fn new(default: StateRef) -> Self { - let array: [StateRef; 128] = std::array::from_fn(|_| Weak::clone(&default)); - - FSMTranistion { array } - } - - pub fn apply(&mut self, mask: TransitionMask, state: StateRef) { - for i in 0..128 { - if mask.get_bit(i) { - self.array[i] = Weak::clone(&state); - } - } - } - - pub fn to_targets_vec(&self) -> Vec<(StateRef, TransitionMask)> { - let mut target_maps: HashMap = HashMap::new(); - - self.array.iter().enumerate().for_each(|(index, target)| { - match target.upgrade() { - None => {} - Some(t) => { - let s_borrowd = t.borrow(); - let key = s_borrowd.to_graph_label(); - match target_maps.get_mut(&key) { - Some((_, mask)) => { - mask.set_bit(index); - } - None => { - let mut mask = TransitionMask::new(); - mask.set_bit(index); - target_maps.insert(key, (Rc::downgrade(&t), mask)); - } - }; - } - }; - }); - - let mut res: Vec<(StateRef, TransitionMask)> = Vec::new(); - - target_maps - .iter() - .for_each(|(_, (target, mask))| match target.upgrade() { - Some(t) => { - res.push((Rc::downgrade(&t), mask.clone())); - } - None => {} - }); - res - } - } -} - -mod transition_masking { - use itertools::Itertools; - use std::{ops::RangeInclusive, usize}; - - pub enum MaskPresets { - Char(char), - AnyCase, - LowerCase, - UpperCase, - AllHumanReadable, - Numbers, - SpecialChars, - WhiteSpace, - LineTermination, - NoChar, - } - - #[derive(Debug, Clone)] - pub struct TransitionMask { - mask: u128, - } - - impl From for TransitionMask { - fn from(value: MaskPresets) -> Self { - let mut n: u128 = 0; - - let mut set_range = |r: RangeInclusive| { - r.for_each(|i| n |= 1 << i); - }; - - match value { - MaskPresets::NoChar => {} - MaskPresets::AnyCase => { - set_range(0x41..=0x5a); // UpperCase - set_range(0x61..=0x7a); // LowerCase - } - MaskPresets::LowerCase => { - set_range(0x61..=0x7a); // LowerCase - } - MaskPresets::UpperCase => { - set_range(0x41..=0x5a); // UpperCase - } - MaskPresets::AllHumanReadable => { - set_range(0x20..=0x7e); // All Ascii Chars + Space + Tab - n |= 1 << 0x9; // Tab - } - MaskPresets::Numbers => { - set_range(0x30..=0x39); // Numbers - } - MaskPresets::SpecialChars => { - set_range(0x21..=0x2F); // ! to / - set_range(0x3A..=0x40); // : to @ - set_range(0x5B..=0x0D); // [ to ` - set_range(0x7B..=0x7E); // { to ~ - } - MaskPresets::WhiteSpace => { - n |= 1 << 0x9; // Tab - n |= 1 << 0x20; // Spaces - } - MaskPresets::LineTermination => { - n |= 1 << 0x0a; // Line Feed - n |= 1 << 0x0d; // Carriage Return - } - MaskPresets::Char(c) => { - if c.is_ascii() { - n |= 1 << (c as u32) - } - } - } - - TransitionMask { mask: n } - } - } - - impl TransitionMask { - pub fn new() -> Self { - TransitionMask { mask: 0 } - } - - pub fn or(&self, other: Self) -> TransitionMask { - TransitionMask { - mask: other.mask | self.mask, - } - } - - pub fn and(&self, other: Self) -> TransitionMask { - TransitionMask { - mask: other.mask & self.mask, - } - } - - pub fn inv(&self) -> TransitionMask { - TransitionMask { mask: !self.mask } - } - - pub fn get_bit(&self, i: usize) -> bool { - (self.mask & (1 << i)) > 0 - } - - pub fn set_bit(&mut self, i: usize) { - self.mask |= 1 << i; - } - - pub fn to_string(&self) -> String { - let mut res: Vec = Vec::new(); - let mut strike: Option = None; - - fn num_to_str(i: usize) -> String { - if (0x21..=0x7E).contains(&i) { - format!("'{}'", ((i as u8) as char).to_string()) - } else { - match i { - 0x20 => "SP".to_string(), - 0x0D => "LF".to_string(), - 0x0A => "CR".to_string(), - 0x09 => "TAB".to_string(), - _ => format!("{:02x}", i), - } - } - } - - for (p, n) in (0..128).tuple_windows() { - match (strike, self.get_bit(p), self.get_bit(n)) { - (None, true, true) => { - // First two - strike = Some(p); - } - (None, true, false) => { - // First, only one - res.push(num_to_str(p)); - } - (None, false, true) => { - // Strik Start - strike = Some(n) - } - (None, false, false) => { - // No Strike - } - (Some(_), true, true) => { - // Stike ongoing - } - (Some(s), true, false) => { - // Strik end - if s == p { - // Single Number - res.push(num_to_str(p)); - } else { - // Range - res.push(format!("{}-{}", num_to_str(s), num_to_str(p))); - } - - strike = None; - } - (Some(_), false, true) => { - // This should no happend - strike = Some(n); - } - (Some(_), false, false) => { - // Should also no happend - strike = None; - } - } - } - - match strike { - None => (), - Some(s) => { - if s == 127 { - res.push(num_to_str(s)); - } else { - res.push(format!("{}-{}", num_to_str(s), num_to_str(127))); - } - } - }; - - res.join(",") - } - } -} - -#[cfg(test)] -mod test { - use graphviz_rust::cmd::Format; - use std::io::Write; - - use super::{tranisitions::*, transition_masking::*, *}; - - #[test] - fn transition_mask_to_string() { - let mut mask1 = TransitionMask::new(); - - mask1.set_bit(0); - - (10..=16).for_each(|i| { - mask1.set_bit(i); - }); - - (50..=51).for_each(|i| { - mask1.set_bit(i); - }); - - mask1.set_bit(60); - mask1.set_bit(62); - mask1.set_bit(64); - - (70..=73).for_each(|i| { - mask1.set_bit(i); - }); - - (126..=127).for_each(|i| { - mask1.set_bit(i); - }); - - println!("{}", mask1.to_string()); - - assert_eq!( - mask1.to_string(), - "00,CR-10,'2'-'3','<','>','@','F'-'I','~'-7f" - ); - } - - #[test] - fn simple_fsm_render() { - let z0 = Rc::new(RefCell::new(FSMState::new( - "z0".to_string(), - FSMStateAction::NONE, - ))); - let z1 = Rc::new(RefCell::new(FSMState::new( - "z1".to_string(), - FSMStateAction::NONE, - ))); - let z2 = Rc::new(RefCell::new(FSMState::new( - "z2".to_string(), - FSMStateAction::TERMINAL, - ))); - let z3 = Rc::new(RefCell::new(FSMState::new( - "z3".to_string(), - FSMStateAction::NONE, - ))); - - let mut z0_transisions = FSMTranistion::new_from_mask( - TransitionMask::from(MaskPresets::Char('a')), - Rc::downgrade(&z1), - Rc::downgrade(&z3), - ); - z0_transisions.apply( - TransitionMask::from(MaskPresets::Char('b')), - Rc::downgrade(&z2), - ); - - let mut z1_transisions = FSMTranistion::new_from_mask( - TransitionMask::from(MaskPresets::Char('a')), - Rc::downgrade(&z1), - Rc::downgrade(&z3), - ); - z1_transisions.apply( - TransitionMask::from(MaskPresets::Char('b')), - Rc::downgrade(&z2), - ); - - let z2_transisions = FSMTranistion::new_from_mask( - TransitionMask::from(MaskPresets::Char('a')), - Rc::downgrade(&z2), - Rc::downgrade(&z3), - ); - - let z3_transisions = FSMTranistion::new(Rc::downgrade(&z3)); - - z0.borrow_mut().set_transitions(z0_transisions); - z1.borrow_mut().set_transitions(z1_transisions); - z2.borrow_mut().set_transitions(z2_transisions); - z3.borrow_mut().set_transitions(z3_transisions); - - let fsm = FSM::new(vec![z0, z1, z2, z3], "Test FSM #1"); - - let data = fsm.render_graph(Format::Svg).unwrap(); - - let mut output_file = std::fs::File::create("/tmp/debug-simle_fsm_building.svg").unwrap(); - output_file.write_all(&data).unwrap(); - - - let svg_content = std::fs::read_to_string("/tmp/debug-simle_fsm_building.svg").unwrap(); - assert_eq!(svg_content, String::from_utf8(data).unwrap()); - } -} diff --git a/src/configotron/fsm/masking.rs b/src/configotron/fsm/masking.rs new file mode 100644 index 0000000..8bf1711 --- /dev/null +++ b/src/configotron/fsm/masking.rs @@ -0,0 +1,218 @@ + +use itertools::Itertools; +use std::{ops::RangeInclusive, usize}; + +pub enum MaskPresets { + Char(char), + AnyCase, + LowerCase, + UpperCase, + AllHumanReadable, + Numbers, + SpecialChars, + WhiteSpace, + LineTermination, + NoChar, +} + +#[derive(Debug, Clone)] +pub struct TransitionMask { + mask: u128, +} + +impl From for TransitionMask { + fn from(value: MaskPresets) -> Self { + let mut n: u128 = 0; + + let mut set_range = |r: RangeInclusive| { + r.for_each(|i| n |= 1 << i); + }; + + match value { + MaskPresets::NoChar => {} + MaskPresets::AnyCase => { + set_range(0x41..=0x5a); // UpperCase + set_range(0x61..=0x7a); // LowerCase + } + MaskPresets::LowerCase => { + set_range(0x61..=0x7a); // LowerCase + } + MaskPresets::UpperCase => { + set_range(0x41..=0x5a); // UpperCase + } + MaskPresets::AllHumanReadable => { + set_range(0x20..=0x7e); // All Ascii Chars + Space + Tab + n |= 1 << 0x9; // Tab + } + MaskPresets::Numbers => { + set_range(0x30..=0x39); // Numbers + } + MaskPresets::SpecialChars => { + set_range(0x21..=0x2F); // ! to / + set_range(0x3A..=0x40); // : to @ + set_range(0x5B..=0x0D); // [ to ` + set_range(0x7B..=0x7E); // { to ~ + } + MaskPresets::WhiteSpace => { + n |= 1 << 0x9; // Tab + n |= 1 << 0x20; // Spaces + } + MaskPresets::LineTermination => { + n |= 1 << 0x0a; // Line Feed + n |= 1 << 0x0d; // Carriage Return + } + MaskPresets::Char(c) => { + if c.is_ascii() { + n |= 1 << (c as u32) + } + } + } + + TransitionMask { mask: n } + } +} + +impl TransitionMask { + pub fn new() -> Self { + TransitionMask { mask: 0 } + } + + pub fn or(&self, other: Self) -> TransitionMask { + TransitionMask { + mask: other.mask | self.mask, + } + } + + pub fn and(&self, other: Self) -> TransitionMask { + TransitionMask { + mask: other.mask & self.mask, + } + } + + pub fn inv(&self) -> TransitionMask { + TransitionMask { mask: !self.mask } + } + + pub fn get_bit(&self, i: usize) -> bool { + (self.mask & (1 << i)) > 0 + } + + pub fn set_bit(&mut self, i: usize) { + self.mask |= 1 << i; + } + + pub fn to_string(&self) -> String { + let mut res: Vec = Vec::new(); + let mut strike: Option = None; + + fn num_to_str(i: usize) -> String { + if (0x21..=0x7E).contains(&i) { + format!("'{}'", ((i as u8) as char).to_string()) + } else { + match i { + 0x20 => "SP".to_string(), + 0x0D => "LF".to_string(), + 0x0A => "CR".to_string(), + 0x09 => "TAB".to_string(), + _ => format!("{:02x}", i), + } + } + } + + for (p, n) in (0..128).tuple_windows() { + match (strike, self.get_bit(p), self.get_bit(n)) { + (None, true, true) => { + // First two + strike = Some(p); + } + (None, true, false) => { + // First, only one + res.push(num_to_str(p)); + } + (None, false, true) => { + // Strik Start + strike = Some(n) + } + (None, false, false) => { + // No Strike + } + (Some(_), true, true) => { + // Stike ongoing + } + (Some(s), true, false) => { + // Strik end + if s == p { + // Single Number + res.push(num_to_str(p)); + } else { + // Range + res.push(format!("{}-{}", num_to_str(s), num_to_str(p))); + } + + strike = None; + } + (Some(_), false, true) => { + // This should no happend + strike = Some(n); + } + (Some(_), false, false) => { + // Should also no happend + strike = None; + } + } + } + + match strike { + None => (), + Some(s) => { + if s == 127 { + res.push(num_to_str(s)); + } else { + res.push(format!("{}-{}", num_to_str(s), num_to_str(127))); + } + } + }; + + res.join(",") + } + } + + +mod test { + use super::TransitionMask; + + #[test] + fn transition_mask_to_string() { + let mut mask1 = TransitionMask::new(); + + mask1.set_bit(0); + + (10..=16).for_each(|i| { + mask1.set_bit(i); + }); + + (50..=51).for_each(|i| { + mask1.set_bit(i); + }); + + mask1.set_bit(60); + mask1.set_bit(62); + mask1.set_bit(64); + + (70..=73).for_each(|i| { + mask1.set_bit(i); + }); + + (126..=127).for_each(|i| { + mask1.set_bit(i); + }); + + println!("{}", mask1.to_string()); + + assert_eq!( + mask1.to_string(), + "00,CR-10,'2'-'3','<','>','@','F'-'I','~'-7f" + ); + } + +} \ No newline at end of file diff --git a/src/configotron/fsm/mod.rs b/src/configotron/fsm/mod.rs new file mode 100644 index 0000000..6065258 --- /dev/null +++ b/src/configotron/fsm/mod.rs @@ -0,0 +1,216 @@ +pub mod masking; +pub mod transition; + +use graphviz_rust::{ + dot_structures::{Attribute, Edge, EdgeTy, Graph, Id, NodeId, Stmt, Vertex}, + exec, + printer::PrinterContext, +}; +use transition::FSMTranistion; +use std::{cell::RefCell, rc::Rc}; + +#[derive(Debug, Clone)] +pub struct FSM { + name: String, + states: Vec>>, +} + +impl FSM { + pub fn new(state: Vec>>, name: &str) -> Self { + FSM { + states: state, + name: name.to_string(), + } + } + + fn render_stmts(&self) -> Vec { + let mut stmts: Vec = vec![Stmt::Attribute(Attribute( + Id::Plain("rankdir".to_string()), + Id::Plain("LR".to_string()), + ))]; + for s in &self.states { + let s_borrowed = s.borrow(); + + stmts.push(Stmt::Node(graphviz_rust::dot_structures::Node { + id: NodeId(Id::Plain(s_borrowed.to_graph_label()), None), + attributes: { + let mut res = vec![Attribute( + Id::Plain("label".to_string()), + Id::Plain(s_borrowed.to_graph_label()), + )]; + match s_borrowed.action { + FSMStateAction::NONE => { + res.push(Attribute( + Id::Plain("shape".to_string()), + Id::Plain("circle".to_string()), + )); + } + FSMStateAction::TERMINAL => { + res.push(Attribute( + Id::Plain("shape".to_string()), + Id::Plain("doublecircle".to_string()), + )); + } + } + res + }, + })); + + match &s_borrowed.transition { + None => {} + Some(t) => { + for (t, range) in t.to_targets_vec() { + match t.upgrade() { + None => {} + Some(target) => { + stmts.push(Stmt::Edge(Edge { + ty: EdgeTy::Pair( + Vertex::N(NodeId( + Id::Plain(s_borrowed.to_graph_label()), + None, + )), + Vertex::N(NodeId( + Id::Plain(target.borrow().to_graph_label()), + None, + )), + ), + attributes: vec![Attribute( + Id::Plain("label".to_string()), + Id::Plain(format!("\"{}\"", range.to_string())), + )], + })); + } + } + } + } + } + } + + stmts + } + + fn render_graph(&self, format: graphviz_rust::cmd::Format) -> Result, std::io::Error> { + let g = Graph::DiGraph { + id: Id::Plain("root".to_string()), + strict: false, + stmts: self.render_stmts(), + }; + + let mut ctx: graphviz_rust::printer::PrinterContext = PrinterContext::default(); + + println!("{}", graphviz_rust::print(g.clone(), &mut ctx)); + + let data = exec(g, &mut ctx, vec![format.into()])?; + + Ok(data) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum FSMStateAction { + NONE, + TERMINAL, +} + +#[derive(Debug, Clone)] +pub struct FSMState { + name: String, + action: FSMStateAction, + transition: Option, +} + +impl FSMState { + pub fn new(name: String, action: FSMStateAction) -> Self { + FSMState { + name: name, + action: action, + transition: None, + } + } + + pub fn set_transitions(&mut self, t: FSMTranistion) { + self.transition = Some(t); + } + + pub fn to_graph_label(&self) -> String { + return format!("\"{}\"", self.name); + } + + pub fn to_graph_hash(&self) -> String { + self.to_graph_label() + } +} + + +#[cfg(test)] +mod test { + use graphviz_rust::cmd::Format; + use std::{cell::RefCell, io::Write, rc::Rc}; + use super::{FSMState, FSMStateAction, FSM}; + use super::transition::FSMTranistion; + use super::masking::{MaskPresets, TransitionMask}; + + #[test] + fn simple_fsm_render() { + let z0 = Rc::new(RefCell::new(FSMState::new( + "z0".to_string(), + FSMStateAction::NONE, + ))); + let z1 = Rc::new(RefCell::new(FSMState::new( + "z1".to_string(), + FSMStateAction::NONE, + ))); + let z2 = Rc::new(RefCell::new(FSMState::new( + "z2".to_string(), + FSMStateAction::TERMINAL, + ))); + let z3 = Rc::new(RefCell::new(FSMState::new( + "z3".to_string(), + FSMStateAction::NONE, + ))); + + let mut z0_transisions = FSMTranistion::new_from_mask( + TransitionMask::from(MaskPresets::Char('a')), + Rc::downgrade(&z1), + Rc::downgrade(&z3), + ); + z0_transisions.apply( + TransitionMask::from(MaskPresets::Char('b')), + Rc::downgrade(&z2), + ); + + let mut z1_transisions = FSMTranistion::new_from_mask( + TransitionMask::from(MaskPresets::Char('a')), + Rc::downgrade(&z1), + Rc::downgrade(&z3), + ); + z1_transisions.apply( + TransitionMask::from(MaskPresets::Char('b')), + Rc::downgrade(&z2), + ); + + let z2_transisions = FSMTranistion::new_from_mask( + TransitionMask::from(MaskPresets::Char('a')), + Rc::downgrade(&z2), + Rc::downgrade(&z3), + ); + + let z3_transisions = FSMTranistion::new(Rc::downgrade(&z3)); + + z0.borrow_mut().set_transitions(z0_transisions); + z1.borrow_mut().set_transitions(z1_transisions); + z2.borrow_mut().set_transitions(z2_transisions); + z3.borrow_mut().set_transitions(z3_transisions); + + let fsm = FSM::new(vec![z0, z1, z2, z3], "Test FSM #1"); + + let data = fsm.render_graph(Format::Svg).unwrap(); + + let mut output_file = std::fs::File::create("/tmp/debug-simle_fsm_building.svg").unwrap(); + output_file.write_all(&data).unwrap(); + + + let svg_content = std::fs::read_to_string("/tmp/debug-simle_fsm_building.svg").unwrap(); + assert_eq!(svg_content, String::from_utf8(data).unwrap()); + } +} diff --git a/src/configotron/fsm/transition.rs b/src/configotron/fsm/transition.rs new file mode 100644 index 0000000..f07e020 --- /dev/null +++ b/src/configotron/fsm/transition.rs @@ -0,0 +1,76 @@ + +use super::masking::TransitionMask; +use super::FSMState; +use std::collections::HashMap; +use std::rc::Rc; +use std::{cell::RefCell, rc::Weak}; + +type StateRef = Weak>; + +#[derive(Debug, Clone)] +pub struct FSMTranistion { + array: [StateRef; 128], +} + +impl FSMTranistion { + pub fn new_from_mask(mask: TransitionMask, pos: StateRef, default: StateRef) -> Self { + let mut array: [StateRef; 128] = std::array::from_fn(|_| Weak::clone(&default)); + for i in 0..128 { + if mask.get_bit(i) { + array[i] = Weak::clone(&pos); + } + } + + FSMTranistion { array } + } + + pub fn new(default: StateRef) -> Self { + let array: [StateRef; 128] = std::array::from_fn(|_| Weak::clone(&default)); + + FSMTranistion { array } + } + + pub fn apply(&mut self, mask: TransitionMask, state: StateRef) { + for i in 0..128 { + if mask.get_bit(i) { + self.array[i] = Weak::clone(&state); + } + } + } + + pub fn to_targets_vec(&self) -> Vec<(StateRef, TransitionMask)> { + let mut target_maps: HashMap = HashMap::new(); + + self.array.iter().enumerate().for_each(|(index, target)| { + match target.upgrade() { + None => {} + Some(t) => { + let s_borrowd = t.borrow(); + let key = s_borrowd.to_graph_label(); + match target_maps.get_mut(&key) { + Some((_, mask)) => { + mask.set_bit(index); + } + None => { + let mut mask = TransitionMask::new(); + mask.set_bit(index); + target_maps.insert(key, (Rc::downgrade(&t), mask)); + } + }; + } + }; + }); + + let mut res: Vec<(StateRef, TransitionMask)> = Vec::new(); + + target_maps + .iter() + .for_each(|(_, (target, mask))| match target.upgrade() { + Some(t) => { + res.push((Rc::downgrade(&t), mask.clone())); + } + None => {} + }); + res + } +}