151 lines
3.3 KiB
Rust
151 lines
3.3 KiB
Rust
use std::{
|
|
convert::TryInto,
|
|
sync::{Arc, Mutex},
|
|
};
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
|
struct Inner {
|
|
counter: Vec<u16>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Generator {
|
|
current: Arc<Mutex<Inner>>,
|
|
}
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Path {
|
|
inner: Vec<u16>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum PathError {
|
|
Format,
|
|
Length,
|
|
Range,
|
|
}
|
|
|
|
impl Inner {
|
|
fn next(&mut self) -> Vec<u16> {
|
|
let mut modified_depth = 0;
|
|
|
|
for (depth, count) in self.counter.iter_mut().enumerate().rev() {
|
|
if *count < 999 {
|
|
*count += 1;
|
|
modified_depth = depth;
|
|
break;
|
|
} else {
|
|
*count = 0;
|
|
}
|
|
}
|
|
|
|
if modified_depth == 0 {
|
|
self.counter.push(0);
|
|
}
|
|
|
|
self.counter.clone()
|
|
}
|
|
}
|
|
|
|
impl Generator {
|
|
pub fn new() -> Self {
|
|
Self::from_existing(Path { inner: vec![] })
|
|
}
|
|
|
|
pub fn from_existing(existing: Path) -> Self {
|
|
Generator {
|
|
current: Arc::new(Mutex::new(Inner {
|
|
counter: existing.inner,
|
|
})),
|
|
}
|
|
}
|
|
|
|
pub fn next(&self) -> Path {
|
|
let inner = self.current.lock().unwrap().next();
|
|
|
|
Path { inner }
|
|
}
|
|
}
|
|
|
|
impl Path {
|
|
pub fn from_be_bytes(bytes: Vec<u8>) -> Result<Self, PathError> {
|
|
let inner = bytes
|
|
.chunks(2)
|
|
.map(|chunk| {
|
|
let be_bytes: [u8; 2] = chunk.try_into().map_err(|_| PathError::Length)?;
|
|
Ok(u16::from_be_bytes(be_bytes))
|
|
})
|
|
.collect::<Result<_, PathError>>()?;
|
|
|
|
Self::from_vec(inner)
|
|
}
|
|
|
|
pub fn to_be_bytes(&self) -> Vec<u8> {
|
|
self.inner
|
|
.iter()
|
|
.flat_map(|num| num.to_be_bytes())
|
|
.collect()
|
|
}
|
|
|
|
pub fn into_inner(self) -> Vec<u16> {
|
|
self.inner
|
|
}
|
|
|
|
pub fn from_vec(inner: Vec<u16>) -> Result<Self, PathError> {
|
|
if inner.is_empty() {
|
|
return Ok(Path { inner });
|
|
}
|
|
|
|
if inner.len().saturating_sub(1) != inner[0].into() {
|
|
return Err(PathError::Format);
|
|
}
|
|
|
|
for elem in inner.iter() {
|
|
if *elem > 999 {
|
|
return Err(PathError::Range);
|
|
}
|
|
}
|
|
|
|
Ok(Path { inner })
|
|
}
|
|
|
|
pub fn to_strings(&self) -> Vec<String> {
|
|
self.inner
|
|
.iter()
|
|
.map(|dir| {
|
|
if *dir > 99 {
|
|
format!("{}", dir)
|
|
} else if *dir > 9 {
|
|
format!("0{}", dir)
|
|
} else {
|
|
format!("00{}", dir)
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for PathError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
PathError::Format => {
|
|
write!(f, "Invalid path format")
|
|
}
|
|
PathError::Length => {
|
|
write!(f, "Invalid segment length")
|
|
}
|
|
PathError::Range => {
|
|
write!(f, "Invalid segment format")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for PathError {}
|
|
|
|
impl Default for Generator {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|