1use super::Error;
23#[cfg(feature = "alloc")]
24use crate::{pathbuf::PathBuf, DELIMITER};
25#[cfg(feature = "alloc")]
26use alloc::{str, string::String, vec::Vec};
27#[cfg(feature = "alloc")]
28use core::fmt::{self, Debug};
29
30pub const MAX_COMPONENT_LENGTH: usize = 256;
32
33#[derive(Eq, Hash, PartialEq, PartialOrd, Ord)]
39#[repr(transparent)]
40pub struct Path([u8]);
41
42impl Path {
43 #[allow(unsafe_code)]
49 pub fn new<P>(path: &P) -> Result<&Self, Error>
50 where
51 P: AsRef<[u8]> + ?Sized,
52 {
53 if Components::new(path.as_ref()).validate() {
54 Ok(unsafe { &*(path.as_ref() as *const [u8] as *const Self) })
55 } else {
56 Err(Error)
57 }
58 }
59
60 pub fn as_bytes(&self) -> &[u8] {
62 self.0.as_ref()
63 }
64
65 pub fn components(&self) -> Components<'_> {
67 Components::new(&self.0)
68 }
69
70 pub fn is_root(&self) -> bool {
72 self.0.is_empty()
73 }
74
75 #[cfg(feature = "alloc")]
79 pub fn join<P>(&self, path: P) -> PathBuf
80 where
81 P: AsRef<Path>,
82 {
83 let mut result = PathBuf::new();
84 result.extend(self.components());
85 result.extend(path.as_ref().components());
86 result
87 }
88
89 pub fn parent(&self) -> Option<&Path> {
91 let mut tail = None;
92
93 for component in self.components() {
94 tail = Some(component)
95 }
96
97 tail.map(|t| {
98 let tail_len = self.0.len() - t.len() - 1;
99 Path::new(&self.0[..tail_len]).unwrap()
100 })
101 }
102
103 #[cfg(feature = "alloc")]
109 pub fn stringify(&self) -> Result<String, Error> {
110 let mut result = String::new();
111
112 if self.is_root() {
113 result.push(DELIMITER);
114 return Ok(result);
115 }
116
117 for component in self.components() {
118 result.push(DELIMITER);
119 result.push_str(component.stringify()?.as_ref());
120 }
121
122 Ok(result)
123 }
124
125 #[cfg(feature = "alloc")]
127 pub fn to_vec(&self) -> Vec<u8> {
128 self.0.to_vec()
129 }
130
131 #[cfg(feature = "alloc")]
133 pub(crate) fn debug_components(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(f, "(")?;
135
136 if let Ok(s) = self.stringify() {
137 s.fmt(f)?;
138 } else {
139 let component_count = self.components().count();
140 for (i, component) in self.components().enumerate() {
141 write!(f, "{:?}", component)?;
142 if i < component_count - 1 {
143 write!(f, ", ")?;
144 }
145 }
146 }
147
148 write!(f, ")")
149 }
150}
151
152impl AsRef<Path> for Path {
153 fn as_ref(&self) -> &Self {
154 self
155 }
156}
157
158#[cfg(feature = "alloc")]
159impl Debug for Path {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 write!(f, "hkd32::Path")?;
162 self.debug_components(f)
163 }
164}
165
166#[derive(Copy, Clone, Eq, Hash, PartialEq)]
168#[repr(transparent)]
169pub struct Component<'a>(&'a [u8]);
170
171#[allow(clippy::len_without_is_empty)]
173impl<'a> Component<'a> {
174 pub fn new(bytes: &'a [u8]) -> Result<Self, Error> {
179 if !bytes.is_empty() && bytes.len() <= MAX_COMPONENT_LENGTH {
180 Ok(Component(bytes))
181 } else {
182 Err(Error)
183 }
184 }
185
186 pub fn as_bytes(&self) -> &'a [u8] {
188 self.0
189 }
190
191 pub fn len(&self) -> usize {
193 self.0.len()
194 }
195
196 #[cfg(feature = "alloc")]
200 pub fn stringify(&self) -> Result<String, Error> {
201 let s = str::from_utf8(self.as_bytes())
202 .map(String::from)
203 .map_err(|_| Error)?;
204
205 if s.is_ascii() {
206 Ok(s)
207 } else {
208 Err(Error)
209 }
210 }
211
212 #[cfg(feature = "alloc")]
214 pub fn to_bytes(self) -> Vec<u8> {
215 let mut serialized = Vec::with_capacity(1 + self.len());
216 serialized.push((self.len() - 1) as u8);
217 serialized.extend_from_slice(self.0);
218 serialized
219 }
220}
221
222impl<'a> AsRef<Component<'a>> for Component<'a> {
223 fn as_ref(&self) -> &Component<'a> {
224 self
225 }
226}
227
228#[cfg(feature = "alloc")]
229impl<'a> Debug for Component<'a> {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(f, "hkd32::Component")?;
232
233 if let Ok(s) = self.stringify() {
234 write!(f, "({:?})", s)
235 } else {
236 write!(f, "({:?})", self.as_bytes())
237 }
238 }
239}
240
241#[derive(Clone)]
243pub struct Components<'a> {
244 path: &'a [u8],
246
247 valid: bool,
249}
250
251impl<'a> Components<'a> {
252 fn new(path: &'a [u8]) -> Self {
254 Self { path, valid: true }
255 }
256
257 fn validate(mut self) -> bool {
261 while self.next().is_some() {}
262 self.valid
263 }
264}
265
266impl<'a> Iterator for Components<'a> {
267 type Item = Component<'a>;
268
269 fn next(&mut self) -> Option<Component<'a>> {
270 let component_len = *self.path.first()? as usize + 1;
272 self.path = &self.path[1..];
273
274 if self.path.len() < component_len {
275 self.valid = false;
278 return None;
279 }
280
281 let (component_bytes, remaining) = self.path.split_at(component_len);
282 self.path = remaining;
283
284 if let Ok(component) = Component::new(component_bytes) {
285 Some(component)
286 } else {
287 self.valid = false;
288 None
289 }
290 }
291}
292
293#[cfg(all(test, feature = "alloc"))]
294mod tests {
295 use super::*;
296
297 #[test]
298 fn test_root() {
299 let root_path = Path::new(&[]).unwrap();
300 assert_eq!(root_path.components().count(), 0);
301 assert_eq!(root_path.stringify().unwrap(), "/");
302 assert_eq!(&format!("{:?}", root_path), "hkd32::Path(\"/\")");
303 }
304}