storage-path-generator/src/lib.rs

121 lines
2.6 KiB
Rust

use parking_lot::Mutex;
use std::{convert::TryInto, sync::Arc};
#[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 struct PathError;
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().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)?;
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);
}
for elem in inner.iter() {
if *elem > 999 {
return Err(PathError);
}
}
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()
}
}