Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 106 additions & 5 deletions rosidl_runtime_rs/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::ffi::CStr;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::ptr;
Comment thread
maspe36 marked this conversation as resolved.
Outdated
use std::ptr::slice_from_raw_parts;

#[cfg(feature = "serde")]
mod serde;
Expand Down Expand Up @@ -135,7 +137,7 @@ macro_rules! string_impl {
};
// SAFETY: Passing in a zeroed string is safe.
if !unsafe { $init(&mut msg as *mut _) } {
panic!("Sinit failed");
panic!("$init failed");
Comment thread
maspe36 marked this conversation as resolved.
Outdated
}
msg
}
Expand Down Expand Up @@ -224,10 +226,47 @@ macro_rules! string_impl {
}
}

impl FromIterator<char> for $string {
fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
let mut buf = <$string>::default();
buf.extend(iter);
buf
}
}

impl<'a> FromIterator<&'a char> for $string {
fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> Self {
let mut buf = <$string>::default();
buf.extend(iter);
buf
}
}

impl Extend<char> for $string {
Comment thread
maspe36 marked this conversation as resolved.
Outdated
fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
let mut v = self.to_vec();
let iterator = iter.into_iter();

iterator.for_each(|c| {
v.push(c as $char_type);
});

// SAFETY: It's okay to pass a non-zero-terminated string here since assignn
// uses the specified length and will append the 0 to the dest string itself.
if !unsafe { $assignn(self as *mut _, v.as_ptr() as *const _, v.len()) } {
panic!("$assignn failed");
}
}
Comment thread
maspe36 marked this conversation as resolved.
Outdated
}

impl<'a> Extend<&'a char> for $string {
fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
}

// SAFETY: A string is a simple data structure, and therefore not thread-specific.
unsafe impl Send for $string {}
// SAFETY: A string does not have interior mutability, so it can be shared.
unsafe impl Sync for $string {}

impl SequenceAlloc for $string {
fn sequence_init(seq: &mut Sequence<Self>, size: usize) -> bool {
Expand All @@ -243,6 +282,20 @@ macro_rules! string_impl {
unsafe { $sequence_copy(in_seq as *const _, out_seq as *mut _) }
}
}

impl $string {
/// Returns a copy of `self` as a vector without the trailing null byte.
pub fn to_vec(&self) -> Vec<$char_type> {
let mut v: Vec<$char_type> = vec![];

// SAFETY: self.data points to self.size consecutive, initialized elements and
// isn't modified externally.
let s = unsafe { slice_from_raw_parts(self.data, self.size).as_ref() };
v.extend_from_slice(s.unwrap());

v
}
}
};
}

Expand Down Expand Up @@ -274,7 +327,7 @@ string_impl!(
impl From<&str> for String {
fn from(s: &str) -> Self {
let mut msg = Self {
data: std::ptr::null_mut(),
data: ptr::null_mut(),
size: 0,
capacity: 0,
};
Expand Down Expand Up @@ -304,7 +357,7 @@ impl String {
impl From<&str> for WString {
fn from(s: &str) -> Self {
let mut msg = Self {
data: std::ptr::null_mut(),
data: ptr::null_mut(),
size: 0,
capacity: 0,
};
Expand Down Expand Up @@ -503,4 +556,52 @@ 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::<String>();

assert_eq!(expected, actual);

// Empty case
let expected = String::from("");
let actual = "".chars().collect::<String>();

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::<WString>();

assert_eq!(expected, actual);

// Empty case
let expected = WString::from("");
let actual = "".chars().collect::<WString>();

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);
}
}