storage_path_generator/
lib.rs

1use std::{
2    convert::TryInto,
3    sync::{Arc, Mutex},
4};
5
6#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
7struct Inner {
8    counter: Vec<u16>,
9}
10
11#[derive(Clone, Debug)]
12pub struct Generator {
13    current: Arc<Mutex<Inner>>,
14}
15
16#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
17pub struct Path {
18    inner: Vec<u16>,
19}
20
21#[derive(Debug)]
22pub enum PathError {
23    Format,
24    Length,
25    Range,
26}
27
28impl Inner {
29    fn next(&mut self) -> Vec<u16> {
30        let mut modified_depth = 0;
31
32        for (depth, count) in self.counter.iter_mut().enumerate().rev() {
33            if *count < 999 {
34                *count += 1;
35                modified_depth = depth;
36                break;
37            } else {
38                *count = 0;
39            }
40        }
41
42        if modified_depth == 0 {
43            self.counter.push(0);
44        }
45
46        self.counter.clone()
47    }
48}
49
50impl Generator {
51    pub fn new() -> Self {
52        Self::from_existing(Path { inner: vec![] })
53    }
54
55    pub fn from_existing(existing: Path) -> Self {
56        Generator {
57            current: Arc::new(Mutex::new(Inner {
58                counter: existing.inner,
59            })),
60        }
61    }
62
63    pub fn next(&self) -> Path {
64        let inner = self.current.lock().unwrap().next();
65
66        Path { inner }
67    }
68}
69
70impl Path {
71    pub fn from_be_bytes(bytes: Vec<u8>) -> Result<Self, PathError> {
72        let inner = bytes
73            .chunks(2)
74            .map(|chunk| {
75                let be_bytes: [u8; 2] = chunk.try_into().map_err(|_| PathError::Length)?;
76                Ok(u16::from_be_bytes(be_bytes))
77            })
78            .collect::<Result<_, PathError>>()?;
79
80        Self::from_vec(inner)
81    }
82
83    pub fn to_be_bytes(&self) -> Vec<u8> {
84        self.inner
85            .iter()
86            .flat_map(|num| num.to_be_bytes())
87            .collect()
88    }
89
90    pub fn into_inner(self) -> Vec<u16> {
91        self.inner
92    }
93
94    pub fn from_vec(inner: Vec<u16>) -> Result<Self, PathError> {
95        if inner.is_empty() {
96            return Ok(Path { inner });
97        }
98
99        if inner.len().saturating_sub(1) != inner[0].into() {
100            return Err(PathError::Format);
101        }
102
103        for elem in inner.iter() {
104            if *elem > 999 {
105                return Err(PathError::Range);
106            }
107        }
108
109        Ok(Path { inner })
110    }
111
112    pub fn to_strings(&self) -> Vec<String> {
113        self.inner
114            .iter()
115            .map(|dir| {
116                if *dir > 99 {
117                    format!("{}", dir)
118                } else if *dir > 9 {
119                    format!("0{}", dir)
120                } else {
121                    format!("00{}", dir)
122                }
123            })
124            .collect()
125    }
126}
127
128impl std::fmt::Display for PathError {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        match self {
131            PathError::Format => {
132                write!(f, "Invalid path format")
133            }
134            PathError::Length => {
135                write!(f, "Invalid segment length")
136            }
137            PathError::Range => {
138                write!(f, "Invalid segment format")
139            }
140        }
141    }
142}
143
144impl std::error::Error for PathError {}
145
146impl Default for Generator {
147    fn default() -> Self {
148        Self::new()
149    }
150}