storage-path-generator/src/lib.rs

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()
}
}