deno_libffi/middle/
types.rs

1//! Representations of C types and arrays thereof.
2//!
3//! These are used to describe the types of the arguments and results of
4//! functions. When we construct a CIF (“Call Inter<span></span>Face”),
5//! we provide a sequence of argument types and a result type, and
6//! libffi uses this to figure out how to set up a call to a function
7//! with those types.
8
9use libc;
10use std::fmt;
11use std::mem;
12use std::ptr;
13
14use crate::low;
15
16use super::util::Unique;
17
18// Internally we represent types and type arrays using raw pointers,
19// since this is what libffi understands. Below we wrap them with
20// types that implement Drop and Clone.
21
22type Type_ = *mut low::ffi_type;
23type TypeArray_ = *mut Type_;
24
25// Informal indication that the object should be considered owned by
26// the given reference.
27type Owned<T> = T;
28
29/// Represents a single C type.
30///
31/// # Example
32///
33/// Suppose we have a C struct:
34///
35/// ```c
36/// struct my_struct {
37///     uint16_t f1;
38///     uint64_t f2;
39/// };
40/// ```
41///
42/// To pass the struct by value via libffi, we need to construct a
43/// `Type` object describing its layout:
44///
45/// ```
46/// use deno_libffi::middle::Type;
47///
48/// let my_struct = Type::structure(vec![
49///     Type::u64(),
50///     Type::u16(),
51/// ]);
52/// ```
53pub struct Type(Unique<low::ffi_type>);
54
55/// Represents a sequence of C types.
56///
57/// This can be used to construct a struct type or as the arguments
58/// when creating a [`Cif`](struct.Cif.html).
59pub struct TypeArray(Unique<*mut low::ffi_type>);
60
61impl fmt::Debug for Type {
62    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
63        formatter.write_fmt(format_args!("Type({:?})", *self.0))
64    }
65}
66
67impl fmt::Debug for TypeArray {
68    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
69        formatter.write_fmt(format_args!("TypeArray({:?})", *self.0))
70    }
71}
72
73/// Computes the length of a raw `TypeArray_` by searching for the
74/// null terminator.
75unsafe fn ffi_type_array_len(mut array: TypeArray_) -> usize {
76    let mut count = 0;
77    while !(*array).is_null() {
78        count += 1;
79        array = array.offset(1);
80    }
81    count
82}
83
84/// Creates an empty `TypeArray_` with null terminator.
85unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<TypeArray_> {
86    let array = libc::malloc((len + 1) * mem::size_of::<Type_>()) as TypeArray_;
87    assert!(
88        !array.is_null(),
89        "ffi_type_array_create_empty: out of memory"
90    );
91    *array.add(len) = ptr::null_mut::<low::ffi_type>() as Type_;
92    array
93}
94
95/// Creates a null-terminated array of Type_. Takes ownership of
96/// the elements.
97unsafe fn ffi_type_array_create<I>(elements: I) -> Owned<TypeArray_>
98where
99    I: ExactSizeIterator<Item = Type>,
100{
101    let size = elements.len();
102    let new = ffi_type_array_create_empty(size);
103    for (i, element) in elements.enumerate() {
104        *new.add(i) = *element.0;
105        mem::forget(element);
106    }
107
108    new
109}
110
111/// Creates a struct type from a raw array of element types.
112unsafe fn ffi_type_struct_create_raw(elements: Owned<TypeArray_>) -> Owned<Type_> {
113    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as Type_;
114    assert!(!new.is_null(), "ffi_type_struct_create_raw: out of memory");
115
116    (*new).size = 0;
117    (*new).alignment = 0;
118    (*new).type_ = low::type_tag::STRUCT;
119    (*new).elements = elements;
120
121    new
122}
123
124/// Creates a struct `ffi_type` with the given elements. Takes ownership
125/// of the elements.
126unsafe fn ffi_type_struct_create<I>(elements: I) -> Owned<Type_>
127where
128    I: ExactSizeIterator<Item = Type>,
129{
130    ffi_type_struct_create_raw(ffi_type_array_create(elements))
131}
132
133/// Makes a copy of a type array.
134unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
135    let size = ffi_type_array_len(old);
136    let new = ffi_type_array_create_empty(size);
137
138    for i in 0..size {
139        *new.add(i) = ffi_type_clone(*old.add(i));
140    }
141
142    new
143}
144
145/// Makes a copy of a type.
146unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
147    if (*old).type_ == low::type_tag::STRUCT {
148        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
149    } else {
150        old
151    }
152}
153
154/// Destroys a `TypeArray_` and all of its elements.
155unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
156    let mut current = victim;
157    while !(*current).is_null() {
158        ffi_type_destroy(*current);
159        current = current.offset(1);
160    }
161
162    libc::free(victim as *mut libc::c_void);
163}
164
165/// Destroys a `Type_` if it was dynamically allocated.
166unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
167    if (*victim).type_ == low::type_tag::STRUCT {
168        ffi_type_array_destroy((*victim).elements);
169        libc::free(victim as *mut libc::c_void);
170    }
171}
172
173impl Drop for Type {
174    fn drop(&mut self) {
175        unsafe { ffi_type_destroy(*self.0) }
176    }
177}
178
179impl Drop for TypeArray {
180    fn drop(&mut self) {
181        unsafe { ffi_type_array_destroy(*self.0) }
182    }
183}
184
185impl Clone for Type {
186    fn clone(&self) -> Self {
187        Type(unsafe { Unique::new(ffi_type_clone(*self.0)) })
188    }
189}
190
191impl Clone for TypeArray {
192    fn clone(&self) -> Self {
193        TypeArray(unsafe { Unique::new(ffi_type_array_clone(*self.0)) })
194    }
195}
196
197macro_rules! match_size_signed {
198    ( $name:ident ) => {
199        match mem::size_of::<libc::$name>() {
200            1 => Self::i8(),
201            2 => Self::i16(),
202            4 => Self::i32(),
203            8 => Self::i64(),
204            _ => panic!("Strange size for C type"),
205        }
206    };
207}
208
209macro_rules! match_size_unsigned {
210    ( $name:ident ) => {
211        match mem::size_of::<libc::$name>() {
212            1 => Self::u8(),
213            2 => Self::u16(),
214            4 => Self::u32(),
215            8 => Self::u64(),
216            _ => panic!("Strange size for C type"),
217        }
218    };
219}
220
221impl Type {
222    /// Returns the representation of the C `void` type.
223    ///
224    /// This is used only for the return type of a CIF, not for an
225    /// argument or struct member.
226    pub fn void() -> Self {
227        Type(unsafe { Unique::new(&mut low::types::void) })
228    }
229
230    /// Returns the unsigned 8-bit numeric type.
231    pub fn u8() -> Self {
232        Type(unsafe { Unique::new(&mut low::types::uint8) })
233    }
234
235    /// Returns the signed 8-bit numeric type.
236    pub fn i8() -> Self {
237        Type(unsafe { Unique::new(&mut low::types::sint8) })
238    }
239
240    /// Returns the unsigned 16-bit numeric type.
241    pub fn u16() -> Self {
242        Type(unsafe { Unique::new(&mut low::types::uint16) })
243    }
244
245    /// Returns the signed 16-bit numeric type.
246    pub fn i16() -> Self {
247        Type(unsafe { Unique::new(&mut low::types::sint16) })
248    }
249
250    /// Returns the unsigned 32-bit numeric type.
251    pub fn u32() -> Self {
252        Type(unsafe { Unique::new(&mut low::types::uint32) })
253    }
254
255    /// Returns the signed 32-bit numeric type.
256    pub fn i32() -> Self {
257        Type(unsafe { Unique::new(&mut low::types::sint32) })
258    }
259
260    /// Returns the unsigned 64-bit numeric type.
261    pub fn u64() -> Self {
262        Type(unsafe { Unique::new(&mut low::types::uint64) })
263    }
264
265    /// Returns the signed 64-bit numeric type.
266    pub fn i64() -> Self {
267        Type(unsafe { Unique::new(&mut low::types::sint64) })
268    }
269
270    #[cfg(target_pointer_width = "16")]
271    /// Returns the C equivalent of Rust `usize` (`u16`).
272    pub fn usize() -> Self {
273        Self::u16()
274    }
275
276    #[cfg(target_pointer_width = "16")]
277    /// Returns the C equivalent of Rust `isize` (`i16`).
278    pub fn isize() -> Self {
279        Self::i16()
280    }
281
282    #[cfg(target_pointer_width = "32")]
283    /// Returns the C equivalent of Rust `usize` (`u32`).
284    pub fn usize() -> Self {
285        Self::u32()
286    }
287
288    #[cfg(target_pointer_width = "32")]
289    /// Returns the C equivalent of Rust `isize` (`i32`).
290    pub fn isize() -> Self {
291        Self::i32()
292    }
293
294    #[cfg(target_pointer_width = "64")]
295    /// Returns the C equivalent of Rust `usize` (`u64`).
296    pub fn usize() -> Self {
297        Self::u64()
298    }
299
300    #[cfg(target_pointer_width = "64")]
301    /// Returns the C equivalent of Rust `isize` (`i64`).
302    pub fn isize() -> Self {
303        Self::i64()
304    }
305
306    /// Returns the C `signed char` type.
307    pub fn c_schar() -> Self {
308        match_size_signed!(c_schar)
309    }
310
311    /// Returns the C `unsigned char` type.
312    pub fn c_uchar() -> Self {
313        match_size_unsigned!(c_uchar)
314    }
315
316    /// Returns the C `short` type.
317    pub fn c_short() -> Self {
318        match_size_signed!(c_short)
319    }
320
321    /// Returns the C `unsigned short` type.
322    pub fn c_ushort() -> Self {
323        match_size_unsigned!(c_ushort)
324    }
325
326    /// Returns the C `int` type.
327    pub fn c_int() -> Self {
328        match_size_signed!(c_int)
329    }
330
331    /// Returns the C `unsigned int` type.
332    pub fn c_uint() -> Self {
333        match_size_unsigned!(c_uint)
334    }
335
336    /// Returns the C `long` type.
337    pub fn c_long() -> Self {
338        match_size_signed!(c_long)
339    }
340
341    /// Returns the C `unsigned long` type.
342    pub fn c_ulong() -> Self {
343        match_size_unsigned!(c_ulong)
344    }
345
346    /// Returns the C `longlong` type.
347    pub fn c_longlong() -> Self {
348        match_size_signed!(c_longlong)
349    }
350
351    /// Returns the C `unsigned longlong` type.
352    pub fn c_ulonglong() -> Self {
353        match_size_unsigned!(c_ulonglong)
354    }
355
356    /// Returns the C `float` (32-bit floating point) type.
357    pub fn f32() -> Self {
358        Type(unsafe { Unique::new(&mut low::types::float) })
359    }
360
361    /// Returns the C `double` (64-bit floating point) type.
362    pub fn f64() -> Self {
363        Type(unsafe { Unique::new(&mut low::types::double) })
364    }
365
366    /// Returns the C `void*` type, for passing any kind of pointer.
367    pub fn pointer() -> Self {
368        Type(unsafe { Unique::new(&mut low::types::pointer) })
369    }
370
371    /// Returns the C `long double` (extended-precision floating point) type.
372    #[cfg(not(all(target_arch = "arm")))]
373    pub fn longdouble() -> Self {
374        Type(unsafe { Unique::new(&mut low::types::longdouble) })
375    }
376
377    /// Returns the C `_Complex float` type.
378    ///
379    /// This item is enabled by `#[cfg(feature = "complex")]`.
380    #[cfg(feature = "complex")]
381    pub fn c32() -> Self {
382        Type(unsafe { Unique::new(&mut low::types::complex_float) })
383    }
384
385    /// Returns the C `_Complex double` type.
386    ///
387    /// This item is enabled by `#[cfg(feature = "complex")]`.
388    #[cfg(feature = "complex")]
389    pub fn c64() -> Self {
390        Type(unsafe { Unique::new(&mut low::types::complex_double) })
391    }
392
393    /// Returns the C `_Complex long double` type.
394    ///
395    /// This item is enabled by `#[cfg(feature = "complex")]`.
396    #[cfg(feature = "complex")]
397    #[cfg(not(all(target_arch = "arm")))]
398    pub fn complex_longdouble() -> Self {
399        Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
400    }
401
402    /// Constructs a structure type whose fields have the given types.
403    pub fn structure<I>(fields: I) -> Self
404    where
405        I: IntoIterator<Item = Type>,
406        I::IntoIter: ExactSizeIterator<Item = Type>,
407    {
408        Type(unsafe { Unique::new(ffi_type_struct_create(fields.into_iter())) })
409    }
410
411    /// Gets a raw pointer to the underlying
412    /// [`ffi_type`](../raw/struct._ffi_type.html).
413    ///
414    /// This method may be useful for interacting with the
415    /// [`low`](../low/index.html) and
416    /// [`raw`](../raw/index.html) layers.
417    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
418        *self.0
419    }
420}
421
422impl TypeArray {
423    /// Constructs an array the given `Type`s.
424    pub fn new<I>(elements: I) -> Self
425    where
426        I: IntoIterator<Item = Type>,
427        I::IntoIter: ExactSizeIterator<Item = Type>,
428    {
429        TypeArray(unsafe { Unique::new(ffi_type_array_create(elements.into_iter())) })
430    }
431
432    /// Gets a raw pointer to the underlying C array of
433    /// [`ffi_type`](../raw/struct._ffi_type.html)s.
434    ///
435    /// The C array is null-terminated.
436    ///
437    /// This method may be useful for interacting with the
438    /// [`low`](../low/index.html) and
439    /// [`raw`](../raw/index.html) layers.
440    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
441        *self.0
442    }
443}
444
445#[cfg(test)]
446mod test {
447    use super::*;
448
449    #[test]
450    fn create_u64() {
451        Type::u64();
452    }
453
454    #[test]
455    fn clone_u64() {
456        let _ = Type::u64().clone().clone();
457    }
458
459    #[test]
460    fn create_struct() {
461        Type::structure(vec![Type::i64(), Type::i64(), Type::u64()]);
462    }
463
464    #[test]
465    fn clone_struct() {
466        let _ = Type::structure(vec![Type::i64(), Type::i64(), Type::u64()])
467            .clone()
468            .clone();
469    }
470}