Skip to content

Commit 7a07fe6

Browse files
nwnesteve
authored andcommitted
Fix Unicode handling in String and WString (#362)
According to https://design.ros2.org/articles/wide_strings.html, the `string` and `wstring` types must use the UTF-8 and UTF-16 encodings (not necessarily enforced), cannot contain null bytes or words (enforced), and, when bounded, are measured in terms of bytes or words. Moreover, though the rosidl_runtime_c `U16String` type uses `uint_least16_t`, Rust guarantees the existence of a precise `u16` type, so we should use that instead of `ushort`, which isn't guaranteed to be the same as `uint_least16_t` either. (Rust doesn't support platforms where `uint_least16_t != uint16_t`.)
1 parent b8c84b8 commit 7a07fe6

File tree

1 file changed

+13
-15
lines changed

1 file changed

+13
-15
lines changed

rosidl_runtime_rs/src/string.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mod serde;
1010
use crate::sequence::Sequence;
1111
use crate::traits::SequenceAlloc;
1212

13-
/// A zero-terminated string of 8-bit characters.
13+
/// A zero-terminated UTF-8 string.
1414
///
1515
/// The layout of this type is the same as `rosidl_runtime_c__String`. See the
1616
/// [`Message`](crate::Message) trait for background information on this topic.
@@ -34,7 +34,7 @@ pub struct String {
3434
capacity: usize,
3535
}
3636

37-
/// A zero-terminated string of 16-bit characters.
37+
/// A zero-terminated UTF-16 string.
3838
///
3939
/// The layout of this type is the same as `rosidl_runtime_c__U16String`. See the
4040
/// [`Message`](crate::Message) trait for background information on this topic.
@@ -50,15 +50,15 @@ pub struct String {
5050
/// ```
5151
#[repr(C)]
5252
pub struct WString {
53-
data: *mut std::os::raw::c_ushort,
53+
data: *mut u16,
5454
size: usize,
5555
capacity: usize,
5656
}
5757

58-
/// A zero-terminated string of 8-bit characters with a length limit.
58+
/// A zero-terminated UTF-8 string with a length limit.
5959
///
6060
/// The same as [`String`], but it cannot be constructed from a string that is too large.
61-
/// The length is measured as the number of Unicode scalar values, not bytes.
61+
/// The length is measured as the number of bytes.
6262
///
6363
/// # Example
6464
///
@@ -77,10 +77,10 @@ pub struct BoundedString<const N: usize> {
7777
inner: String,
7878
}
7979

80-
/// A zero-terminated string of 16-bit characters with a length limit.
80+
/// A zero-terminated UTF-16 string with a length limit.
8181
///
8282
/// The same as [`WString`], but it cannot be constructed from a string that is too large.
83-
/// The length is measured as the number of Unicode scalar values, not bytes.
83+
/// The length is measured as the number of 16-bit words.
8484
///
8585
/// # Example
8686
///
@@ -290,7 +290,7 @@ string_impl!(
290290
);
291291
string_impl!(
292292
WString,
293-
std::os::raw::c_ushort,
293+
u16,
294294
u16,
295295
from_utf16_lossy,
296296
rosidl_runtime_c__U16String__init,
@@ -406,7 +406,7 @@ impl<const N: usize> SequenceAlloc for BoundedString<N> {
406406
impl<const N: usize> TryFrom<&str> for BoundedString<N> {
407407
type Error = StringExceedsBoundsError;
408408
fn try_from(s: &str) -> Result<Self, Self::Error> {
409-
let length = s.chars().count();
409+
let length = s.len();
410410
if length <= N {
411411
Ok(Self {
412412
inner: String::from(s),
@@ -472,14 +472,12 @@ impl<const N: usize> SequenceAlloc for BoundedWString<N> {
472472
impl<const N: usize> TryFrom<&str> for BoundedWString<N> {
473473
type Error = StringExceedsBoundsError;
474474
fn try_from(s: &str) -> Result<Self, Self::Error> {
475-
let length = s.chars().count();
476-
if length <= N {
477-
Ok(Self {
478-
inner: WString::from(s),
479-
})
475+
let inner = WString::from(s);
476+
if inner.size <= N {
477+
Ok(Self { inner })
480478
} else {
481479
Err(StringExceedsBoundsError {
482-
len: length,
480+
len: inner.size,
483481
upper_bound: N,
484482
})
485483
}

0 commit comments

Comments
 (0)