diff --git a/commons/zenoh-keyexpr/src/key_expr/format/mod.rs b/commons/zenoh-keyexpr/src/key_expr/format/mod.rs index 8dc5fb89a3..dbdf0e6446 100644 --- a/commons/zenoh-keyexpr/src/key_expr/format/mod.rs +++ b/commons/zenoh-keyexpr/src/key_expr/format/mod.rs @@ -387,13 +387,17 @@ impl<'s, Storage: IKeFormatStorage<'s>> KeFormatter<'s, Storage> { let Some(i) = segments.iter().position(|s| s.spec.id() == id) else { return Err(FormatSetError::InvalidId); }; - if let Some((start, end)) = self.values.as_ref()[i] { + let values = self.values.as_mut(); + if let Some((start, end)) = values[i].take() { let end = end.get(); let shift = end - start; self.buffer.replace_range(start as usize..end as usize, ""); - for (start, end) in self.values.as_mut()[(i + 1)..].iter_mut().flatten() { - *start -= shift; - *end = NonZeroU32::new(end.get() - shift).unwrap() + for (s, e) in values.iter_mut().flatten() { + if *s < start { + continue; + } + *s -= shift; + *e = NonZeroU32::new(e.get() - shift).unwrap() } } let pattern = segments[i].spec.pattern(); @@ -401,18 +405,18 @@ impl<'s, Storage: IKeFormatStorage<'s>> KeFormatter<'s, Storage> { write!(&mut self.buffer, "{value}").unwrap(); // Writing on `&mut String` should be infallible. match (|| { let end = self.buffer.len(); - if !(end == start && pattern.as_str() == "**") { + if pattern.as_str() != "**" { let Ok(ke) = keyexpr::new(&self.buffer[start..end]) else { return Err(()); }; - if end > u32::MAX as usize || !pattern.includes(ke) { + if !pattern.includes(ke) { return Err(()); } } - self.values.as_mut()[i] = Some((start as u32, unsafe { - // `end` must be >0 for self.buffer[start..end] to be a keyexpr - NonZeroU32::new_unchecked(end as u32) - })); + values[i] = Some(( + start as u32, + NonZeroU32::new(end.try_into().map_err(|_| ())?).ok_or(())?, + )); Ok(()) })() { Ok(()) => Ok(self), diff --git a/commons/zenoh-keyexpr/src/key_expr/include.rs b/commons/zenoh-keyexpr/src/key_expr/include.rs index ed54369c20..46a4e40d69 100644 --- a/commons/zenoh-keyexpr/src/key_expr/include.rs +++ b/commons/zenoh-keyexpr/src/key_expr/include.rs @@ -47,7 +47,10 @@ impl Includer<&[u8], &[u8]> for LTRIncluder { } } else { let (rchunk, rrest) = right.split_once(&DELIMITER); - if rchunk.is_empty() || !self.non_double_wild_chunk_includes(lchunk, rchunk) { + if rchunk.is_empty() + || rchunk == DOUBLE_WILD + || !self.non_double_wild_chunk_includes(lchunk, rchunk) + { return false; } let rempty = rrest.is_empty(); diff --git a/zenoh/tests/formatters.rs b/zenoh/tests/formatters.rs new file mode 100644 index 0000000000..ae894e44b6 --- /dev/null +++ b/zenoh/tests/formatters.rs @@ -0,0 +1,23 @@ +#[test] +fn reuse() { + zenoh::kedefine!( + pub gkeys: "zenoh/${group:*}/${member:*}", + ); + let mut formatter = gkeys::formatter(); + let k1 = zenoh::keformat!(formatter, group = "foo", member = "bar").unwrap(); + assert_eq!(dbg!(k1).as_str(), "zenoh/foo/bar"); + + formatter.set("member", "*").unwrap(); + let k2 = formatter.build().unwrap(); + assert_eq!(dbg!(k2).as_str(), "zenoh/foo/*"); + + dbg!(&mut formatter).group("foo").unwrap(); + dbg!(&mut formatter).member("*").unwrap(); + let k2 = dbg!(&mut formatter).build().unwrap(); + assert_eq!(dbg!(k2).as_str(), "zenoh/foo/*"); + + let k3 = zenoh::keformat!(formatter, group = "foo", member = "*").unwrap(); + assert_eq!(dbg!(k3).as_str(), "zenoh/foo/*"); + + zenoh::keformat!(formatter, group = "**", member = "**").unwrap_err(); +}