rclrust_msg_core/
string.rs

1use std::{
2    ffi::{CStr, CString},
3    mem::ManuallyDrop,
4    os::raw::c_char,
5};
6
7use crate::ffi::uint_least16_t;
8use crate::traits::{FFIFromRust, FFIToRust, ZeroInit};
9
10/// An array of 8-bit characters terminated by a null character.
11#[repr(C)]
12#[derive(Debug)]
13pub struct FFIString {
14    data: *mut c_char,
15    size: usize,
16    capacity: usize,
17}
18
19impl FFIString {
20    /// Returns the length of the string (excluding the null byte)
21    pub const fn len(&self) -> usize {
22        self.size
23    }
24
25    /// Returns `true` if the string has a length of 0.
26    pub const fn is_empty(&self) -> bool {
27        self.len() == 0
28    }
29}
30
31impl ZeroInit for FFIString {
32    fn zero_init() -> Self {
33        Self {
34            data: std::ptr::null_mut(),
35            size: 0,
36            capacity: 0,
37        }
38    }
39}
40
41impl FFIToRust for FFIString {
42    type Target = String;
43
44    fn to_rust(&self) -> Self::Target {
45        if self.is_empty() {
46            "".to_string()
47        } else {
48            unsafe { CStr::from_ptr(self.data) }
49                .to_str()
50                .expect("CStr::to_str failed")
51                .to_string()
52        }
53    }
54}
55
56#[repr(C)]
57#[derive(Debug)]
58pub struct OwnedFFIString {
59    data: *mut c_char,
60    size: usize,
61    capacity: usize,
62}
63
64impl OwnedFFIString {
65    /// Returns the length of the string (excluding the null byte)
66    pub const fn len(&self) -> usize {
67        self.size
68    }
69
70    /// Returns `true` if the string has a length of 0.
71    pub const fn is_empty(&self) -> bool {
72        self.len() == 0
73    }
74}
75
76impl ZeroInit for OwnedFFIString {
77    fn zero_init() -> Self {
78        Self {
79            data: std::ptr::null_mut(),
80            size: 0,
81            capacity: 0,
82        }
83    }
84}
85
86impl FFIFromRust for OwnedFFIString {
87    type From = String;
88
89    unsafe fn from_rust(string: &Self::From) -> Self {
90        let cstring = CString::new(string.clone()).expect("CString::new failed");
91        let len = cstring.as_bytes().len();
92        Self {
93            data: cstring.into_raw(),
94            size: len,
95            capacity: len + 1,
96        }
97    }
98}
99
100impl Drop for OwnedFFIString {
101    fn drop(&mut self) {
102        unsafe {
103            CString::from_raw(self.data);
104        }
105    }
106}
107
108/// An array of 16-bit characters terminated by a null character.  <br>
109/// *Is it better to be compatible with some crates supporting wide string?*
110#[repr(C)]
111#[derive(Debug)]
112pub struct FFIWString {
113    data: *mut uint_least16_t,
114    size: usize,
115    capacity: usize,
116}
117
118impl FFIWString {
119    /// Returns the length of the string (excluding the null byte)
120    pub const fn len(&self) -> usize {
121        self.size
122    }
123
124    /// Returns `true` if the sequence has a length of 0.
125    pub const fn is_empty(&self) -> bool {
126        self.len() == 0
127    }
128}
129
130impl ZeroInit for FFIWString {
131    fn zero_init() -> Self {
132        Self {
133            data: std::ptr::null_mut(),
134            size: 0,
135            capacity: 0,
136        }
137    }
138}
139
140impl FFIToRust for FFIWString {
141    type Target = Vec<u16>;
142
143    fn to_rust(&self) -> Self::Target {
144        unsafe { std::slice::from_raw_parts(self.data, self.len()) }
145            .iter()
146            .map(|&v| v as u16)
147            .collect::<Vec<_>>()
148    }
149}
150
151#[repr(C)]
152#[derive(Debug)]
153pub struct OwnedFFIWString {
154    data: *mut uint_least16_t,
155    size: usize,
156    capacity: usize,
157}
158
159impl OwnedFFIWString {
160    /// Returns the length of the string (excluding the null byte)
161    pub const fn len(&self) -> usize {
162        self.size
163    }
164
165    /// Returns `true` if the sequence has a length of 0.
166    pub const fn is_empty(&self) -> bool {
167        self.len() == 0
168    }
169}
170
171impl ZeroInit for OwnedFFIWString {
172    fn zero_init() -> Self {
173        Self {
174            data: std::ptr::null_mut(),
175            size: 0,
176            capacity: 0,
177        }
178    }
179}
180
181impl FFIFromRust for OwnedFFIWString {
182    type From = Vec<u16>;
183
184    unsafe fn from_rust(string: &Self::From) -> Self {
185        let mut string = string.clone();
186        string.push(0);
187        string.shrink_to_fit();
188        assert_eq!(string.len(), string.capacity());
189        let mut string = ManuallyDrop::new(string);
190        Self {
191            data: string.as_mut_ptr(),
192            size: string.len() - 1,
193            capacity: string.len(),
194        }
195    }
196}
197
198impl Drop for OwnedFFIWString {
199    fn drop(&mut self) {
200        unsafe { Vec::from_raw_parts(self.data, self.capacity, self.capacity) };
201    }
202}