use crate::sequence::helper::*;
use std::convert::From;
use std::convert::TryFrom;
use super::*;
#[derive(Debug)]
pub struct SequenceBuilder {
start: u64,
step: u32,
inclusive: bool,
renderer: SeqRendererBuilder,
min_render_length: Option<u8>,
end: Option<u64>
}
impl Default for SequenceBuilder {
fn default() -> Self {
Self {
start: 0,
step: 1,
end: None,
inclusive: false,
renderer: Default::default(),
min_render_length: Default::default(),
}
}
}
impl SequenceBuilder {
pub fn new() -> Self {
Self { ..Default::default() }
}
pub fn end(mut self, end: u64) -> Self {
self.end = Some(end);
self
}
pub fn start(mut self, start: u64) -> Self {
self.start = start;
self
}
pub fn step(mut self, step: u32) -> Self {
self.step = step;
self
}
pub fn max_render_capacity(mut self, chars: u8) -> Self {
self.renderer = self.renderer.capacity(chars);
self
}
pub fn min_render_length(mut self, chars: u8) -> Self {
self.min_render_length = Some(chars);
self
}
pub fn exclusive(mut self) -> Self {
self.inclusive = false;
self
}
pub fn inclusive(mut self) -> Self {
self.inclusive = true;
self
}
pub fn lower(mut self) -> Self {
self.renderer = SeqRendererBuilder::lower();
self
}
pub fn upper(mut self) -> Self {
self.renderer = SeqRendererBuilder::upper();
self
}
pub fn numeric(mut self) -> Self {
self.renderer = SeqRendererBuilder::numeric();
self
}
pub fn build(self) -> Result<Sequence, SequenceError> {
let renderer = self.renderer.build()?;
match (renderer.display(), self.min_render_length) {
(RenderDisplay::Upper | RenderDisplay::Lower, Some(_)) => return Err(SequenceError::PaddingAlpha),
_ => ()
};
let end = match (self.end, self.inclusive) {
(Some(end), true) => Some(end + 1),
(Some(end), false) => Some(end),
_ => None
};
let seq = Sequence {
end,
step: self.step,
start: self.start,
renderer,
.. Default::default()
};
Ok(seq)
}
}
impl From<u64> for SequenceBuilder {
fn from(start: u64) -> Self {
Self::new().start(start)
}
}
impl TryFrom<&str> for SequenceBuilder {
type Error = SequenceError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let first_char = value
.chars()
.next()
.ok_or_else( || SequenceError::EmptyString )?
;
match renderer::RenderDisplay::try_from(first_char)? {
renderer::RenderDisplay::Numeric => Ok(
Self::new().start(value.parse::<u64>()?).numeric()
),
renderer::RenderDisplay::Upper => Ok(
Self::new().start(string_to_int(&value)?).upper()
),
renderer::RenderDisplay::Lower => Ok(
Self::new().start(string_to_int(&value)?).lower()
)
}
}
}
impl TryFrom<(&str, &str)> for SequenceBuilder {
type Error = SequenceError;
fn try_from((start, end): (&str, &str)) -> Result<Self, Self::Error> {
let first_char = start
.chars()
.next()
.ok_or_else( || SequenceError::EmptyString )?
;
let builder = match renderer::RenderDisplay::try_from(first_char)? {
renderer::RenderDisplay::Numeric => {
Self::new()
.start(start.parse::<u64>()?)
.end(end.parse::<u64>()?)
.numeric()
},
renderer::RenderDisplay::Upper => {
Self::new()
.start(string_to_int(&start)?)
.end(string_to_int(&end)?)
.upper()
},
renderer::RenderDisplay::Lower => {
Self::new()
.start(string_to_int(&start)?)
.end(string_to_int(&end)?)
.lower()
}
};
Ok(builder)
}
}
impl TryFrom<char> for SequenceBuilder {
type Error = SequenceError;
fn try_from(value: char) -> Result<Self, Self::Error> {
Ok(Self::new().start(char_to_int(value)? as u64))
}
}
#[cfg(test)]
mod test {
use super::*;
fn max_render_capacity() {
for limit in 1..10 {
let max = crate::sequence::renderer::max_alpha(limit);
let mut seq = SequenceBuilder::new().start(max)
.upper()
.max_render_capacity(limit)
.build()
.unwrap();
let render_as = "Z".repeat(limit as usize);
let elem = seq.next().unwrap();
assert_eq!( elem.to_string(), render_as );
let elem = seq.next();
assert_eq!( elem, None );
assert_eq!( seq.next(), None )
}
for limit in 1..10 {
let max = crate::sequence::renderer::max_numeric(limit);
let mut seq = SequenceBuilder::new().start(max).numeric().max_render_capacity(limit).build().unwrap();
let render_as = "9".repeat(limit as usize);
assert_eq!( seq.to_string(), render_as, "Render {} as {}", max, render_as );
assert_eq!(
seq.next(),
None,
"Throw error with numeric char limit of {} which can only represent {}",
limit,
max
);
assert_eq!( seq.next(), None )
}
}
#[test]
fn simple() {
for c in 'A'..'Z' {
let mut seq = SequenceBuilder::new().start(c as u64 - 'A' as u64).upper().build().unwrap();
let elem = seq.next().unwrap();
assert_eq!(
elem.to_string(),
c.to_string(),
);
let mut seq = SequenceBuilder::new().start(c as u64 - 'A' as u64).lower().build().unwrap();
let elem = seq.next().unwrap();
assert_eq!(
elem.to_string(),
c.to_string().to_lowercase(),
);
}
for i in 1..123_456 {
let mut seq = SequenceBuilder::new().start(i).numeric().build().unwrap();
let elem = seq.next().unwrap();
assert_eq!(
elem.to_string(),
i.to_string()
);
}
}
fn rollover() {
const A: u32 = 0;
const Z: u32 = 25;
for i in A..Z {
let seq = SequenceBuilder::new().start(Z as u64).upper().build().unwrap();
let result = format!("A{}", std::char::from_u32('A' as u32 + i).unwrap());
assert_eq!(
seq.skip(i as usize + 1).next().unwrap().to_string(),
result
);
let mut seq = SequenceBuilder::new().start(Z as u64).upper().build().unwrap();
assert_eq!(
seq.nth(i as usize + 1).unwrap().to_string(),
result,
".nth({})", i
);
let seq = SequenceBuilder::new().start(Z as u64 + 1 + i as u64).lower().build().unwrap();
assert_eq!(
seq.to_string(),
result.to_lowercase()
);
let mut seq = SequenceBuilder::new().start(A as u64).upper().build().unwrap();
for len in 1..5 {
assert_eq!(
seq.nth(26usize.pow(len as u32) - 1).unwrap().to_string(),
"A".repeat(len + 1),
);
}
let mut seq = SequenceBuilder::new().start(Z as u64).upper().build().unwrap();
for len in 2..5 {
assert_eq!(
seq.nth(26usize.pow(len as u32) - 1).unwrap().to_string(),
"Z".repeat(len),
);
}
}
}
}