1use alloc::{boxed::Box, string::String, vec::Vec};
51use core::{
52 convert::{TryFrom, TryInto},
53 fmt::{Debug, Display},
54 num::NonZeroU32,
55};
56
57use zenoh_result::{bail, zerror, Error, IError, ZResult};
58
59use super::{keyexpr, OwnedKeyExpr};
60
61mod support;
62pub use support::{IKeFormatStorage, Segment};
63use support::{IterativeConstructor, Spec};
64
65#[derive(Clone, Copy, Hash)]
100pub struct KeFormat<'s, Storage: IKeFormatStorage<'s> + 's = Vec<Segment<'s>>> {
101 storage: Storage,
103 suffix: &'s str,
108}
109impl<'s, Storage: IKeFormatStorage<'s>> Debug for KeFormat<'s, Storage> {
110 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111 write!(f, "{self}")
112 }
113}
114impl<'s> KeFormat<'s, Vec<Segment<'s>>> {
115 pub fn new<S: AsRef<str> + ?Sized>(value: &'s S) -> ZResult<Self> {
117 value.as_ref().try_into()
118 }
119 pub fn noalloc_new<const N: usize>(value: &'s str) -> ZResult<KeFormat<'s, [Segment<'s>; N]>> {
126 value.try_into()
127 }
128}
129
130pub mod macro_support {
131 use super::*;
132 #[doc(hidden)]
136 #[derive(Clone, Copy)]
137 pub struct SegmentBuilder {
138 pub segment_start: usize,
139 pub prefix_end: usize,
140 pub spec_start: usize,
141 pub id_end: u16,
142 pub pattern_end: u16,
143 pub spec_end: usize,
144 pub segment_end: usize,
145 }
146
147 #[doc(hidden)]
152 pub unsafe fn specs<'s>(this: &KeFormat<'s, Vec<Segment<'s>>>) -> Vec<SegmentBuilder> {
153 let segments = this.storage.segments();
154 if segments.is_empty() {
155 return Vec::new();
156 }
157 let source_start = segments[0].prefix.as_ptr() as usize;
158 segments
159 .iter()
160 .map(|segment| {
161 let segment_start = segment.prefix.as_ptr() as usize - source_start;
162 let prefix_end = segment_start + segment.prefix.len();
163 let spec_start = segment.spec.spec.as_ptr() as usize - source_start;
164 let spec_end = spec_start + segment.spec.spec.len();
165 let segment_end = spec_end + spec_start - prefix_end - 1;
166 SegmentBuilder {
167 segment_start,
168 prefix_end,
169 spec_start,
170 id_end: segment.spec.id_end,
171 pattern_end: segment.spec.pattern_end,
172 spec_end,
173 segment_end,
174 }
175 })
176 .collect()
177 }
178 #[doc(hidden)]
183 pub const unsafe fn const_new<const N: usize>(
184 source: &'static str,
185 segments: [SegmentBuilder; N],
186 ) -> KeFormat<'static, [Segment<'static>; N]> {
187 const unsafe fn substr(source: &'static str, start: usize, end: usize) -> &'static str {
190 unsafe {
192 core::str::from_utf8_unchecked(core::slice::from_raw_parts(
193 source.as_ptr().add(start),
194 end - start,
195 ))
196 }
197 }
198 let mut storage = [Segment {
199 prefix: "",
200 spec: Spec {
201 spec: "",
202 id_end: 0,
203 pattern_end: 0,
204 },
205 }; N];
206 let mut suffix_start = 0;
207 let mut i = 0;
208 while i < N {
209 let segment = segments[i];
210 let prefix = unsafe { substr(source, segment.segment_start, segment.prefix_end) };
212 let spec = Spec {
213 spec: unsafe { substr(source, segment.spec_start, segment.spec_end) },
215 id_end: segment.id_end,
216 pattern_end: segment.pattern_end,
217 };
218 storage[i] = Segment { prefix, spec };
219 suffix_start = segment.segment_end;
220 i += 1;
221 }
222 let suffix = unsafe { substr(source, suffix_start, source.len()) };
224 KeFormat { storage, suffix }
225 }
226}
227impl<'s, Storage: IKeFormatStorage<'s> + 's> KeFormat<'s, Storage> {
228 pub fn formatter(&'s self) -> KeFormatter<'s, Storage> {
230 KeFormatter {
231 format: self,
232 buffer: String::new(),
233 values: Storage::values_storage(&self.storage, |_| None),
234 }
235 }
236}
237impl<'s, Storage: IKeFormatStorage<'s> + 's> TryFrom<&'s String> for KeFormat<'s, Storage> {
238 type Error = Error;
239 fn try_from(value: &'s String) -> Result<Self, Self::Error> {
240 Self::try_from(value.as_str())
241 }
242}
243impl<'s, Storage: IKeFormatStorage<'s> + 's> TryFrom<&'s str> for KeFormat<'s, Storage> {
244 type Error = Error;
245 fn try_from(value: &'s str) -> Result<Self, Self::Error> {
246 let mut storage = Storage::new_constructor();
247 let mut segment_start = 0;
248 let mut i = 0;
249 let bvalue = value.as_bytes();
250 while i < bvalue.len() {
251 if bvalue[i] == b'$' {
252 let prefix_end = i;
253 i += 1;
254 let (terminator, spec_start) = match bvalue[i] {
255 b'{' => ("}", i+ 1),
256 b'*' => {i+= 1; continue;}
257 b'#' if bvalue[i+1] == b'{' => ("}#", i +2),
258 c => bail!("Invalid KeFormat: {value} contains `${}` which is not legal in KEs or formats", c as char)
259 };
260 let spec = &value[spec_start..];
261 let Some(spec_end) = spec.find(terminator) else {
262 bail!("Invalid KeFormat: {value} contains an unterminated spec")
263 };
264 let spec = &spec[..spec_end];
265 let spec = match Spec::try_from(spec) {
266 Ok(spec) => spec,
267 Err(e) => {
268 bail!(e => "Invalid KeFormat: {value} contains an invalid spec: {spec}")
269 }
270 };
271 let segment_end = spec_end + spec_start + terminator.len();
272 if prefix_end != 0 && bvalue[prefix_end - 1] != b'/' {
273 bail!("Invalid KeFormat: a spec in {value} is preceded a non-`/` character")
274 }
275 if !matches!(bvalue.get(segment_end), None | Some(b'/')) {
276 bail!("Invalid KeFormat: a spec in {value} is followed by a non-`/` character")
277 }
278 keyexpr::new(spec.pattern().as_str())?; let prefix = &value[segment_start..prefix_end];
280 if prefix.contains('*') {
281 bail!("Invalid KeFormat: wildcards are only allowed in specs when writing formats")
282 }
283 let segment = Segment { prefix, spec };
284 storage = match Storage::add_segment(storage, segment) {
285 IterativeConstructor::Error(e) => {
286 bail!("Couldn't construct KeFormat because its Storage's add_segment failed: {e}")
287 }
288 s => s,
289 };
290 segment_start = segment_end;
291 } else {
292 i += 1;
293 }
294 }
295 let IterativeConstructor::Complete(storage) = storage else {
296 bail!("Couldn't construct KeFormat because its Storage construction was only partial after adding the last segment.")
297 };
298 let segments = storage.segments();
299 for i in 0..(segments.len() - 1) {
300 if segments[(i + 1)..]
301 .iter()
302 .any(|s| s.spec.id() == segments[i].spec.id())
303 {
304 bail!("Invalid KeFormat: {value} contains duplicated ids")
305 }
306 }
307 let suffix = &value[segment_start..];
308 if suffix.contains('*') {
309 bail!("Invalid KeFormat: wildcards are only allowed in specs when writing formats")
310 }
311 Ok(KeFormat { storage, suffix })
312 }
313}
314
315impl<'s, Storage: IKeFormatStorage<'s> + 's> core::convert::TryFrom<&KeFormat<'s, Storage>>
316 for String
317{
318 type Error = core::fmt::Error;
319 fn try_from(value: &KeFormat<'s, Storage>) -> Result<Self, Self::Error> {
320 use core::fmt::Write;
321 let mut s = String::new();
322 for segment in value.storage.segments() {
323 s += segment.prefix;
324 write!(&mut s, "{}", segment.spec.pattern())?;
325 }
326 s += value.suffix;
327 Ok(s)
328 }
329}
330impl<'s, Storage: IKeFormatStorage<'s> + 's> core::convert::TryFrom<&KeFormat<'s, Storage>>
331 for OwnedKeyExpr
332{
333 type Error = Error;
334 fn try_from(value: &KeFormat<'s, Storage>) -> Result<Self, Self::Error> {
335 let s: String = value
336 .try_into()
337 .map_err(|e| zerror!("failed to write into String: {e}"))?;
338 OwnedKeyExpr::autocanonize(s)
339 }
340}
341
342impl<'s, Storage: IKeFormatStorage<'s> + 's> core::fmt::Display for KeFormat<'s, Storage> {
343 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
344 for segment in self.storage.segments() {
345 write!(f, "{}{}", segment.prefix, segment.spec)?;
346 }
347 write!(f, "{}", self.suffix)
348 }
349}
350
351#[derive(Debug, Clone, Copy, PartialEq, Eq)]
352struct NonMaxU32(NonZeroU32);
353impl NonMaxU32 {
354 fn new(value: u32) -> Option<Self> {
355 NonZeroU32::new(!value).map(NonMaxU32)
356 }
357 fn get(&self) -> u32 {
358 !self.0.get()
359 }
360}
361
362#[derive(Clone)]
364pub struct KeFormatter<'s, Storage: IKeFormatStorage<'s>> {
365 format: &'s KeFormat<'s, Storage>,
366 buffer: String,
367 values: Storage::ValuesStorage<Option<(u32, NonMaxU32)>>,
368}
369
370impl<'s, Storage: IKeFormatStorage<'s>> core::fmt::Debug for KeFormatter<'s, Storage> {
371 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
372 let values = self.values.as_ref();
373 let segments = self.format.storage.segments();
374 for i in 0..values.len() {
375 let Segment { prefix, spec } = segments[i];
376 let value =
377 values[i].map(|(start, end)| &self.buffer[start as usize..end.get() as usize]);
378 let id = spec.id();
379 let pattern = spec.pattern();
380 let sharp = if id.contains('}')
381 || pattern.contains('}')
382 || value.map_or_else(
383 || spec.default().is_some_and(|v| v.contains('}')),
384 |v| v.contains('}'),
385 ) {
386 "#"
387 } else {
388 ""
389 };
390 write!(f, "{prefix}${sharp}{{{id}:{pattern}")?;
391 if let Some(value) = value {
392 write!(f, "={value}")?
393 } else if let Some(default) = spec.default() {
394 write!(f, "#{default}")?
395 };
396 write!(f, "}}{sharp}")?;
397 }
398 write!(f, "{}", self.format.suffix)
399 }
400}
401
402impl<'s, Storage: IKeFormatStorage<'s>> TryFrom<&KeFormatter<'s, Storage>> for OwnedKeyExpr {
403 type Error = Error;
404
405 fn try_from(value: &KeFormatter<'s, Storage>) -> Result<Self, Self::Error> {
406 let values = value.values.as_ref();
407 let segments = value.format.storage.segments();
408 let mut len = value.format.suffix.len();
409 for i in 0..values.len() {
410 len += segments[i].prefix.len()
411 + if let Some((start, end)) = values[i] {
412 (end.get() - start) as usize
413 } else if let Some(default) = segments[i].spec.default() {
414 default.len()
415 } else {
416 bail!("Missing field `{}` in {value:?}", segments[i].spec.id())
417 };
418 }
419 let mut ans = String::with_capacity(len);
420 let mut concatenate = |s: &str| {
421 let skip_slash = matches!(ans.as_bytes().last(), None | Some(b'/'))
422 && s.as_bytes().first() == Some(&b'/');
423 ans += &s[skip_slash as usize..];
424 };
425 for i in 0..values.len() {
426 concatenate(segments[i].prefix);
427 if let Some((start, end)) = values[i] {
428 let end = end.get();
429 concatenate(&value.buffer[start as usize..end as usize])
430 } else if let Some(default) = segments[i].spec.default() {
431 concatenate(default)
432 } else {
433 unsafe { core::hint::unreachable_unchecked() }
435 };
436 }
437 concatenate(value.format.suffix);
438 if ans.ends_with('/') {
439 ans.pop();
440 }
441 OwnedKeyExpr::autocanonize(ans)
442 }
443}
444impl<'s, Storage: IKeFormatStorage<'s>> TryFrom<&mut KeFormatter<'s, Storage>> for OwnedKeyExpr {
445 type Error = Error;
446
447 fn try_from(value: &mut KeFormatter<'s, Storage>) -> Result<Self, Self::Error> {
448 (&*value).try_into()
449 }
450}
451
452#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
453pub enum FormatSetError {
454 InvalidId,
455 PatternNotMatched,
456}
457impl core::fmt::Display for FormatSetError {
458 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
459 write!(f, "{self:?}")
460 }
461}
462impl IError for FormatSetError {}
463impl<'s, Storage: IKeFormatStorage<'s>> KeFormatter<'s, Storage> {
464 pub fn format(&self) -> &KeFormat<'s, Storage> {
466 self.format
467 }
468
469 pub fn clear(&mut self) -> &mut Self {
471 self.buffer.clear();
472 for value in self.values.as_mut() {
473 *value = None
474 }
475 self
476 }
477
478 pub fn build(&self) -> ZResult<OwnedKeyExpr> {
483 self.try_into()
484 }
485 pub fn get(&self, id: &str) -> Option<&str> {
487 let segments = self.format.storage.segments();
488 segments
489 .iter()
490 .position(|s| s.spec.id() == id)
491 .and_then(|i| {
492 self.values.as_ref()[i]
493 .map(|(start, end)| &self.buffer[start as usize..end.get() as usize])
494 })
495 }
496 pub fn set<S: Display>(&mut self, id: &str, value: S) -> Result<&mut Self, FormatSetError> {
503 use core::fmt::Write;
504 let segments = self.format.storage.segments();
505 let Some(i) = segments.iter().position(|s| s.spec.id() == id) else {
506 return Err(FormatSetError::InvalidId);
507 };
508 let values = self.values.as_mut();
509 if let Some((start, end)) = values[i].take() {
510 let end = end.get();
511 let shift = end - start;
512 self.buffer.replace_range(start as usize..end as usize, "");
513 for (s, e) in values.iter_mut().flatten() {
514 if *s < start {
515 continue;
516 }
517 *s -= shift;
518 *e = NonMaxU32::new(e.get() - shift).unwrap()
519 }
520 }
521 let pattern = segments[i].spec.pattern();
522 let start = self.buffer.len();
523 write!(&mut self.buffer, "{value}").unwrap(); let mut set_value = || {
525 let end = self.buffer.len();
526 if start == end {
527 if !pattern.is_double_wild() {
528 return Err(());
529 }
530 } else {
531 let Ok(ke) = keyexpr::new(&self.buffer[start..end]) else {
532 return Err(());
533 };
534 if !pattern.includes(ke) {
535 return Err(());
536 }
537 }
538
539 values[i] = Some((
540 start as u32,
541 NonMaxU32::new(end.try_into().map_err(|_| ())?).ok_or(())?,
542 ));
543 Ok(())
544 };
545 match set_value() {
546 Ok(()) => Ok(self),
547 Err(()) => {
548 self.buffer.truncate(start);
549 Err(FormatSetError::PatternNotMatched)
550 }
551 }
552 }
553}
554
555pub struct OwnedKeFormat<Storage: IKeFormatStorage<'static> + 'static = Vec<Segment<'static>>> {
557 _owner: Box<str>,
558 format: KeFormat<'static, Storage>,
559}
560impl<Storage: IKeFormatStorage<'static> + 'static> core::ops::Deref for OwnedKeFormat<Storage> {
561 type Target = KeFormat<'static, Storage>;
562 fn deref(&self) -> &Self::Target {
563 &self.format
564 }
565}
566impl<Storage: IKeFormatStorage<'static> + 'static> TryFrom<Box<str>> for OwnedKeFormat<Storage> {
567 type Error = <KeFormat<'static, Storage> as TryFrom<&'static str>>::Error;
568 fn try_from(value: Box<str>) -> Result<Self, Self::Error> {
569 let owner = value;
570 let format: KeFormat<'static, Storage> = unsafe {
572 core::mem::transmute::<&str, &'static str>(&owner)
574 }
575 .try_into()?;
576 Ok(Self {
577 _owner: owner,
578 format,
579 })
580 }
581}
582impl<Storage: IKeFormatStorage<'static> + 'static> TryFrom<String> for OwnedKeFormat<Storage> {
583 type Error = <KeFormat<'static, Storage> as TryFrom<&'static str>>::Error;
584 fn try_from(value: String) -> Result<Self, Self::Error> {
585 value.into_boxed_str().try_into()
586 }
587}
588impl<Storage: IKeFormatStorage<'static> + 'static> core::str::FromStr for OwnedKeFormat<Storage> {
589 type Err = <KeFormat<'static, Storage> as TryFrom<&'static str>>::Error;
590 fn from_str(s: &str) -> Result<Self, Self::Err> {
591 Box::<str>::from(s).try_into()
592 }
593}
594impl<'s, S1: IKeFormatStorage<'s> + 's, S2: IKeFormatStorage<'s> + 's> PartialEq<KeFormat<'s, S2>>
595 for KeFormat<'s, S1>
596{
597 fn eq(&self, other: &KeFormat<'s, S2>) -> bool {
598 self.suffix == other.suffix && self.storage.segments() == other.storage.segments()
599 }
600}
601
602#[test]
603fn formatting() {
604 let format = KeFormat::new("a/${a:*}/b/$#{b:**}#/c").unwrap();
605 assert_eq!(format.storage[0].prefix, "a/");
606 assert_eq!(format.storage[0].spec.id(), "a");
607 assert_eq!(format.storage[0].spec.pattern(), "*");
608 assert_eq!(format.storage[1].prefix, "/b/");
609 assert_eq!(format.storage[1].spec.id(), "b");
610 assert_eq!(format.storage[1].spec.pattern(), "**");
611 assert_eq!(format.suffix, "/c");
612 let ke: OwnedKeyExpr = format
613 .formatter()
614 .set("a", 1)
615 .unwrap()
616 .set("b", "hi/there")
617 .unwrap()
618 .try_into()
619 .unwrap();
620 assert_eq!(ke.as_str(), "a/1/b/hi/there/c");
621 let ke: OwnedKeyExpr = format
622 .formatter()
623 .set("a", 1)
624 .unwrap()
625 .set("b", "")
626 .unwrap()
627 .try_into()
628 .unwrap();
629 assert_eq!(ke.as_str(), "a/1/b/c");
630}
631
632mod parsing;
633pub use parsing::{Iter, Parsed};