diplomat_runtime/
slices.rs

1use alloc::boxed::Box;
2use core::marker::PhantomData;
3use core::mem::ManuallyDrop;
4use core::ops::{Deref, DerefMut};
5use core::ptr::NonNull;
6
7/// This is equivalent to `&[T]`, except it has a stable `repr(C)` layout
8#[repr(C)]
9pub struct DiplomatSlice<'a, T> {
10    // Invariant: ptr is a valid ptr to the beginning of an &[T] allocation. It may be null if len is null
11    ptr: *const T,
12    // Invariant: the allocation contains at least `len` elements
13    len: usize,
14    phantom: PhantomData<&'a [T]>,
15}
16
17impl<T> Clone for DiplomatSlice<'_, T> {
18    fn clone(&self) -> Self {
19        *self
20    }
21}
22impl<T> Copy for DiplomatSlice<'_, T> {}
23
24impl<'a, T> From<&'a [T]> for DiplomatSlice<'a, T> {
25    fn from(x: &'a [T]) -> Self {
26        // Safe to construct since we're constructing it from a slice
27        DiplomatSlice {
28            ptr: x.as_ptr(),
29            len: x.len(),
30            phantom: PhantomData,
31        }
32    }
33}
34
35impl<'a, T> From<DiplomatSlice<'a, T>> for &'a [T] {
36    fn from(x: DiplomatSlice<'a, T>) -> Self {
37        unsafe {
38            // It's common in C-land to represent empty slices with NULL, which is not the case in Rust
39            // We normalize this
40            if x.ptr.is_null() {
41                debug_assert!(x.len == 0);
42                return &[];
43            }
44            // Safety: carrying over safety variants from DiplomatSlice, and we null-checked
45            core::slice::from_raw_parts(x.ptr, x.len)
46        }
47    }
48}
49
50impl<T> Deref for DiplomatSlice<'_, T> {
51    type Target = [T];
52    fn deref(&self) -> &[T] {
53        (*self).into()
54    }
55}
56
57/// This is equivalent to `&mut [T]`, except it has a stable repr(C) layout
58#[repr(C)]
59pub struct DiplomatSliceMut<'a, T> {
60    // Invariant: ptr is a valid ptr to the beginning of an &[T] allocation.  It may be null if len is null
61    ptr: *mut T,
62    // Invariant: the allocation contains at least `len` elements
63    len: usize,
64    phantom: PhantomData<&'a mut [T]>,
65}
66
67impl<'a, T> From<&'a mut [T]> for DiplomatSliceMut<'a, T> {
68    fn from(x: &'a mut [T]) -> Self {
69        // Safe to construct since we're constructing it from a slice
70        DiplomatSliceMut {
71            ptr: x.as_mut_ptr(),
72            len: x.len(),
73            phantom: PhantomData,
74        }
75    }
76}
77
78impl<'a, T> From<DiplomatSliceMut<'a, T>> for &'a mut [T] {
79    fn from(x: DiplomatSliceMut<'a, T>) -> Self {
80        unsafe {
81            if x.ptr.is_null() {
82                debug_assert!(x.len == 0);
83                return &mut [];
84            }
85            // Safety: carrying over safety variants from DiplomatSliceMut
86            core::slice::from_raw_parts_mut(x.ptr, x.len)
87        }
88    }
89}
90
91impl<T> Deref for DiplomatSliceMut<'_, T> {
92    type Target = [T];
93    fn deref(&self) -> &[T] {
94        if self.ptr.is_null() {
95            debug_assert!(self.len == 0);
96            return &[];
97        }
98        unsafe {
99            // Safety: carrying over safety variants from DiplomatSliceMut
100
101            core::slice::from_raw_parts(self.ptr, self.len)
102        }
103    }
104}
105
106impl<T> DerefMut for DiplomatSliceMut<'_, T> {
107    fn deref_mut(&mut self) -> &mut [T] {
108        if self.ptr.is_null() {
109            debug_assert!(self.len == 0);
110            return &mut [];
111        }
112        unsafe {
113            // Safety: carrying over safety variants from DiplomatSliceMut
114
115            core::slice::from_raw_parts_mut(self.ptr, self.len)
116        }
117    }
118}
119
120/// This is equivalent to `Box<[T]>`.
121///
122/// By and large, this is useful when a backend like JS or Dart needs to allocate
123/// a new slice in Rust memory to pass data around *anyway*, so we can avoid wasting
124/// allocations by reusing them in Rust.
125#[repr(C)]
126pub struct DiplomatOwnedSlice<T> {
127    // Invariant: ptr is a valid ptr to the beginning of an owned Box<[T]> allocation.  It may be null if len is null
128    ptr: *mut T,
129    // Invariant: the allocation contains `len` elements
130    len: usize,
131    phantom: PhantomData<Box<[T]>>,
132}
133
134impl<T> Drop for DiplomatOwnedSlice<T> {
135    fn drop(&mut self) {
136        if !self.ptr.is_null() {
137            unsafe {
138                // Safety: This is equivalent to a valid Box
139                drop(Box::from_raw(core::ptr::slice_from_raw_parts_mut(
140                    self.ptr, self.len,
141                )));
142            }
143        }
144    }
145}
146
147impl<T> From<Box<[T]>> for DiplomatOwnedSlice<T> {
148    fn from(x: Box<[T]>) -> Self {
149        // Safe to construct since we're constructing it from a valid Box<[T]>
150        let len = x.len();
151        DiplomatOwnedSlice {
152            ptr: Box::into_raw(x) as *mut T,
153            len,
154            phantom: PhantomData,
155        }
156    }
157}
158
159impl<T> From<DiplomatOwnedSlice<T>> for Box<[T]> {
160    fn from(x: DiplomatOwnedSlice<T>) -> Self {
161        let x = ManuallyDrop::new(x);
162        unsafe {
163            if x.ptr.is_null() {
164                debug_assert!(x.len == 0);
165                let dangling = core::ptr::NonNull::dangling().as_ptr();
166                return Box::from_raw(core::ptr::slice_from_raw_parts_mut(dangling, x.len));
167            }
168            // Safety: carrying over safety variants from DiplomatOwnedSlice
169            Box::from_raw(core::ptr::slice_from_raw_parts_mut(x.ptr, x.len))
170        }
171    }
172}
173
174impl<T> Deref for DiplomatOwnedSlice<T> {
175    type Target = [T];
176    fn deref(&self) -> &[T] {
177        if self.ptr.is_null() {
178            debug_assert!(self.len == 0);
179            return &[];
180        }
181        // Safety: The type invariants allow us to treat is as a valid Box<[T]>
182        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
183    }
184}
185
186impl<T> DerefMut for DiplomatOwnedSlice<T> {
187    fn deref_mut(&mut self) -> &mut [T] {
188        if self.ptr.is_null() {
189            debug_assert!(self.len == 0);
190            return &mut [];
191        }
192        // Safety: The type invariants allow us to treat is as a valid Box<[T]>
193        unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
194    }
195}
196
197/// This is equivalent to `&str`, except it has a stable `repr(C)` layout
198// Safety invariant: contained slice must be valid UTF-8
199#[repr(transparent)]
200#[derive(Copy, Clone)]
201pub struct DiplomatUtf8StrSlice<'a>(DiplomatSlice<'a, u8>);
202
203impl<'a> From<&'a str> for DiplomatUtf8StrSlice<'a> {
204    fn from(x: &'a str) -> Self {
205        // Safety: invariant upheld; obtained from `str`
206        Self(x.as_bytes().into())
207    }
208}
209
210impl<'a> From<DiplomatUtf8StrSlice<'a>> for &'a str {
211    fn from(x: DiplomatUtf8StrSlice<'a>) -> Self {
212        unsafe {
213            // We can assume this because of the invariant on DiplomatUtf8StrSlice
214            core::str::from_utf8_unchecked(<&[u8]>::from(x.0))
215        }
216    }
217}
218
219impl Deref for DiplomatUtf8StrSlice<'_> {
220    type Target = str;
221    fn deref(&self) -> &str {
222        (*self).into()
223    }
224}
225
226/// This is equivalent to `Box<str>`, except it has a stable `repr(C)` layout
227// Safety invariant: contained slice must be valid UTF-8
228#[repr(transparent)]
229pub struct DiplomatOwnedUTF8StrSlice(DiplomatOwnedSlice<u8>);
230
231impl From<Box<str>> for DiplomatOwnedUTF8StrSlice {
232    fn from(x: Box<str>) -> Self {
233        // Safety: invariant upheld; obtained from `str`
234        Self(Box::<[u8]>::from(x).into())
235    }
236}
237
238impl From<DiplomatOwnedUTF8StrSlice> for Box<str> {
239    fn from(x: DiplomatOwnedUTF8StrSlice) -> Self {
240        let buf = Box::<[u8]>::from(x.0);
241        let len = buf.len();
242        let raw = Box::into_raw(buf);
243        let raw = if raw.is_null() {
244            debug_assert!(len == 0);
245            NonNull::<u8>::dangling().as_ptr()
246        } else {
247            raw as *mut u8
248        };
249        unsafe {
250            // We deconstructed the Box already so we don't have to worry about provenance
251            // We're technically making an &mut [u8] here, because there isn't an easy route to construct
252            // string types that are owned
253            let slice = core::slice::from_raw_parts_mut(raw, len);
254            // We can assume this because of the invariant on DiplomatOwnedUTF8StrSlice
255            let strslice = core::str::from_utf8_unchecked_mut(slice);
256            Box::from_raw(strslice as *mut str)
257        }
258    }
259}
260
261impl Deref for DiplomatOwnedUTF8StrSlice {
262    type Target = str;
263    fn deref(&self) -> &str {
264        let slice = &self.0;
265        unsafe {
266            // We can assume this because of the invariant on DiplomatOwnedUTF8StrSlice
267            core::str::from_utf8_unchecked(slice)
268        }
269    }
270}
271
272/// This like `&str`, but unvalidated and safe to use over FFI
273///
274/// This type will usually map to some string type in the target language, and
275/// you will not need to worry about the safety of mismatched string invariants.
276pub type DiplomatStrSlice<'a> = DiplomatSlice<'a, u8>;
277/// This like `Box<str>`, but unvalidated and safe to use over FFI
278///
279/// This type will usually map to some string type in the target language, and
280/// you will not need to worry about the safety of mismatched string invariants.
281pub type DiplomatOwnedStrSlice = DiplomatOwnedSlice<u8>;
282/// An unvalidated UTF-16 string that is safe to use over FFI
283///
284/// This type will usually map to some string type in the target language, and
285/// you will not need to worry about the safety of mismatched string invariants.
286pub type DiplomatStr16Slice<'a> = DiplomatSlice<'a, u16>;
287/// An unvalidated, owned UTF-16 string that is safe to use over FFI
288///
289/// This type will usually map to some string type in the target language, and
290/// you will not need to worry about the safety of mismatched string invariants.
291pub type DiplomatOwnedStr16Slice<'a> = DiplomatOwnedSlice<u16>;