From 087527ef12a353c5b4023b242c31c715f5369a14 Mon Sep 17 00:00:00 2001 From: Sam Privett Date: Sun, 13 Nov 2022 15:30:52 -0800 Subject: [PATCH] Extend string types (#293) --- rosidl_runtime_rs/src/string.rs | 132 +++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 21 deletions(-) diff --git a/rosidl_runtime_rs/src/string.rs b/rosidl_runtime_rs/src/string.rs index 201889a9..44043a60 100644 --- a/rosidl_runtime_rs/src/string.rs +++ b/rosidl_runtime_rs/src/string.rs @@ -126,21 +126,6 @@ macro_rules! string_impl { ) -> bool; } - impl Default for $string { - fn default() -> Self { - let mut msg = Self { - data: std::ptr::null_mut(), - size: 0, - capacity: 0, - }; - // SAFETY: Passing in a zeroed string is safe. - if !unsafe { $init(&mut msg as *mut _) } { - panic!("Sinit failed"); - } - msg - } - } - impl Clone for $string { fn clone(&self) -> Self { let mut msg = Self::default(); @@ -158,6 +143,21 @@ macro_rules! string_impl { } } + impl Default for $string { + fn default() -> Self { + let mut msg = Self { + data: std::ptr::null_mut(), + size: 0, + capacity: 0, + }; + // SAFETY: Passing in a zeroed string is safe. + if !unsafe { $init(&mut msg as *mut _) } { + panic!("$init failed"); + } + msg + } + } + // It's not guaranteed that there are no interior null bytes, hence no Deref to CStr. // This does not include the null byte at the end! impl Deref for $string { @@ -200,15 +200,39 @@ macro_rules! string_impl { impl Eq for $string {} - impl Hash for $string { - fn hash(&self, state: &mut H) { - self.deref().hash(state) + impl Extend for $string { + fn extend>(&mut self, iter: I) { + let mut s = self.to_string(); + s.extend(iter); + *self = Self::from(s.as_str()); } } - impl PartialEq for $string { - fn eq(&self, other: &Self) -> bool { - self.deref().eq(other.deref()) + impl<'a> Extend<&'a char> for $string { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } + } + + impl FromIterator for $string { + fn from_iter>(iter: I) -> Self { + let mut buf = <$string>::default(); + buf.extend(iter); + buf + } + } + + impl<'a> FromIterator<&'a char> for $string { + fn from_iter>(iter: I) -> Self { + let mut buf = <$string>::default(); + buf.extend(iter); + buf + } + } + + impl Hash for $string { + fn hash(&self, state: &mut H) { + self.deref().hash(state) } } @@ -218,6 +242,12 @@ macro_rules! string_impl { } } + impl PartialEq for $string { + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } + } + impl PartialOrd for $string { fn partial_cmp(&self, other: &Self) -> Option { self.deref().partial_cmp(other.deref()) @@ -503,4 +533,64 @@ mod tests { s.as_str().try_into().unwrap() } } + + #[test] + fn string_from_char_iterator() { + // Base char case + let expected = String::from("abc"); + let actual = "abc".chars().collect::(); + + assert_eq!(expected, actual); + + // Empty case + let expected = String::from(""); + let actual = "".chars().collect::(); + + assert_eq!(expected, actual); + + // Non-ascii char case + let expected = String::from("Grüß Gott! 𝕊"); + let actual = "Grüß Gott! 𝕊".chars().collect::(); + + assert_eq!(expected, actual); + } + + #[test] + fn extend_string_with_char_iterator() { + let expected = WString::from("abcdef"); + let mut actual = WString::from("abc"); + actual.extend("def".chars()); + + assert_eq!(expected, actual); + } + + #[test] + fn wstring_from_char_iterator() { + // Base char case + let expected = WString::from("abc"); + let actual = "abc".chars().collect::(); + + assert_eq!(expected, actual); + + // Empty case + let expected = WString::from(""); + let actual = "".chars().collect::(); + + assert_eq!(expected, actual); + + // Non-ascii char case + let expected = WString::from("Grüß Gott! 𝕊"); + let actual = "Grüß Gott! 𝕊".chars().collect::(); + + assert_eq!(expected, actual); + } + + #[test] + fn extend_wstring_with_char_iterator() { + let expected = WString::from("abcdef"); + let mut actual = WString::from("abc"); + actual.extend("def".chars()); + + assert_eq!(expected, actual); + } }