maia/
ffi.rs

1// Copyright 2022 Google LLC
2
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9pub(crate) use std::ffi::c_void;
10use std::ffi::CStr;
11use std::fmt::Debug;
12pub(crate) use std::marker::PhantomData;
13use std::mem::MaybeUninit;
14use std::os::raw::c_char;
15pub(crate) use std::ptr::NonNull;
16
17/// The null pointer
18#[repr(transparent)]
19#[derive(Copy, Clone, Default)]
20pub struct Null(Option<&'static Never>);
21enum Never {}
22
23impl Debug for Null {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        f.write_str("Null")
26    }
27}
28
29/// An immutably borrowed, null-terminated utf-8 string, represented as
30/// a non-null c `const char*`.
31#[repr(transparent)]
32#[derive(Debug, Copy, Clone)]
33pub struct Str<'a> {
34    _ptr: NonNull<c_char>,
35    _lt: PhantomData<&'a ()>,
36}
37
38// Safety: As with &
39unsafe impl<'a> Send for Str<'a> {}
40unsafe impl<'a> Sync for Str<'a> {}
41
42impl<'a> Str<'a> {
43    /// Fails if not null terminated
44    pub fn new(s: &'a str) -> Result<Self, std::ffi::FromBytesWithNulError> {
45        s.try_into()
46    }
47    /// # Safety
48    /// The slice must be null terminated and not contain null bytes
49    pub const unsafe fn new_unchecked(b: &'a [u8]) -> Self {
50        Str {
51            _ptr: NonNull::new_unchecked(
52                CStr::from_bytes_with_nul_unchecked(b).as_ptr() as *mut c_char,
53            ),
54            _lt: PhantomData,
55        }
56    }
57    /// Returns the string as a regular Rust str
58    pub fn as_str(self) -> &'a str {
59        unsafe {
60            std::str::from_utf8_unchecked(
61                CStr::from_ptr(self._ptr.as_ptr()).to_bytes(),
62            )
63        }
64    }
65}
66
67impl Default for Str<'_> {
68    fn default() -> Self {
69        <&CStr>::default().into()
70    }
71}
72
73// TODO: User-defined unsize, once the compiler allows that.
74
75impl<'a> From<&'a CStr> for Str<'a> {
76    fn from(cstring: &'a CStr) -> Self {
77        // Safety: CStr::as_ptr is always non-null.
78        Str { _ptr: unsafe { (&*cstring.as_ptr()).into() }, _lt: PhantomData }
79    }
80}
81
82/// Fails if not null terminated
83impl<'a> TryFrom<&'a str> for Str<'a> {
84    type Error = std::ffi::FromBytesWithNulError;
85    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
86        Ok(CStr::from_bytes_with_nul(value.as_bytes())?.into())
87    }
88}
89
90/// A c string stored as a null-terminated utf-8 string inside an array of
91/// bytes of fixed length.
92#[repr(transparent)]
93#[derive(Clone)]
94pub struct CharArray<const N: usize>([u8; N]);
95
96impl<const N: usize> CharArray<N> {
97    /// Borrows the string as a regular Rust str
98    pub fn as_str(&self) -> &str {
99        unsafe {
100            let len = self.0.iter().position(|&c| c == 0).unwrap_unchecked();
101            let slice = std::slice::from_raw_parts(self.0.as_ptr(), len);
102            std::str::from_utf8_unchecked(slice)
103        }
104    }
105}
106
107impl<const N: usize> Debug for CharArray<N> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        f.write_str("CharArray<")?;
110        N.fmt(f)?;
111        f.write_str(">(")?;
112        self.as_str().fmt(f)?;
113        f.write_str(")")
114    }
115}
116
117impl<const N: usize, const M: usize> PartialEq<CharArray<M>> for CharArray<N> {
118    fn eq(&self, other: &CharArray<M>) -> bool {
119        self.as_str() == other.as_str()
120    }
121}
122
123impl<'a, const N: usize> PartialEq<Str<'a>> for CharArray<N> {
124    fn eq(&self, other: &Str<'a>) -> bool {
125        self.as_str() == other.as_str()
126    }
127}
128
129/// An owned contiguous sequence of T, represented as a u32 and an inline array.
130#[repr(C)]
131#[derive(Debug)]
132pub struct InlineSlice<T, const N: usize> {
133    count: u32,
134    value: [MaybeUninit<T>; N],
135}
136
137impl<T, const N: usize> InlineSlice<T, N> {
138    /// The length of the slice
139    pub fn len(&self) -> u32 {
140        self.count
141    }
142    /// Whether the slice is empty
143    pub fn is_empty(&self) -> bool {
144        self.count == 0
145    }
146    /// Borrows the contents as a normal rust slice
147    #[inline]
148    pub fn as_slice(&self) -> &[T] {
149        unsafe {
150            std::slice::from_raw_parts(
151                self.value.as_ptr() as *const T,
152                self.count as usize,
153            )
154        }
155    }
156    /// Iterate over the slice
157    #[inline]
158    pub fn iter(&self) -> impl Iterator<Item = &T> {
159        self.as_slice().iter()
160    }
161}
162
163impl<'a, T, const N: usize> std::iter::IntoIterator for &'a InlineSlice<T, N> {
164    type Item = &'a T;
165    type IntoIter = std::slice::Iter<'a, T>;
166    fn into_iter(self) -> Self::IntoIter {
167        self.as_slice().iter()
168    }
169}
170
171impl<T, const N: usize> Default for InlineSlice<T, N> {
172    fn default() -> Self {
173        Self {
174            count: 0,
175            // The MaybeUninit members are initialized when uninitialized
176            value: unsafe { MaybeUninit::uninit().assume_init() },
177        }
178    }
179}
180
181/// A UUID stored inline
182#[repr(transparent)]
183#[derive(Debug, PartialEq, Eq, Copy, Clone)]
184pub struct UUID(pub [u8; 16]);
185
186// Note: Be *very* careful about how this is aligned in the outer struct.
187
188/// An immutably borrowed contiguous sequence of T. Represented as a u32
189/// followed by a pointer. Create using the [`slice()`] function.
190#[repr(C)]
191pub struct Slice<'a, T> {
192    count: u32,
193    ptr: *const T,
194    _lt: PhantomData<&'a T>,
195}
196
197// Safety: As with &
198unsafe impl<'a, T: Sync> Send for Slice<'a, T> {}
199unsafe impl<'a, T: Sync> Sync for Slice<'a, T> {}
200
201impl<'a, T> Copy for Slice<'a, T> {}
202impl<'a, T> Clone for Slice<'a, T> {
203    fn clone(&self) -> Self {
204        Self { count: self.count, ptr: self.ptr, _lt: self._lt }
205    }
206}
207
208impl<'a, T: Debug> Debug for Slice<'a, T> {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        self.as_slice().fmt(f)
211    }
212}
213
214impl<'a, T> Slice<'a, T> {
215    fn new(arr: &'a [T]) -> Self {
216        Slice { count: arr.len() as u32, ptr: arr.as_ptr(), _lt: PhantomData }
217    }
218    /// The length of the slice
219    pub fn len(&self) -> u32 {
220        self.count
221    }
222    /// Whether the slice is empty
223    pub fn is_empty(&self) -> bool {
224        self.count == 0
225    }
226    /// Convert back into a normal rust slice
227    pub fn as_slice(&self) -> &'a [T] {
228        unsafe {
229            let len = self.count as usize;
230            std::slice::from_raw_parts(self.ptr, len)
231        }
232    }
233}
234
235impl<'a, T> Default for Slice<'a, T> {
236    fn default() -> Self {
237        (&[]).into()
238    }
239}
240
241impl<'a, T> From<&'a [T]> for Slice<'a, T> {
242    fn from(arr: &'a [T]) -> Self {
243        Self::new(arr)
244    }
245}
246
247impl<'a, T> From<&'a mut [T]> for Slice<'a, T> {
248    fn from(arr: &'a mut [T]) -> Self {
249        Self::new(arr)
250    }
251}
252
253impl<'a, T> From<&'a Vec<T>> for Slice<'a, T> {
254    fn from(arr: &'a Vec<T>) -> Self {
255        Self::new(arr)
256    }
257}
258
259impl<'a, T, const N: usize> From<&'a [T; N]> for Slice<'a, T> {
260    fn from(ts: &'a [T; N]) -> Self {
261        Self { count: N as u32, ptr: ts.as_ptr(), _lt: PhantomData }
262    }
263}
264
265impl<'a, T> std::iter::IntoIterator for Slice<'a, T> {
266    type Item = &'a T;
267    type IntoIter = std::slice::Iter<'a, T>;
268    fn into_iter(self) -> Self::IntoIter {
269        self.as_slice().iter()
270    }
271}
272
273/// An immutably borrowed contiguous sequence of T. Represented as a u32
274/// followed by a pointer. Create using the [`slice()`] function. This type
275/// differs from [`struct@Slice`] only in that it is aligned to a 4-byte
276/// boundary, for cases where the structure alignment of [`struct@Slice`] puts
277/// the count member in the wrong place on 64 bit systems. This type does not
278/// use unaligned loads or stores and has no special alignment requirement
279/// itself.
280#[repr(C)]
281pub struct Slice_<'a, T> {
282    count: u32,
283    ptr: SlicePtr<T>,
284    _lt: PhantomData<&'a T>,
285}
286
287#[repr(packed)]
288struct SlicePtr<T>(*const T);
289
290// Safety: As with &
291unsafe impl<'a, T: Sync> Send for Slice_<'a, T> {}
292unsafe impl<'a, T: Sync> Sync for Slice_<'a, T> {}
293
294impl<T> Copy for SlicePtr<T> {}
295impl<T> Clone for SlicePtr<T> {
296    fn clone(&self) -> Self {
297        Self(self.0)
298    }
299}
300impl<'a, T> Copy for Slice_<'a, T> {}
301impl<'a, T> Clone for Slice_<'a, T> {
302    fn clone(&self) -> Self {
303        Self { count: self.count, ptr: self.ptr, _lt: self._lt }
304    }
305}
306
307impl<'a, T: Debug> Debug for Slice_<'a, T> {
308    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309        self.as_slice().fmt(f)
310    }
311}
312
313impl<'a, T> Default for Slice_<'a, T> {
314    fn default() -> Self {
315        (&[]).into()
316    }
317}
318
319impl<'a, T> Slice_<'a, T> {
320    fn new(arr: &'a [T]) -> Self {
321        Self {
322            count: arr.len() as u32,
323            ptr: SlicePtr(arr.as_ptr()),
324            _lt: PhantomData,
325        }
326    }
327    /// The length of the slice
328    pub fn len(&self) -> u32 {
329        self.count
330    }
331    /// Whether the slice is empty
332    pub fn is_empty(&self) -> bool {
333        self.count == 0
334    }
335    /// Convert back into a normal rust slice
336    pub fn as_slice(&self) -> &'a [T] {
337        unsafe {
338            let ptr = self.ptr.0;
339            let len = self.count as usize;
340            std::slice::from_raw_parts(ptr, len)
341        }
342    }
343}
344
345impl<'a, T> From<&'a [T]> for Slice_<'a, T> {
346    fn from(arr: &'a [T]) -> Self {
347        Self::new(arr)
348    }
349}
350
351impl<'a, T> From<&'a mut [T]> for Slice_<'a, T> {
352    fn from(arr: &'a mut [T]) -> Self {
353        Self::new(arr)
354    }
355}
356
357impl<'a, T> From<&'a Vec<T>> for Slice_<'a, T> {
358    fn from(arr: &'a Vec<T>) -> Self {
359        Self::new(arr)
360    }
361}
362
363impl<'a, T, const N: usize> From<&'a [T; N]> for Slice_<'a, T> {
364    fn from(ts: &'a [T; N]) -> Self {
365        Self { count: N as u32, ptr: SlicePtr(ts.as_ptr()), _lt: PhantomData }
366    }
367}
368
369impl<'a, T> std::iter::IntoIterator for Slice_<'a, T> {
370    type Item = &'a T;
371    type IntoIter = std::slice::Iter<'a, T>;
372    fn into_iter(self) -> Self::IntoIter {
373        self.as_slice().iter()
374    }
375}
376
377/// Create a Vulkan slice object ([`struct@Slice`] or [`struct@Slice_`]) from
378/// the passed value. Less awkward looking than calling [`into`](Into::into)
379/// when using an array literal.
380#[inline]
381pub fn slice<'a, T, S: IsSlice<'a, T>>(value: &'a [T]) -> S {
382    IsSlice::to_slice_impl(value)
383}
384/// A convenience trate for creating either a [`struct@Slice`] or
385/// [`struct@Slice_`]. Call with [`vk::slice`](crate::vk::slice).
386pub trait IsSlice<'a, T> {
387    /// See [`slice()`].
388    fn to_slice_impl(value: &'a [T]) -> Self;
389}
390impl<'a, T> IsSlice<'a, T> for Slice<'a, T> {
391    fn to_slice_impl(value: &'a [T]) -> Self {
392        Self::new(value)
393    }
394}
395impl<'a, T> IsSlice<'a, T> for Slice_<'a, T> {
396    fn to_slice_impl(value: &'a [T]) -> Self {
397        Self::new(value)
398    }
399}
400
401/// An immutably borrowed contiguous sequence of bytes. Represented as a usize
402/// followed by a pointer.
403#[repr(C)]
404#[derive(Debug)]
405pub struct Bytes<'a> {
406    len: usize,
407    ptr: *const u8,
408    _lt: PhantomData<&'a u8>,
409}
410
411// Safety: As with &
412unsafe impl<'a> Send for Bytes<'a> {}
413unsafe impl<'a> Sync for Bytes<'a> {}
414
415impl<'a> Copy for Bytes<'a> {}
416impl<'a> Clone for Bytes<'a> {
417    fn clone(&self) -> Self {
418        Self { len: self.len, ptr: self.ptr, _lt: self._lt }
419    }
420}
421
422impl<'a> Bytes<'a> {
423    /// Create from a byte slice
424    pub fn new(slice: &'a [u8]) -> Self {
425        Self { len: slice.len(), ptr: slice.as_ptr(), _lt: PhantomData }
426    }
427    /// The number of bytes
428    pub fn len(&self) -> usize {
429        self.len
430    }
431    /// Whether the value is emty
432    pub fn is_empty(&self) -> bool {
433        self.len == 0
434    }
435    /// Convert back into a normal rust slice
436    pub fn as_slice(&self) -> &'a [u8] {
437        unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
438    }
439}
440
441impl<'a> Default for Bytes<'a> {
442    fn default() -> Self {
443        Self::new(&[])
444    }
445}
446
447impl<'a> From<&'a [u8]> for Bytes<'a> {
448    fn from(slice: &'a [u8]) -> Self {
449        Self::new(slice)
450    }
451}
452
453impl<'a> From<&'a [u32]> for Bytes<'a> {
454    fn from(slice: &'a [u32]) -> Self {
455        Bytes {
456            len: slice.len() * 4,
457            ptr: slice.as_ptr() as *const u8,
458            _lt: PhantomData,
459        }
460    }
461}
462
463impl<'a> From<&'a Vec<u8>> for Bytes<'a> {
464    fn from(vec: &'a Vec<u8>) -> Self {
465        Self::new(vec)
466    }
467}
468
469/// An immutably borrowed contiguous nonempty sequence of T. Represented as a
470/// non-null pointer.
471#[repr(transparent)]
472#[derive(Debug)]
473pub struct Array<'a, T> {
474    _ptr: NonNull<T>,
475    _lt: PhantomData<&'a T>,
476}
477
478// Safety: As with &
479unsafe impl<'a, T: Sync> Send for Array<'a, T> {}
480unsafe impl<'a, T: Sync> Sync for Array<'a, T> {}
481
482impl<'a, T> Copy for Array<'a, T> {}
483impl<'a, T> Clone for Array<'a, T> {
484    fn clone(&self) -> Self {
485        Self { _ptr: self._ptr, _lt: self._lt }
486    }
487}
488
489impl<'a, T, const N: usize> From<&'a [T; N]> for Array<'a, T> {
490    fn from(array: &'a [T; N]) -> Self {
491        let _array_must_be_non_empty = N - 1;
492        Self {
493            _ptr: unsafe { NonNull::new_unchecked(array.as_ptr() as *mut T) },
494            _lt: PhantomData,
495        }
496    }
497}
498
499impl<'a, T> Array<'a, T> {
500    /// Convert from a slice. Returns [`None`] if `slice` is empty.
501    pub fn from_slice(slice: &'a [T]) -> Option<Array<'a, T>> {
502        if slice.is_empty() {
503            None
504        } else {
505            Some(Self {
506                _ptr: unsafe {
507                    NonNull::new_unchecked(slice.as_ptr() as *mut T)
508                },
509                _lt: PhantomData,
510            })
511        }
512    }
513    /// Convert back into a normal rust slice
514    /// # Safety
515    /// `len` must be less than or equal to the original length.
516    pub unsafe fn as_slice(self, len: u32) -> &'a [T] {
517        std::slice::from_raw_parts(self._ptr.as_ptr(), len as usize)
518    }
519}
520
521/// A mutably borrowed contiguous nonempty sequence of T. Represented as a
522/// non-null pointer.
523#[repr(transparent)]
524#[derive(Debug)]
525pub struct ArrayMut<'a, T> {
526    _ptr: NonNull<T>,
527    _lt: PhantomData<&'a mut T>,
528}
529
530// Safety: As with &
531unsafe impl<'a, T: Sync> Send for ArrayMut<'a, T> {}
532unsafe impl<'a, T: Sync> Sync for ArrayMut<'a, T> {}
533
534impl<'a, T, const N: usize> From<&'a mut [T; N]> for ArrayMut<'a, T> {
535    fn from(array: &'a mut [T; N]) -> Self {
536        let _array_must_be_non_empty = N - 1;
537        Self {
538            _ptr: unsafe { NonNull::new_unchecked(array.as_ptr() as *mut T) },
539            _lt: PhantomData,
540        }
541    }
542}
543
544impl<'a, T> ArrayMut<'a, T> {
545    /// Convert from a slice. Returns [`None`] if `slice` is empty.
546    pub fn from_slice(slice: &'a mut [T]) -> Option<ArrayMut<'a, T>> {
547        if slice.is_empty() {
548            None
549        } else {
550            Some(Self {
551                _ptr: unsafe {
552                    NonNull::new_unchecked(slice.as_ptr() as *mut T)
553                },
554                _lt: PhantomData,
555            })
556        }
557    }
558}