1//! Representations of C types for the high layer.
2
3use std::marker::PhantomData;
4
5use super::super::low;
6use super::super::middle;
7
8/// Represents a C type statically associated with a Rust type.
9///
10/// In particular, the run-time value describes a particular C type,
11/// while the type parameter `T` is the equivalent Rust type.
12/// Instances of this type are created via the [`CType`] trait.
13#[derive(Clone, Debug)]
14pub struct Type<T> {
15 untyped: middle::Type,
16 _marker: PhantomData<*mut T>,
17}
18
19impl<T> Type<T> {
20 fn make(untyped: middle::Type) -> Self {
21 Type {
22 untyped,
23 _marker: PhantomData,
24 }
25 }
26
27 /// Gets the underlying representation as used by the
28 /// [`mod@middle`] layer.
29 pub fn into_middle(self) -> middle::Type {
30 self.untyped
31 }
32}
33
34/// Types that we can automatically marshall to/from C.
35///
36/// In particular, for any type `T` that implements `CType`, we can
37/// get a `Type<T>` for describing that type.
38/// This trait is unsafe to implement because if the libffi type
39/// associated with a Rust type doesn’t match then we get
40/// undefined behavior.
41pub unsafe trait CType: Copy {
42 /// Creates or retrieves a `Type<T>` for any type `T: CType`.
43 ///
44 /// We can use the resulting object to assemble a CIF to set up
45 /// a call that uses type `T`.
46 fn reify() -> Type<Self>;
47 /// The low-level libffi library implicitly extends small integer
48 /// return values to `ffi_arg` or `ffi_sarg`. Track the possibly
49 /// extended variant of `T` as an associated type here.
50 type RetType: std::convert::From<Self> + std::convert::TryInto<Self>;
51}
52
53macro_rules! impl_ffi_type {
54 ($type_:ty, $ret_:ty, $cons:ident) => {
55 unsafe impl CType for $type_ {
56 fn reify() -> Type<Self> {
57 Type::make(middle::Type::$cons())
58 }
59 type RetType = $ret_;
60 }
61 };
62 ($type_:ident, $ret_:ty) => {
63 impl_ffi_type!($type_, $ret_, $type_);
64 };
65 ($type_:ident) => {
66 impl_ffi_type!($type_, $type_, $type_);
67 };
68}
69
70// We assume that `ffi_arg` and `ffi_sarg` are either 32-bit or 64-bit
71// integer types on all supported platforms here.
72impl_ffi_type!(u8, low::ffi_arg);
73impl_ffi_type!(i8, low::ffi_sarg);
74impl_ffi_type!(u16, low::ffi_arg);
75impl_ffi_type!(i16, low::ffi_sarg);
76impl_ffi_type!(u32, low::ffi_arg);
77impl_ffi_type!(i32, low::ffi_sarg);
78impl_ffi_type!(u64);
79impl_ffi_type!(i64);
80impl_ffi_type!(f32);
81impl_ffi_type!(f64);
82impl_ffi_type!(usize);
83impl_ffi_type!(isize);
84impl_ffi_type!((), (), void);
85
86// Why is the complex stuff even here? It doesn’t work yet because
87// libffi doesn’t support it, so it should probably go away and come
88// back when it’s actually useful. Also, the definitions for c_c32 and
89// c_c64 should come from elsewhere (the num package?), but that
90// elsewhere doesn’t seem to exist yet.
91
92/// Laid out the same as C11 `float complex` and C++11
93/// `std::complex<float>`.
94///
95/// This item is enabled by `#[cfg(feature = "complex")]`.
96///
97/// # Warning
98///
99/// This type does not obey the ABI, and as such should not be passed by
100/// value to or from a C or C++ function. Passing it via a pointer is
101/// okay. Theoretically, passing it via libffi is okay, but libffi
102/// doesn’t have complex support on most platforms yet.
103#[allow(non_camel_case_types)]
104#[cfg(feature = "complex")]
105pub type c_c32 = [f32; 2];
106
107/// Laid out the same as C11 `double complex` and C++11
108/// `std::complex<double>`.
109///
110/// This item is enabled by `#[cfg(feature = "complex")]`.
111///
112/// # Warning
113///
114/// This type does not obey the ABI, and as such should not be passed by
115/// value to or from a C or C++ function. Passing it via a pointer is
116/// okay. Theoretically, passing it via libffi is okay, but libffi
117/// doesn’t have complex support on most platforms yet.
118#[allow(non_camel_case_types)]
119#[cfg(feature = "complex")]
120pub type c_c64 = [f64; 2];
121
122#[cfg(feature = "complex")]
123impl_ffi_type!(c_c32, c32);
124
125#[cfg(feature = "complex")]
126impl_ffi_type!(c_c64, c64);
127
128unsafe impl<T> CType for *const T {
129 fn reify() -> Type<Self> {
130 Type::make(untyped:middle::Type::pointer())
131 }
132 type RetType = *const T;
133}
134
135unsafe impl<T> CType for *mut T {
136 fn reify() -> Type<Self> {
137 Type::make(untyped:middle::Type::pointer())
138 }
139 type RetType = *mut T;
140}
141