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](super::Cif) (“Call
5//! Inter<span></span>Face”), we provide a sequence of argument types
6//! and a result type, and libffi uses this to figure out how to set up
7//! a call to a function 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 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`].
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: usize = 0;
77 while !(*array).is_null() {
78 count += 1;
79 array = array.offset(count: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: *mut *mut ffi_type = 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(count: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: usize = elements.len();
102 let new: *mut *mut ffi_type = ffi_type_array_create_empty(len:size);
103 for (i: usize, element: Type) in elements.enumerate() {
104 *new.add(count: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(
113 elements: Owned<TypeArray_>,
114 size: usize,
115 alignment: u16,
116) -> Owned<Type_> {
117 let new: *mut ffi_type = libc::malloc(size:mem::size_of::<low::ffi_type>()) as Type_;
118 assert!(!new.is_null(), "ffi_type_struct_create_raw: out of memory");
119
120 (*new).size = size;
121 (*new).alignment = alignment;
122 (*new).type_ = low::type_tag::STRUCT;
123 (*new).elements = elements;
124
125 new
126}
127
128/// Creates a struct `ffi_type` with the given elements. Takes ownership
129/// of the elements.
130unsafe fn ffi_type_struct_create<I>(elements: I) -> Owned<Type_>
131where
132 I: ExactSizeIterator<Item = Type>,
133{
134 ffi_type_struct_create_raw(elements:ffi_type_array_create(elements), size:0, alignment:0)
135}
136
137/// Makes a copy of a type array.
138unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
139 let size: usize = ffi_type_array_len(array:old);
140 let new: *mut *mut ffi_type = ffi_type_array_create_empty(len:size);
141
142 for i: usize in 0..size {
143 *new.add(count:i) = ffi_type_clone(*old.add(count:i));
144 }
145
146 new
147}
148
149/// Makes a copy of a type.
150unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
151 if (*old).type_ == low::type_tag::STRUCT {
152 let low::ffi_type {
153 alignment: u16,
154 elements: *mut *mut ffi_type,
155 size: usize,
156 ..
157 } = *old;
158 let new: *mut ffi_type = ffi_type_struct_create_raw(elements:ffi_type_array_clone(old:elements), size, alignment);
159 new
160 } else {
161 old
162 }
163}
164
165/// Destroys a `TypeArray_` and all of its elements.
166unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
167 let mut current: *mut *mut ffi_type = victim;
168 while !(*current).is_null() {
169 ffi_type_destroy(*current);
170 current = current.offset(count:1);
171 }
172
173 libc::free(victim as *mut libc::c_void);
174}
175
176/// Destroys a `Type_` if it was dynamically allocated.
177unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
178 if (*victim).type_ == low::type_tag::STRUCT {
179 ffi_type_array_destroy((*victim).elements);
180 libc::free(victim as *mut libc::c_void);
181 }
182}
183
184impl Drop for Type {
185 fn drop(&mut self) {
186 unsafe { ffi_type_destroy(*self.0) }
187 }
188}
189
190impl Drop for TypeArray {
191 fn drop(&mut self) {
192 unsafe { ffi_type_array_destroy(*self.0) }
193 }
194}
195
196impl Clone for Type {
197 fn clone(&self) -> Self {
198 Type(unsafe { Unique::new(ptr:ffi_type_clone(*self.0)) })
199 }
200}
201
202impl Clone for TypeArray {
203 fn clone(&self) -> Self {
204 TypeArray(unsafe { Unique::new(ptr:ffi_type_array_clone(*self.0)) })
205 }
206}
207
208macro_rules! match_size_signed {
209 ( $name:ident ) => {
210 match mem::size_of::<libc::$name>() {
211 1 => Self::i8(),
212 2 => Self::i16(),
213 4 => Self::i32(),
214 8 => Self::i64(),
215 _ => panic!("Strange size for C type"),
216 }
217 };
218}
219
220macro_rules! match_size_unsigned {
221 ( $name:ident ) => {
222 match mem::size_of::<libc::$name>() {
223 1 => Self::u8(),
224 2 => Self::u16(),
225 4 => Self::u32(),
226 8 => Self::u64(),
227 _ => panic!("Strange size for C type"),
228 }
229 };
230}
231
232impl Type {
233 /// Returns the representation of the C `void` type.
234 ///
235 /// This is used only for the return type of a [CIF](super::Cif),
236 /// not for an argument or struct member.
237 pub fn void() -> Self {
238 Type(unsafe { Unique::new(&mut low::types::void) })
239 }
240
241 /// Returns the unsigned 8-bit numeric type.
242 pub fn u8() -> Self {
243 Type(unsafe { Unique::new(&mut low::types::uint8) })
244 }
245
246 /// Returns the signed 8-bit numeric type.
247 pub fn i8() -> Self {
248 Type(unsafe { Unique::new(&mut low::types::sint8) })
249 }
250
251 /// Returns the unsigned 16-bit numeric type.
252 pub fn u16() -> Self {
253 Type(unsafe { Unique::new(&mut low::types::uint16) })
254 }
255
256 /// Returns the signed 16-bit numeric type.
257 pub fn i16() -> Self {
258 Type(unsafe { Unique::new(&mut low::types::sint16) })
259 }
260
261 /// Returns the unsigned 32-bit numeric type.
262 pub fn u32() -> Self {
263 Type(unsafe { Unique::new(&mut low::types::uint32) })
264 }
265
266 /// Returns the signed 32-bit numeric type.
267 pub fn i32() -> Self {
268 Type(unsafe { Unique::new(&mut low::types::sint32) })
269 }
270
271 /// Returns the unsigned 64-bit numeric type.
272 pub fn u64() -> Self {
273 Type(unsafe { Unique::new(&mut low::types::uint64) })
274 }
275
276 /// Returns the signed 64-bit numeric type.
277 pub fn i64() -> Self {
278 Type(unsafe { Unique::new(&mut low::types::sint64) })
279 }
280
281 #[cfg(target_pointer_width = "16")]
282 /// Returns the C equivalent of Rust `usize` (`u16`).
283 pub fn usize() -> Self {
284 Self::u16()
285 }
286
287 #[cfg(target_pointer_width = "16")]
288 /// Returns the C equivalent of Rust `isize` (`i16`).
289 pub fn isize() -> Self {
290 Self::i16()
291 }
292
293 #[cfg(target_pointer_width = "32")]
294 /// Returns the C equivalent of Rust `usize` (`u32`).
295 pub fn usize() -> Self {
296 Self::u32()
297 }
298
299 #[cfg(target_pointer_width = "32")]
300 /// Returns the C equivalent of Rust `isize` (`i32`).
301 pub fn isize() -> Self {
302 Self::i32()
303 }
304
305 #[cfg(target_pointer_width = "64")]
306 /// Returns the C equivalent of Rust `usize` (`u64`).
307 pub fn usize() -> Self {
308 Self::u64()
309 }
310
311 #[cfg(target_pointer_width = "64")]
312 /// Returns the C equivalent of Rust `isize` (`i64`).
313 pub fn isize() -> Self {
314 Self::i64()
315 }
316
317 /// Returns the C `signed char` type.
318 pub fn c_schar() -> Self {
319 match_size_signed!(c_schar)
320 }
321
322 /// Returns the C `unsigned char` type.
323 pub fn c_uchar() -> Self {
324 match_size_unsigned!(c_uchar)
325 }
326
327 /// Returns the C `short` type.
328 pub fn c_short() -> Self {
329 match_size_signed!(c_short)
330 }
331
332 /// Returns the C `unsigned short` type.
333 pub fn c_ushort() -> Self {
334 match_size_unsigned!(c_ushort)
335 }
336
337 /// Returns the C `int` type.
338 pub fn c_int() -> Self {
339 match_size_signed!(c_int)
340 }
341
342 /// Returns the C `unsigned int` type.
343 pub fn c_uint() -> Self {
344 match_size_unsigned!(c_uint)
345 }
346
347 /// Returns the C `long` type.
348 pub fn c_long() -> Self {
349 match_size_signed!(c_long)
350 }
351
352 /// Returns the C `unsigned long` type.
353 pub fn c_ulong() -> Self {
354 match_size_unsigned!(c_ulong)
355 }
356
357 /// Returns the C `longlong` type.
358 pub fn c_longlong() -> Self {
359 match_size_signed!(c_longlong)
360 }
361
362 /// Returns the C `unsigned longlong` type.
363 pub fn c_ulonglong() -> Self {
364 match_size_unsigned!(c_ulonglong)
365 }
366
367 /// Returns the C `float` (32-bit floating point) type.
368 pub fn f32() -> Self {
369 Type(unsafe { Unique::new(&mut low::types::float) })
370 }
371
372 /// Returns the C `double` (64-bit floating point) type.
373 pub fn f64() -> Self {
374 Type(unsafe { Unique::new(&mut low::types::double) })
375 }
376
377 /// Returns the C `void*` type, for passing any kind of pointer.
378 pub fn pointer() -> Self {
379 Type(unsafe { Unique::new(&mut low::types::pointer) })
380 }
381
382 /// Returns the C `long double` (extended-precision floating point) type.
383 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
384 pub fn longdouble() -> Self {
385 Type(unsafe { Unique::new(&mut low::types::longdouble) })
386 }
387
388 /// Returns the C `_Complex float` type.
389 ///
390 /// This item is enabled by `#[cfg(feature = "complex")]`.
391 #[cfg(feature = "complex")]
392 pub fn c32() -> Self {
393 Type(unsafe { Unique::new(&mut low::types::complex_float) })
394 }
395
396 /// Returns the C `_Complex double` type.
397 ///
398 /// This item is enabled by `#[cfg(feature = "complex")]`.
399 #[cfg(feature = "complex")]
400 pub fn c64() -> Self {
401 Type(unsafe { Unique::new(&mut low::types::complex_double) })
402 }
403
404 /// Returns the C `_Complex long double` type.
405 ///
406 /// This item is enabled by `#[cfg(feature = "complex")]`.
407 #[cfg(feature = "complex")]
408 #[cfg(not(all(target_arch = "arm")))]
409 pub fn complex_longdouble() -> Self {
410 Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
411 }
412
413 /// Constructs a structure type whose fields have the given types.
414 pub fn structure<I>(fields: I) -> Self
415 where
416 I: IntoIterator<Item = Type>,
417 I::IntoIter: ExactSizeIterator<Item = Type>,
418 {
419 Type(unsafe { Unique::new(ffi_type_struct_create(fields.into_iter())) })
420 }
421
422 /// Gets a raw pointer to the underlying [`low::ffi_type`].
423 ///
424 /// This method may be useful for interacting with the
425 /// [`low`](crate::low) and [`raw`](crate::raw) layers.
426 pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
427 *self.0
428 }
429}
430
431impl TypeArray {
432 /// Constructs an array the given `Type`s.
433 pub fn new<I>(elements: I) -> Self
434 where
435 I: IntoIterator<Item = Type>,
436 I::IntoIter: ExactSizeIterator<Item = Type>,
437 {
438 TypeArray(unsafe { Unique::new(ptr:ffi_type_array_create(elements:elements.into_iter())) })
439 }
440
441 /// Gets a raw pointer to the underlying C array of
442 /// [`low::ffi_type`]s.
443 ///
444 /// The C array is null-terminated.
445 ///
446 /// This method may be useful for interacting with the
447 /// [`low`](crate::low) and [`raw`](crate::raw) layers.
448 pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
449 *self.0
450 }
451}
452
453#[cfg(test)]
454mod test {
455 use super::*;
456
457 #[test]
458 fn create_u64() {
459 Type::u64();
460 }
461
462 #[test]
463 fn clone_u64() {
464 let _ = Type::u64().clone().clone();
465 }
466
467 #[test]
468 fn create_struct() {
469 Type::structure(vec![Type::i64(), Type::i64(), Type::u64()]);
470 }
471
472 #[test]
473 fn clone_struct() {
474 let _ = Type::structure(vec![Type::i64(), Type::i64(), Type::u64()])
475 .clone()
476 .clone();
477 }
478}
479