1use libc::{c_char, strlen};
4#[cfg(feature = "stable_deref_trait")]
5use stable_deref_trait::StableDeref;
6
7use std::borrow::{Borrow, BorrowMut};
8use std::convert::{AsMut, AsRef};
9use std::default::Default;
10#[cfg(feature = "std")]
11use std::ffi::CStr;
12use std::hash::{Hash, Hasher};
13use std::iter::once;
14use std::ops::{Deref, DerefMut};
15use std::ptr::{copy_nonoverlapping, null, null_mut, write};
16use std::str::Utf8Error;
17
18use crate::internal::gen_malloc;
19use crate::mbox::MBox;
20
21#[cfg(all(test, not(windows)))]
22use crate::internal::DropCounter;
23
24pub trait Sentinel: Eq {
26 const SENTINEL: Self;
28}
29
30impl<T> Sentinel for *const T {
31 const SENTINEL: Self = null();
32}
33
34impl<T> Sentinel for *mut T {
35 const SENTINEL: Self = null_mut();
36}
37
38impl<T: Eq> Sentinel for Option<T> {
39 const SENTINEL: Self = None;
40}
41
42macro_rules! impl_zero_for_sentinel {
43 ($($ty:ty)+) => {
44 $(impl Sentinel for $ty {
45 const SENTINEL: Self = 0;
46 })+
47 }
48}
49
50impl_zero_for_sentinel!(u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize);
51
52#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
54pub struct MArray<T: Sentinel>(MBox<[T]>);
55
56#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
58pub struct MString(MBox<str>);
59
60impl<T: Sentinel> MArray<T> {
61 pub unsafe fn from_raw(base: *mut T) -> MArray<T> {
70 let mut len = 0;
71 while *base.add(len) != T::SENTINEL {
72 len += 1;
73 }
74 MArray(MBox::from_raw_parts(base, len + 1))
75 }
76
77 pub fn into_mbox_with_sentinel(self) -> MBox<[T]> {
79 self.0
80 }
81
82 pub fn into_mbox(self) -> MBox<[T]> {
84 let (ptr, len) = self.0.into_raw_parts();
85 unsafe { MBox::from_raw_parts(ptr, len - 1) }
86 }
87}
88
89impl<T: Sentinel + Clone> MArray<T> {
90 pub fn from_slice(slice: &[T]) -> MArray<T> {
92 MArray(slice.iter().cloned().chain(once(T::SENTINEL)).collect())
93 }
94}
95
96impl MString {
97 pub unsafe fn from_raw_unchecked(base: *mut c_char) -> MString {
108 let len = strlen(base);
109 MString(MBox::from_raw_utf8_parts_unchecked(
110 base as *mut u8,
111 len + 1,
112 ))
113 }
114
115 pub unsafe fn from_raw(base: *mut c_char) -> Result<MString, Utf8Error> {
125 let len = strlen(base);
126 let mbox = MBox::from_raw_utf8_parts(base as *mut u8, len + 1)?;
127 Ok(MString(mbox))
128 }
129
130 pub fn into_bytes(self) -> MArray<u8> {
131 MArray(self.0.into_bytes())
132 }
133
134 pub fn into_mbox_with_sentinel(self) -> MBox<str> {
136 self.0
137 }
138
139 pub fn into_mbox(self) -> MBox<str> {
141 unsafe { MBox::from_utf8_unchecked(self.into_bytes().into_mbox()) }
142 }
143
144 #[cfg(all(feature = "std"))]
146 pub fn as_c_str(&self) -> &CStr {
147 unsafe { CStr::from_bytes_with_nul_unchecked(self.0.as_bytes()) }
148 }
149
150 pub fn as_bytes_with_sentinel(&self) -> &[u8] {
152 self.0.as_bytes()
153 }
154}
155
156impl From<&str> for MString {
157 fn from(string: &str) -> MString {
159 unsafe {
160 let len = string.len();
161 let ptr = gen_malloc(len + 1).as_ptr();
162 copy_nonoverlapping(string.as_ptr(), ptr, len);
163 write(ptr.add(len), 0);
164 MString(MBox::from_raw_utf8_parts_unchecked(ptr, len + 1))
165 }
166 }
167}
168
169impl<T: Sentinel> Deref for MArray<T> {
170 type Target = [T];
171 fn deref(&self) -> &[T] {
172 let actual_len = self.0.len() - 1;
173 &self.0[..actual_len]
174 }
175}
176
177impl Deref for MString {
178 type Target = str;
179 fn deref(&self) -> &str {
180 let actual_len = self.0.len() - 1;
181 &self.0[..actual_len]
182 }
183}
184
185#[cfg(feature = "stable_deref_trait")]
186unsafe impl<T: Sentinel> StableDeref for MArray<T> {}
187#[cfg(feature = "stable_deref_trait")]
188unsafe impl StableDeref for MString {}
189
190impl<T: Sentinel> DerefMut for MArray<T> {
191 fn deref_mut(&mut self) -> &mut [T] {
192 let actual_len = self.0.len() - 1;
193 &mut self.0[..actual_len]
194 }
195}
196
197#[allow(clippy::derive_hash_xor_eq)]
198impl Hash for MString {
199 fn hash<H: Hasher>(&self, state: &mut H) {
200 self.deref().hash(state);
201 }
202}
203
204#[allow(clippy::derive_hash_xor_eq)]
205impl<T: Sentinel + Hash> Hash for MArray<T> {
206 fn hash<H: Hasher>(&self, state: &mut H) {
207 self.deref().hash(state);
208 }
209}
210
211impl DerefMut for MString {
212 fn deref_mut(&mut self) -> &mut str {
213 let actual_len = self.0.len() - 1;
214 &mut self.0[..actual_len]
215 }
216}
217
218impl<T: Sentinel> Default for MArray<T> {
219 fn default() -> Self {
220 unsafe {
221 let arr = gen_malloc(1).as_ptr();
222 write(arr, T::SENTINEL);
223 MArray(MBox::from_raw_parts(arr, 1))
224 }
225 }
226}
227
228impl Default for MString {
229 fn default() -> Self {
230 unsafe {
231 let arr = gen_malloc(1).as_ptr();
232 write(arr, 0);
233 MString(MBox::from_raw_utf8_parts_unchecked(arr, 1))
234 }
235 }
236}
237
238impl<T: Sentinel> AsRef<[T]> for MArray<T> {
239 fn as_ref(&self) -> &[T] {
240 self
241 }
242}
243
244impl<T: Sentinel> AsMut<[T]> for MArray<T> {
245 fn as_mut(&mut self) -> &mut [T] {
246 self
247 }
248}
249
250impl<T: Sentinel> Borrow<[T]> for MArray<T> {
251 fn borrow(&self) -> &[T] {
252 self
253 }
254}
255
256impl<T: Sentinel> BorrowMut<[T]> for MArray<T> {
257 fn borrow_mut(&mut self) -> &mut [T] {
258 self
259 }
260}
261
262impl AsRef<str> for MString {
263 fn as_ref(&self) -> &str {
264 self
265 }
266}
267
268impl AsMut<str> for MString {
269 fn as_mut(&mut self) -> &mut str {
270 self
271 }
272}
273
274impl Borrow<str> for MString {
275 fn borrow(&self) -> &str {
276 self
277 }
278}
279
280impl BorrowMut<str> for MString {
281 fn borrow_mut(&mut self) -> &mut str {
282 self
283 }
284}
285
286#[cfg(feature = "std")]
287impl AsRef<CStr> for MString {
288 fn as_ref(&self) -> &CStr {
289 self.as_c_str()
290 }
291}
292
293#[test]
294fn test_array() {
295 unsafe {
296 let src = gen_malloc::<u8>(6).as_ptr();
297 *src.offset(0) = 56;
298 *src.offset(1) = 18;
299 *src.offset(2) = 200;
300 *src.offset(3) = 0;
301 *src.offset(4) = 105;
302 *src.offset(5) = 0;
303
304 let mut array = MArray::from_raw(src);
305 assert_eq!(&*array, &[56u8, 18, 200]);
306 array[1] = 19;
307 assert_eq!(*src.offset(1), 19);
308 }
309}
310
311#[cfg(not(windows))]
312#[test]
313fn test_array_with_drop() {
314 let counter = DropCounter::default();
315 unsafe {
316 let src = gen_malloc::<Option<DropCounter>>(3).as_ptr();
317 write(src.offset(0), Some(counter.clone()));
318 write(src.offset(1), Some(counter.clone()));
319 write(src.offset(2), None);
320
321 counter.assert_eq(0);
322 let array = MArray::from_raw(src);
323 assert_eq!(array.len(), 2);
324 array[0].as_ref().unwrap().assert_eq(0);
325 array[1].as_ref().unwrap().assert_eq(0);
326 }
327 counter.assert_eq(2);
328}
329
330#[test]
331fn test_string() {
332 unsafe {
333 let src = gen_malloc::<c_char>(5).as_ptr();
334 *src.offset(0) = 0x61;
335 *src.offset(1) = -0x19i8 as c_char;
336 *src.offset(2) = -0x6ci8 as c_char;
337 *src.offset(3) = -0x4ei8 as c_char;
338 *src.offset(4) = 0;
339
340 let string = MString::from_raw_unchecked(src);
341 assert_eq!(&*string, "a甲");
342 }
343}
344
345#[test]
346fn test_non_utf8_string() {
347 unsafe {
348 let src = gen_malloc::<c_char>(2).as_ptr();
349 *src.offset(0) = -1i8 as c_char;
350 *src.offset(1) = 0;
351
352 let string = MString::from_raw(src);
353 assert!(string.is_err());
354
355 let src2 = gen_malloc::<c_char>(2).as_ptr();
356 *src2.offset(0) = 1;
357 *src2.offset(1) = 0;
358
359 let string2 = MString::from_raw(src2);
360 assert_eq!(string2.unwrap().deref(), "\u{1}");
361 }
362}
363
364#[cfg(feature = "std")]
365#[test]
366fn test_c_str() {
367 unsafe {
368 let src = gen_malloc::<c_char>(2).as_ptr();
369 *src.offset(0) = 1;
370 *src.offset(1) = 0;
371 let string = MString::from_raw_unchecked(src);
372 let c_str = string.as_c_str();
373 assert_eq!(c_str, CStr::from_ptr(b"\x01\x00".as_ptr() as *const c_char));
374 }
375}
376
377#[cfg(not(windows))]
378#[test]
379fn test_array_into_mbox() {
380 let first = MArray::from_slice(&[123, 456, 789]);
381 let second = first.clone();
382
383 assert_eq!(&*first.into_mbox(), &[123, 456, 789]);
384 assert_eq!(&*second.into_mbox_with_sentinel(), &[123, 456, 789, 0]);
385}
386
387#[test]
388fn test_string_into_mbox() {
389 let first = MString::from("abcde");
390 let second = first.clone();
391
392 assert_eq!(first.as_bytes(), b"abcde");
393 assert_eq!(&*first.into_mbox(), "abcde");
394 assert_eq!(second.as_bytes_with_sentinel(), b"abcde\0");
395 assert_eq!(&*second.into_mbox_with_sentinel(), "abcde\0");
396}
397
398#[cfg(not(windows))]
399#[test]
400fn test_default_array() {
401 let arr = MArray::<u64>::default();
402 assert_eq!(arr.into_mbox_with_sentinel(), MBox::from_slice(&[0u64]));
403}
404
405#[test]
406fn test_default_string() {
407 let string = MString::default();
408 assert_eq!(string.into_mbox_with_sentinel(), MBox::<str>::from("\0"));
409}
410
411#[cfg(feature = "std")]
412#[test]
413fn test_hash_string() {
414 use std::collections::HashSet;
415
416 let mut hs: HashSet<MString> = HashSet::new();
417 hs.insert(MString::from("a"));
418 hs.insert(MString::from("bcd"));
419
420 let hs = hs;
421 assert!(hs.contains("bcd"));
422 assert!(!hs.contains("ef"));
423 assert!(!hs.contains("bcd\0"));
424 assert!(hs.contains("a"));
425 assert!(hs.contains(&MString::from("bcd")));
426 assert!(!hs.contains(&MString::from("ef")));
427 assert!(hs.contains(&MString::from("a")));
428}
429
430#[cfg(feature = "std")]
431#[test]
432fn test_hash_array() {
433 use std::collections::HashSet;
434
435 let mut hs: HashSet<MArray<u8>> = HashSet::new();
436 hs.insert(MArray::from_slice(b"a"));
437 hs.insert(MArray::from_slice(b"bcd"));
438
439 let hs = hs;
440 assert!(hs.contains(&b"bcd"[..]));
441 assert!(!hs.contains(&b"ef"[..]));
442 assert!(!hs.contains(&b"bcd\0"[..]));
443 assert!(hs.contains(&b"a"[..]));
444 assert!(hs.contains(&MArray::from_slice(b"bcd")));
445 assert!(!hs.contains(&MArray::from_slice(b"ef")));
446 assert!(hs.contains(&MArray::from_slice(b"a")));
447}