iceoryx2_bb_system_types/
file_name.rs1pub use iceoryx2_bb_container::semantic_string::SemanticString;
31use iceoryx2_bb_elementary::static_assert::{static_assert_ge, static_assert_le};
32
33use core::hash::{Hash, Hasher};
34use iceoryx2_bb_container::semantic_string;
35use iceoryx2_pal_configuration::FILENAME_LENGTH;
36
37fn invalid_characters(value: &[u8]) -> bool {
38 for c in value {
39 match c {
40 0 => return true,
42 b'/' => return true,
43 1..=31 => return true,
45 b':' => return true,
46 b'\\' => return true,
47 b'<' => return true,
48 b'>' => return true,
49 b'"' => return true,
50 b'|' => return true,
51 b'?' => return true,
52 b'*' => return true,
53 _ => (),
54 }
55 }
56 false
57}
58
59fn invalid_content(value: &[u8]) -> bool {
60 matches!(value, b"" | b"." | b"..")
61}
62
63fn normalize(this: &FileName) -> FileName {
64 *this
65}
66
67semantic_string! {
68 name: FileName,
71 capacity: FILENAME_LENGTH,
72 invalid_content: invalid_content,
73 invalid_characters: invalid_characters,
74 normalize: normalize
75}
76
77#[derive(Debug, Clone, Copy, Eq)]
78pub struct RestrictedFileName<const CAPACITY: usize> {
79 value: iceoryx2_bb_container::byte_string::FixedSizeByteString<CAPACITY>,
80}
81
82impl<const CAPACITY: usize>
83 iceoryx2_bb_container::semantic_string::internal::SemanticStringAccessor<CAPACITY>
84 for RestrictedFileName<CAPACITY>
85{
86 unsafe fn new_empty() -> Self {
87 static_assert_le::<{ CAPACITY }, { FILENAME_LENGTH }>();
88 static_assert_ge::<{ CAPACITY }, 1>();
89
90 Self {
91 value: iceoryx2_bb_container::byte_string::FixedSizeByteString::new(),
92 }
93 }
94
95 unsafe fn get_mut_string(
96 &mut self,
97 ) -> &mut iceoryx2_bb_container::byte_string::FixedSizeByteString<CAPACITY> {
98 &mut self.value
99 }
100
101 fn is_invalid_content(string: &[u8]) -> bool {
102 if Self::does_contain_invalid_characters(string) {
103 return true;
104 }
105
106 invalid_content(string)
107 }
108
109 fn does_contain_invalid_characters(string: &[u8]) -> bool {
110 if core::str::from_utf8(string).is_err() {
111 return true;
112 }
113
114 invalid_characters(string)
115 }
116}
117
118pub(crate) mod visitor_type {
120 pub(crate) struct RestrictedFileName<const CAPACITY: usize>;
121}
122
123impl<const CAPACITY: usize> serde::de::Visitor<'_> for visitor_type::RestrictedFileName<CAPACITY> {
124 type Value = RestrictedFileName<CAPACITY>;
125
126 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
127 formatter.write_str("a string containing the service name")
128 }
129
130 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
131 where
132 E: serde::de::Error,
133 {
134 RestrictedFileName::<CAPACITY>::new(v.as_bytes()).map_err(|e| {
135 E::custom(std::format!(
136 "invalid RestrictedFileName<{}> provided {:?} ({:?}).",
137 CAPACITY,
138 v,
139 e
140 ))
141 })
142 }
143}
144
145impl<'de, const CAPACITY: usize> serde::Deserialize<'de> for RestrictedFileName<CAPACITY> {
146 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147 where
148 D: serde::Deserializer<'de>,
149 {
150 deserializer.deserialize_str(visitor_type::RestrictedFileName::<CAPACITY>)
151 }
152}
153
154impl<const CAPACITY: usize> serde::Serialize for RestrictedFileName<CAPACITY> {
155 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
156 where
157 S: serde::Serializer,
158 {
159 serializer.serialize_str(std::str::from_utf8(self.as_bytes()).unwrap())
160 }
161}
162impl<const CAPACITY: usize> iceoryx2_bb_container::semantic_string::SemanticString<CAPACITY>
165 for RestrictedFileName<CAPACITY>
166{
167 fn as_string(&self) -> &iceoryx2_bb_container::byte_string::FixedSizeByteString<CAPACITY> {
168 &self.value
169 }
170
171 fn normalize(&self) -> Self {
172 *self
173 }
174
175 unsafe fn new_unchecked(bytes: &[u8]) -> Self {
176 Self {
177 value: iceoryx2_bb_container::byte_string::FixedSizeByteString::new_unchecked(bytes),
178 }
179 }
180
181 unsafe fn insert_bytes_unchecked(&mut self, idx: usize, bytes: &[u8]) {
182 self.value.insert_bytes_unchecked(idx, bytes);
183 }
184}
185
186impl<const CAPACITY: usize> RestrictedFileName<CAPACITY> {
187 pub const fn max_len() -> usize {
189 CAPACITY
190 }
191}
192
193impl<const CAPACITY: usize> std::fmt::Display for RestrictedFileName<CAPACITY> {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 std::write!(f, "{}", self.value)
196 }
197}
198
199impl<const CAPACITY: usize> Hash for RestrictedFileName<CAPACITY> {
200 fn hash<H: Hasher>(&self, state: &mut H) {
201 self.normalize().as_bytes().hash(state)
202 }
203}
204
205impl<const CAPACITY: usize> From<RestrictedFileName<CAPACITY>> for FileName {
206 fn from(value: RestrictedFileName<CAPACITY>) -> FileName {
207 unsafe { FileName::new_unchecked(value.as_bytes()) }
210 }
211}
212
213impl<const CAPACITY: usize> From<RestrictedFileName<CAPACITY>> for String {
214 fn from(value: RestrictedFileName<CAPACITY>) -> String {
215 unsafe { String::from_utf8_unchecked(value.as_bytes().to_vec()) }
217 }
218}
219
220impl<const CAPACITY: usize> From<&RestrictedFileName<CAPACITY>> for String {
221 fn from(value: &RestrictedFileName<CAPACITY>) -> String {
222 unsafe { String::from_utf8_unchecked(value.as_bytes().to_vec()) }
224 }
225}
226
227impl<const CAPACITY: usize> std::convert::TryFrom<&str> for RestrictedFileName<CAPACITY> {
228 type Error = iceoryx2_bb_container::semantic_string::SemanticStringError;
229
230 fn try_from(value: &str) -> Result<Self, Self::Error> {
231 Self::new(value.as_bytes())
232 }
233}
234
235impl<const CAPACITY: usize> std::convert::TryFrom<&FileName> for RestrictedFileName<CAPACITY> {
236 type Error = iceoryx2_bb_container::semantic_string::SemanticStringError;
237
238 fn try_from(value: &FileName) -> Result<Self, Self::Error> {
239 Self::new(value.as_bytes())
240 }
241}
242
243impl<const CAPACITY: usize> PartialEq<RestrictedFileName<CAPACITY>>
244 for RestrictedFileName<CAPACITY>
245{
246 fn eq(&self, other: &RestrictedFileName<CAPACITY>) -> bool {
247 *self.normalize().as_bytes() == *other.normalize().as_bytes()
248 }
249}
250
251impl<const CAPACITY: usize> PartialEq<&[u8]> for RestrictedFileName<CAPACITY> {
252 fn eq(&self, other: &&[u8]) -> bool {
253 let other = match RestrictedFileName::<CAPACITY>::new(other) {
254 Ok(other) => other,
255 Err(_) => return false,
256 };
257
258 *self == other
259 }
260}
261
262impl<const CAPACITY: usize> PartialEq<&[u8]> for &RestrictedFileName<CAPACITY> {
263 fn eq(&self, other: &&[u8]) -> bool {
264 let other = match RestrictedFileName::<CAPACITY>::new(other) {
265 Ok(other) => other,
266 Err(_) => return false,
267 };
268
269 **self == other
270 }
271}
272
273impl<const CAPACITY: usize> PartialEq<[u8; CAPACITY]> for RestrictedFileName<CAPACITY> {
274 fn eq(&self, other: &[u8; CAPACITY]) -> bool {
275 let other = match RestrictedFileName::<CAPACITY>::new(other) {
276 Ok(other) => other,
277 Err(_) => return false,
278 };
279
280 *self == other
281 }
282}
283
284impl<const CAPACITY: usize> PartialEq<&[u8; CAPACITY]> for RestrictedFileName<CAPACITY> {
285 fn eq(&self, other: &&[u8; CAPACITY]) -> bool {
286 #[allow(clippy::explicit_auto_deref)]
288 let other = match RestrictedFileName::<CAPACITY>::new(*other) {
289 Ok(other) => other,
290 Err(_) => return false,
291 };
292
293 *self == other
294 }
295}
296
297impl<const CAPACITY: usize> std::ops::Deref for RestrictedFileName<CAPACITY> {
298 type Target = [u8];
299
300 fn deref(&self) -> &Self::Target {
301 self.value.as_bytes()
302 }
303}