Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide C FFI types via core::ffi, not just in std
The ability to interoperate with C code via FFI is not limited to crates using std; this allows using these types without std. The existing types in `std::os::raw` become type aliases for the ones in `core::ffi`. This uses type aliases rather than re-exports, to allow the std types to remain stable while the core types are unstable. This also moves the currently unstable `NonZero_` variants and `c_size_t`/`c_ssize_t`/`c_ptrdiff_t` types to `core::ffi`, while leaving them unstable.
- Loading branch information
1 parent
0f505c6
commit 335c960
Showing
22 changed files
with
189 additions
and
166 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Equivalent to C's `void` type when used as a [pointer]. | ||
|
||
In essence, `*const c_void` is equivalent to C's `const void*` | ||
and `*mut c_void` is equivalent to C's `void*`. That said, this is | ||
*not* the same as C's `void` return type, which is Rust's `()` type. | ||
|
||
To model pointers to opaque types in FFI, until `extern type` is | ||
stabilized, it is recommended to use a newtype wrapper around an empty | ||
byte array. See the [Nomicon] for details. | ||
|
||
One could use `std::os::raw::c_void` if they want to support old Rust | ||
compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by | ||
this definition. For more information, please read [RFC 2521]. | ||
|
||
[Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs | ||
[RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,156 +1,31 @@ | ||
//! Platform-specific types, as defined by C. | ||
//! | ||
//! Code that interacts via FFI will almost certainly be using the | ||
//! base types provided by C, which aren't nearly as nicely defined | ||
//! as Rust's primitive types. This module provides types which will | ||
//! match those defined by C, so that code that interacts with C will | ||
//! refer to the correct types. | ||
//! Compatibility module for C platform-specific types. Use [`core::ffi`] instead. | ||
|
||
#![stable(feature = "raw_os", since = "1.1.0")] | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
use core::num::*; | ||
|
||
macro_rules! type_alias_no_nz { | ||
{ | ||
$Docfile:tt, $Alias:ident = $Real:ty; | ||
$( $Cfg:tt )* | ||
} => { | ||
#[doc = include_str!($Docfile)] | ||
$( $Cfg )* | ||
macro_rules! alias_core_ffi { | ||
($($t:ident)*) => {$( | ||
#[stable(feature = "raw_os", since = "1.1.0")] | ||
pub type $Alias = $Real; | ||
} | ||
} | ||
|
||
// To verify that the NonZero types in this file's macro invocations correspond | ||
// | ||
// perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2' | ||
// | ||
// NB this does not check that the main c_* types are right. | ||
|
||
macro_rules! type_alias { | ||
{ | ||
$Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty; | ||
$( $Cfg:tt )* | ||
} => { | ||
type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* } | ||
|
||
#[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")] | ||
#[unstable(feature = "raw_os_nonzero", issue = "82363")] | ||
$( $Cfg )* | ||
pub type $NZAlias = $NZReal; | ||
} | ||
#[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))] | ||
// Make this type alias appear cfg-dependent so that Clippy does not suggest | ||
// replacing expressions like `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be | ||
// removed after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 | ||
// is fixed. | ||
#[cfg(all())] | ||
#[doc(cfg(all()))] | ||
pub type $t = core::ffi::$t; | ||
)*} | ||
} | ||
|
||
type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char; | ||
// Make this type alias appear cfg-dependent so that Clippy does not suggest | ||
// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed | ||
// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 | ||
// is fixed. | ||
#[cfg(all())] | ||
#[doc(cfg(all()))] } | ||
type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; } | ||
type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; } | ||
type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; } | ||
type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } | ||
type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } | ||
type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } | ||
type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; | ||
#[doc(cfg(all()))] | ||
#[cfg(any(target_pointer_width = "32", windows))] } | ||
type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; | ||
#[doc(cfg(all()))] | ||
#[cfg(any(target_pointer_width = "32", windows))] } | ||
type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; | ||
#[doc(cfg(all()))] | ||
#[cfg(all(target_pointer_width = "64", not(windows)))] } | ||
type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; | ||
#[doc(cfg(all()))] | ||
#[cfg(all(target_pointer_width = "64", not(windows)))] } | ||
type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } | ||
type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } | ||
type_alias_no_nz! { "float.md", c_float = f32; } | ||
type_alias_no_nz! { "double.md", c_double = f64; } | ||
|
||
#[stable(feature = "raw_os", since = "1.1.0")] | ||
#[doc(no_inline)] | ||
pub use core::ffi::c_void; | ||
|
||
/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++). | ||
/// | ||
/// This type is currently always [`usize`], however in the future there may be | ||
/// platforms where this is not the case. | ||
#[unstable(feature = "c_size_t", issue = "88345")] | ||
pub type c_size_t = usize; | ||
|
||
/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++). | ||
/// | ||
/// This type is currently always [`isize`], however in the future there may be | ||
/// platforms where this is not the case. | ||
#[unstable(feature = "c_size_t", issue = "88345")] | ||
pub type c_ptrdiff_t = isize; | ||
|
||
/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type. | ||
/// | ||
/// This type is currently always [`isize`], however in the future there may be | ||
/// platforms where this is not the case. | ||
#[unstable(feature = "c_size_t", issue = "88345")] | ||
pub type c_ssize_t = isize; | ||
|
||
mod c_char_definition { | ||
cfg_if::cfg_if! { | ||
// These are the targets on which c_char is unsigned. | ||
if #[cfg(any( | ||
all( | ||
target_os = "linux", | ||
any( | ||
target_arch = "aarch64", | ||
target_arch = "arm", | ||
target_arch = "hexagon", | ||
target_arch = "powerpc", | ||
target_arch = "powerpc64", | ||
target_arch = "s390x", | ||
target_arch = "riscv64", | ||
target_arch = "riscv32" | ||
) | ||
), | ||
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), | ||
all(target_os = "l4re", target_arch = "x86_64"), | ||
all( | ||
target_os = "freebsd", | ||
any( | ||
target_arch = "aarch64", | ||
target_arch = "arm", | ||
target_arch = "powerpc", | ||
target_arch = "powerpc64", | ||
target_arch = "riscv64" | ||
) | ||
), | ||
all( | ||
target_os = "netbsd", | ||
any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") | ||
), | ||
all(target_os = "openbsd", target_arch = "aarch64"), | ||
all( | ||
target_os = "vxworks", | ||
any( | ||
target_arch = "aarch64", | ||
target_arch = "arm", | ||
target_arch = "powerpc64", | ||
target_arch = "powerpc" | ||
) | ||
), | ||
all(target_os = "fuchsia", target_arch = "aarch64") | ||
))] { | ||
pub type c_char = u8; | ||
pub type NonZero_c_char = core::num::NonZeroU8; | ||
} else { | ||
// On every other target, c_char is signed. | ||
pub type c_char = i8; | ||
pub type NonZero_c_char = core::num::NonZeroI8; | ||
} | ||
} | ||
alias_core_ffi! { | ||
c_char c_schar c_uchar | ||
c_short c_ushort | ||
c_int c_uint | ||
c_long c_ulong | ||
c_longlong c_ulonglong | ||
c_float | ||
c_double | ||
c_void | ||
} |
Oops, something went wrong.