acyclic_fs/kernel/
namespace_path.rs1use super::{LogicalName, NameEncoding, TreePageError};
4use crate::model::{FilesystemProfile, VolumeLimits};
5use crate::path::PortablePath;
6use thiserror::Error;
7
8#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
15pub struct NamespacePath {
16 components: Vec<LogicalName>,
17 encoded_bytes: u32,
18}
19
20impl NamespacePath {
21 pub fn new(
28 components: Vec<LogicalName>,
29 limits: VolumeLimits,
30 ) -> Result<Self, NamespacePathError> {
31 if u16::try_from(components.len()).unwrap_or(u16::MAX) > limits.maximum_path_depth {
32 return Err(NamespacePathError::TooDeep);
33 }
34 let mut encoded_bytes = 1_u32;
35 for component in &components {
36 let length = u32::try_from(component.as_bytes().len())
37 .map_err(|_| NamespacePathError::ComponentTooLong)?;
38 if length > limits.maximum_component_bytes {
39 return Err(NamespacePathError::ComponentTooLong);
40 }
41 encoded_bytes = encoded_bytes
42 .checked_add(length)
43 .and_then(|value| value.checked_add(1))
44 .ok_or(NamespacePathError::PathTooLong)?;
45 }
46 if !components.is_empty() {
47 encoded_bytes = encoded_bytes.saturating_sub(1);
48 }
49 if encoded_bytes > limits.maximum_path_bytes {
50 return Err(NamespacePathError::PathTooLong);
51 }
52 Ok(Self {
53 components,
54 encoded_bytes,
55 })
56 }
57
58 pub fn from_portable(
65 path: &PortablePath,
66 limits: VolumeLimits,
67 ) -> Result<Self, NamespacePathError> {
68 Self::from_portable_in_profile(path, FilesystemProfile::Portable, limits)
69 }
70
71 pub fn from_portable_in_profile(
81 path: &PortablePath,
82 profile: FilesystemProfile,
83 limits: VolumeLimits,
84 ) -> Result<Self, NamespacePathError> {
85 let components = path
86 .components()
87 .map(|component| {
88 let (encoding, bytes) = match profile {
89 FilesystemProfile::Portable | FilesystemProfile::Browser => {
90 (NameEncoding::Utf8, component.as_bytes().to_vec())
91 }
92 FilesystemProfile::Posix => {
93 (NameEncoding::PosixBytes, component.as_bytes().to_vec())
94 }
95 FilesystemProfile::Windows => (
96 NameEncoding::WindowsUtf16Le,
97 component
98 .encode_utf16()
99 .flat_map(u16::to_le_bytes)
100 .collect(),
101 ),
102 };
103 LogicalName::new(encoding, bytes, limits.maximum_component_bytes)
104 .map_err(NamespacePathError::Name)
105 })
106 .collect::<Result<Vec<_>, _>>()?;
107 Self::new(components, limits)
108 }
109
110 #[must_use]
112 pub fn is_root(&self) -> bool {
113 self.components.is_empty()
114 }
115
116 #[must_use]
118 pub fn depth(&self) -> usize {
119 self.components.len()
120 }
121
122 #[must_use]
124 pub const fn encoded_bytes(&self) -> u32 {
125 self.encoded_bytes
126 }
127
128 #[must_use]
130 pub fn components(&self) -> &[LogicalName] {
131 &self.components
132 }
133
134 #[must_use]
136 pub fn split_last(&self) -> Option<(&[LogicalName], &LogicalName)> {
137 self.components
138 .split_last()
139 .map(|(name, parent)| (parent, name))
140 }
141
142 #[must_use]
147 pub fn parent(&self) -> Option<Self> {
148 let (_, name) = self.split_last()?;
149 let encoded_bytes = if self.components.len() == 1 {
150 1
151 } else {
152 self.encoded_bytes
153 .saturating_sub(u32::try_from(name.as_bytes().len()).unwrap_or(u32::MAX))
154 .saturating_sub(1)
155 };
156 let mut components = self.components.clone();
157 components.pop();
158 Some(Self {
159 components,
160 encoded_bytes,
161 })
162 }
163
164 #[must_use]
166 pub fn is_within(&self, ancestor: &Self) -> bool {
167 self.components.starts_with(&ancestor.components)
168 }
169}
170
171#[derive(Clone, Debug, Eq, Error, PartialEq)]
173pub enum NamespacePathError {
174 #[error("namespace path exceeds its depth bound")]
176 TooDeep,
177 #[error("namespace path component exceeds its byte bound")]
179 ComponentTooLong,
180 #[error("namespace path exceeds its byte bound")]
182 PathTooLong,
183 #[error(transparent)]
185 Name(TreePageError),
186}
187
188#[cfg(test)]
189#[path = "tests/namespace_path.rs"]
190mod tests;