use super::*;
use crate::sequence::renderer::RenderDisplay;
use std::convert::From;
use std::convert::TryFrom;
use std::fmt::Display;
use std::iter::Iterator;
#[derive(Default, Debug, Clone)]
pub struct CombinedSequence {
inner: Vec<Sequence>,
done: bool,
initialized: bool,
}
impl CombinedSequence {
fn new() -> Self {
Self::default()
}
pub fn push(&mut self, seq: Sequence) {
self.inner.push(seq)
}
pub fn sequences(&self) -> std::slice::Iter<Sequence> {
self.inner.iter()
}
pub fn sequences_mut(&mut self) -> std::slice::IterMut<Sequence> {
self.inner.iter_mut()
}
pub fn reset(&mut self) {
self.initialized = false;
for seq in &mut self.sequences_mut() {
seq.reset()
}
}
pub fn zero(&mut self) {
self.initialized = false;
for seq in &mut self.sequences_mut() {
seq.zero()
}
}
fn generate_element(&self) -> CombinedElement {
let mut ce = CombinedElement::new();
for s in self.sequences() {
ce.push(s.generate_element())
}
ce
}
}
impl Iterator for CombinedSequence {
type Item = CombinedElement;
fn next(&mut self) -> Option<Self::Item> {
match (self.done, self.initialized) {
(_, false) => {
for s in &mut self.sequences_mut() {
s.next();
}
self.initialized = true;
Some(self.generate_element())
}
(true, _) => { dbg!("done = true"); None },
(false, true) => {
for s in &mut self.sequences_mut() {
match s.next() {
None => s.rollover(),
Some(_) => break
};
}
Some(self.generate_element())
},
}
}
}
impl From<Vec<Sequence>> for CombinedSequence {
fn from(vec: Vec<Sequence>) -> Self {
Self { inner: vec, .. Default::default() }
}
}
impl TryFrom<&str> for CombinedSequence {
type Error = SequenceError;
fn try_from(input: &str) -> Result<CombinedSequence, Self::Error> {
let mut input : &mut str = &mut input.to_owned();
if ! input.is_ascii() {
return Err(SequenceError::InvalidString);
}
let mut splits: Vec<(usize, RenderDisplay)> = Vec::new();
let mut iter = input.char_indices();
while let Some((i, val)) = iter.next() {
let val = RenderDisplay::try_from(val)?;
match splits.last() {
Some((_, lastval)) if *lastval != val => splits.push( (i,val) ),
None => splits.push( (i,val) ),
_ => ()
}
}
let mut cs = CombinedSequence::new();
while let Some((idx, _)) = splits.pop() {
let (init, last) = input.split_at_mut(idx);
input = &mut(*init);
let mut seq = SequenceBuilder::try_from(&*last).unwrap();
if ! splits.is_empty() {
let length = last.len();
seq = seq.max_render_capacity(length as u8);
}
cs.push( seq.build()? );
}
Ok(cs)
}
}
#[derive(Debug, Default, Clone)]
pub struct CombinedElement {
inner: Vec<Element>
}
impl CombinedElement {
fn new() -> Self {
Self::default()
}
pub fn push(&mut self, elem: Element) {
self.inner.push(elem)
}
pub fn elements(&self) -> std::slice::Iter<Element> {
self.inner.iter()
}
}
impl Display for CombinedElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for i in self.elements().rev() {
write!(f, "{}", i )?
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn one_char() {
let mut seq = SequenceBuilder::try_from("A").unwrap().build().unwrap();
let mut cs = CombinedSequence::try_from("A").unwrap();
let elem = seq.next().unwrap();
let celem = cs.next().unwrap();
assert_eq!( elem.to_string(), "A" );
assert_eq!( celem.to_string(), "A" );
let elem = seq.next().unwrap();
let celem = cs.next().unwrap();
assert_eq!( elem.to_string(), "B" );
assert_eq!( celem.to_string(), "B" );
}
#[test]
fn two_char() {
let mut seq = CombinedSequence::try_from("A0").unwrap();
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "A0" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "A1" );
}
#[test]
fn segment_access() {
let mut seq = CombinedSequence::try_from("A9").unwrap();
let segment1 = seq.inner[0].next().unwrap();
assert_eq!( segment1.to_string(), "9" );
let segment1 = seq.inner[0].next();
assert_eq!( segment1, None );
}
#[test]
fn one_char_with_rollover() {
let mut seq = CombinedSequence::try_from("9").unwrap();
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "9" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "10" );
let mut seq = CombinedSequence::try_from("Z").unwrap();
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "Z" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "AA" );
}
#[test]
fn two_char_with_rollover1() {
let mut seq = CombinedSequence::try_from("A9").unwrap();
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "A9" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "B0" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "B1" );
let mut seq = CombinedSequence::try_from("9A").unwrap();
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "9A" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "9B" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "9C" );
let mut seq = CombinedSequence::try_from("Z9ZZ").unwrap();
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "Z9ZZ" );
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), "AA0A" );
}
}