dora_ros2_bridge/_core/
string.rs1use std::{
2 ffi::{CStr, CString},
3 ops::{Deref, DerefMut},
4 os::raw::c_char,
5};
6
7use widestring::{U16CStr, U16CString};
8
9use super::traits::{FFIFromRust, FFIToRust};
10
11#[derive(
12 Debug,
13 Default,
14 Clone,
15 PartialEq,
16 Eq,
17 PartialOrd,
18 Ord,
19 Hash,
20 serde::Serialize,
21 serde::Deserialize,
22)]
23#[serde(from = "Vec<u16>", into = "Vec<u16>")]
24#[repr(transparent)]
25pub struct U16String(widestring::U16String);
26
27impl U16String {
28 pub fn new() -> Self {
29 Self(widestring::U16String::new())
30 }
31
32 #[allow(clippy::should_implement_trait)]
33 pub fn from_str(arg: &str) -> U16String {
34 Self(widestring::U16String::from_str(arg))
35 }
36}
37
38impl Deref for U16String {
39 type Target = widestring::U16String;
40
41 fn deref(&self) -> &Self::Target {
42 &self.0
43 }
44}
45
46impl DerefMut for U16String {
47 fn deref_mut(&mut self) -> &mut Self::Target {
48 &mut self.0
49 }
50}
51
52impl AsRef<widestring::U16Str> for U16String {
53 fn as_ref(&self) -> &widestring::U16Str {
54 self.0.as_ref()
55 }
56}
57
58impl From<U16String> for Vec<u16> {
59 fn from(value: U16String) -> Self {
60 value.0.into_vec()
61 }
62}
63
64impl From<Vec<u16>> for U16String {
65 fn from(value: Vec<u16>) -> Self {
66 Self(value.into())
67 }
68}
69
70#[repr(C)]
72#[derive(Debug)]
73pub struct FFIString {
74 data: *mut c_char,
75 size: usize,
76 capacity: usize,
77}
78
79impl FFIString {
80 pub const fn len(&self) -> usize {
82 self.size
83 }
84
85 pub const fn is_empty(&self) -> bool {
87 self.len() == 0
88 }
89
90 pub unsafe fn to_str(&self) -> Result<&str, std::str::Utf8Error> {
91 if self.is_empty() {
92 Ok("")
93 } else {
94 unsafe { CStr::from_ptr(self.data).to_str() }
95 }
96 }
97}
98
99impl FFIToRust for FFIString {
100 type Target = String;
101
102 unsafe fn to_rust(&self) -> Self::Target {
103 unsafe { self.to_str().expect("CStr::to_str failed").to_string() }
104 }
105}
106
107#[repr(C)]
108#[derive(Debug)]
109pub struct OwnedFFIString {
110 data: *mut c_char,
111 size: usize,
112 capacity: usize,
113}
114
115impl OwnedFFIString {
116 pub const fn len(&self) -> usize {
118 self.size
119 }
120
121 pub const fn is_empty(&self) -> bool {
123 self.len() == 0
124 }
125}
126
127impl FFIFromRust for OwnedFFIString {
128 type From = String;
129
130 unsafe fn from_rust(string: &Self::From) -> Self {
131 let cstring = CString::new(string.clone()).expect("CString::new failed");
132 let len = cstring.as_bytes().len();
133 Self {
134 data: cstring.into_raw(),
135 size: len,
136 capacity: len + 1,
137 }
138 }
139}
140
141impl Drop for OwnedFFIString {
142 fn drop(&mut self) {
143 unsafe {
144 std::mem::drop(CString::from_raw(self.data));
145 }
146 }
147}
148
149#[repr(C)]
151#[derive(Debug)]
152pub struct FFIWString {
153 data: *mut u16,
154 size: usize,
155 capacity: usize,
156}
157
158impl FFIWString {
159 pub const fn len(&self) -> usize {
161 self.size
162 }
163
164 pub const fn is_empty(&self) -> bool {
166 self.len() == 0
167 }
168}
169
170impl FFIToRust for FFIWString {
171 type Target = U16String;
172
173 unsafe fn to_rust(&self) -> Self::Target {
174 if self.is_empty() {
175 Self::Target::new()
176 } else {
177 U16String(unsafe { U16CStr::from_ptr_str(self.data).to_ustring() })
178 }
179 }
180}
181
182#[repr(C)]
183#[derive(Debug)]
184pub struct OwnedFFIWString {
185 data: *mut u16,
186 size: usize,
187 capacity: usize,
188}
189
190impl OwnedFFIWString {
191 pub const fn len(&self) -> usize {
193 self.size
194 }
195
196 pub const fn is_empty(&self) -> bool {
198 self.len() == 0
199 }
200}
201
202impl FFIFromRust for OwnedFFIWString {
203 type From = U16String;
204
205 unsafe fn from_rust(string: &Self::From) -> Self {
206 let cstring = U16CString::from_ustr(string).expect("U16CString::new failed");
207 let len = cstring.len();
208 Self {
209 data: cstring.into_raw(),
210 size: len,
211 capacity: len + 1,
212 }
213 }
214}
215
216impl Drop for OwnedFFIWString {
217 fn drop(&mut self) {
218 unsafe {
219 std::mem::drop(U16CString::from_raw(self.data));
220 }
221 }
222}
223
224#[cfg(test)]
225mod test {
226 use super::*;
227
228 #[test]
229 fn owned_ffi_string_new() {
230 let string = "abcde".into();
231 let cstring = unsafe { OwnedFFIString::from_rust(&string) };
232 let native_string = FFIString {
233 data: cstring.data,
234 size: cstring.size,
235 capacity: cstring.capacity,
236 };
237
238 assert_eq!(string, unsafe { native_string.to_rust() });
239 }
240
241 #[test]
242 fn owned_ffi_wstring_new() {
243 let wstring = U16String::from_str("あいうえお");
244 let cwstring = unsafe { OwnedFFIWString::from_rust(&wstring) };
245 let native_wstring = FFIWString {
246 data: cwstring.data,
247 size: cwstring.size,
248 capacity: cwstring.capacity,
249 };
250
251 assert_eq!(wstring, unsafe { native_wstring.to_rust() });
252 }
253}