Skip to content

Commit 99404fc

Browse files
authored
Remove most linux-raw-sys types from the public API (#1277)
* Define our own types for `Winsize` and `Sysinfo` * Remove `WaitIdStatus::as_raw`. * Remove more C types from the public API * Use custom definitions of incomplete array and union fields.
1 parent 900cc84 commit 99404fc

11 files changed

Lines changed: 215 additions & 43 deletions

File tree

examples/stdio.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,6 @@ use {
1818
rustix::stdio::{stderr, stdin, stdout},
1919
};
2020

21-
#[cfg(feature = "termios")]
22-
#[cfg(all(not(windows), feature = "stdio"))]
23-
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
24-
struct DebugWinsize(rustix::termios::Winsize);
25-
26-
#[cfg(feature = "termios")]
27-
#[cfg(all(not(windows), feature = "stdio"))]
28-
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
29-
impl core::fmt::Debug for DebugWinsize {
30-
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31-
let mut d = f.debug_struct("Winsize");
32-
d.field("ws_row", &self.0.ws_row);
33-
d.field("ws_col", &self.0.ws_col);
34-
d.field("ws_xpixel", &self.0.ws_xpixel);
35-
d.field("ws_ypixel", &self.0.ws_ypixel);
36-
d.finish()
37-
}
38-
}
39-
4021
#[cfg(all(not(windows), feature = "stdio"))]
4122
fn main() -> io::Result<()> {
4223
let (stdin, stdout, stderr) = (stdin(), stdout(), stderr());
@@ -74,10 +55,7 @@ fn show<Fd: AsFd>(fd: Fd) -> io::Result<()> {
7455
println!(" - process group: {:?}", rustix::termios::tcgetpgrp(fd)?);
7556

7657
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
77-
println!(
78-
" - winsize: {:?}",
79-
DebugWinsize(rustix::termios::tcgetwinsize(fd)?)
80-
);
58+
println!(" - winsize: {:?}", rustix::termios::tcgetwinsize(fd)?);
8159

8260
#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
8361
{

src/backend/linux_raw/c.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub(crate) use linux_raw_sys::general::{
1818
__kernel_pid_t as pid_t, __kernel_time64_t as time_t, __kernel_timespec as timespec, iovec,
1919
O_CLOEXEC, O_NOCTTY, O_NONBLOCK, O_RDWR,
2020
};
21+
#[cfg(feature = "system")]
22+
pub(crate) use linux_raw_sys::system::sysinfo;
2123

2224
#[cfg(feature = "event")]
2325
#[cfg(test)]

src/backend/linux_raw/fs/inotify.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! inotify support for working with inotify objects.
22
3-
use crate::backend::c;
43
use crate::ffi;
54
use bitflags::bitflags;
65

@@ -84,7 +83,7 @@ bitflags! {
8483
/// [`inotify::Reader`]: crate::fs::inotify::InotifyReader
8584
#[repr(transparent)]
8685
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
87-
pub struct ReadFlags: c::c_uint {
86+
pub struct ReadFlags: ffi::c_uint {
8887
/// `IN_ACCESS`
8988
const ACCESS = linux_raw_sys::general::IN_ACCESS;
9089
/// `IN_ATTRIB`
Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,39 @@
1+
use crate::ffi;
2+
13
/// `sysinfo`
2-
pub type Sysinfo = linux_raw_sys::system::sysinfo;
4+
#[non_exhaustive]
5+
#[repr(C)]
6+
pub struct Sysinfo {
7+
/// Seconds since boot
8+
pub uptime: ffi::c_long,
9+
/// 1, 5, and 15 minute load averages
10+
pub loads: [ffi::c_ulong; 3],
11+
/// Total usable main memory size
12+
pub totalram: ffi::c_ulong,
13+
/// Available memory size
14+
pub freeram: ffi::c_ulong,
15+
/// Amount of shared memory
16+
pub sharedram: ffi::c_ulong,
17+
/// Memory used by buffers
18+
pub bufferram: ffi::c_ulong,
19+
/// Total swap space size
20+
pub totalswap: ffi::c_ulong,
21+
/// Swap space still available
22+
pub freeswap: ffi::c_ulong,
23+
/// Number of current processes
24+
pub procs: ffi::c_ushort,
25+
26+
pub(crate) pad: ffi::c_ushort,
27+
28+
/// Total high memory size
29+
pub totalhigh: ffi::c_ulong,
30+
/// Available high memory size
31+
pub freehigh: ffi::c_ulong,
32+
/// Memory unit size in bytes
33+
pub mem_unit: ffi::c_uint,
34+
35+
pub(crate) f:
36+
[u8; 20 - 2 * core::mem::size_of::<ffi::c_long>() - core::mem::size_of::<ffi::c_int>()],
37+
}
338

439
pub(crate) type RawUname = linux_raw_sys::system::new_utsname;

src/check_types.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ macro_rules! check_struct_renamed_field {
5454
};
5555
}
5656

57+
/// The same as `check_struct_field`, but for when the struct is renamed
58+
/// but the field is not.
59+
macro_rules! check_renamed_struct_field {
60+
($to_struct:ident, $from_struct:ident, $field:ident) => {
61+
const_assert_eq!(
62+
memoffset::offset_of!($to_struct, $field),
63+
memoffset::offset_of!(c::$from_struct, $field)
64+
);
65+
66+
// As above, this can't use `const_assert_eq`.
67+
assert_eq!(
68+
memoffset::span_of!($to_struct, $field),
69+
memoffset::span_of!(c::$from_struct, $field)
70+
);
71+
};
72+
}
73+
5774
/// The same as `check_struct_renamed_field`, but for when both the struct and
5875
/// a field are renamed.
5976
macro_rules! check_renamed_struct_renamed_field {

src/event/epoll.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@
7373
#![allow(unused_qualifications)]
7474

7575
use super::epoll;
76-
#[cfg(feature = "alloc")]
77-
use crate::backend::c;
7876
pub use crate::backend::event::epoll::*;
7977
use crate::backend::event::syscalls;
8078
use crate::fd::{AsFd, OwnedFd};
@@ -205,7 +203,7 @@ pub fn delete<EpollFd: AsFd, SourceFd: AsFd>(epoll: EpollFd, source: SourceFd) -
205203
pub fn wait<EpollFd: AsFd>(
206204
epoll: EpollFd,
207205
event_list: &mut EventVec,
208-
timeout: c::c_int,
206+
timeout: crate::ffi::c_int,
209207
) -> io::Result<()> {
210208
// SAFETY: We're calling `epoll_wait` via FFI and we know how it
211209
// behaves.
@@ -456,6 +454,7 @@ impl<'a> IntoIterator for &'a EventVec {
456454
#[cfg(test)]
457455
mod tests {
458456
use super::*;
457+
use crate::backend::c;
459458

460459
#[test]
461460
fn test_epoll_layouts() {

src/io_uring/bindgen_types.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! Local versions of types that bindgen would use.
2+
3+
/// This represents an incomplete array field at the end of a struct.
4+
///
5+
/// This is called `__IncompleteArrayField` in bindgen bindings.
6+
#[repr(C)]
7+
#[derive(Default)]
8+
pub struct IncompleteArrayField<T>(::core::marker::PhantomData<T>, [T; 0]);
9+
10+
#[allow(missing_docs)]
11+
impl<T> IncompleteArrayField<T> {
12+
#[inline]
13+
pub const fn new() -> Self {
14+
IncompleteArrayField(::core::marker::PhantomData, [])
15+
}
16+
17+
#[inline]
18+
pub fn as_ptr(&self) -> *const T {
19+
self as *const _ as *const T
20+
}
21+
22+
#[inline]
23+
pub fn as_mut_ptr(&mut self) -> *mut T {
24+
self as *mut _ as *mut T
25+
}
26+
27+
#[inline]
28+
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
29+
::core::slice::from_raw_parts(self.as_ptr(), len)
30+
}
31+
32+
#[inline]
33+
pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
34+
::core::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
35+
}
36+
}
37+
38+
impl<T> ::core::fmt::Debug for IncompleteArrayField<T> {
39+
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
40+
fmt.write_str("IncompleteArrayField")
41+
}
42+
}
43+
44+
/// This represents a toplevel union field.
45+
///
46+
/// This is called `__BindgenUnionField` in bindgen bindings.
47+
pub struct UnionField<T>(::core::marker::PhantomData<T>);
48+
49+
#[allow(missing_docs)]
50+
impl<T> UnionField<T> {
51+
#[inline]
52+
pub const fn new() -> Self {
53+
UnionField(::core::marker::PhantomData)
54+
}
55+
56+
#[inline]
57+
pub unsafe fn as_ref(&self) -> &T {
58+
::core::mem::transmute(self)
59+
}
60+
61+
#[inline]
62+
pub unsafe fn as_mut(&mut self) -> &mut T {
63+
::core::mem::transmute(self)
64+
}
65+
}
66+
67+
impl<T> ::core::default::Default for UnionField<T> {
68+
#[inline]
69+
fn default() -> Self {
70+
Self::new()
71+
}
72+
}
73+
74+
impl<T> ::core::clone::Clone for UnionField<T> {
75+
#[inline]
76+
fn clone(&self) -> Self {
77+
*self
78+
}
79+
}
80+
81+
impl<T> ::core::marker::Copy for UnionField<T> {}
82+
83+
impl<T> ::core::fmt::Debug for UnionField<T> {
84+
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
85+
fmt.write_str("UnionField")
86+
}
87+
}
88+
89+
impl<T> ::core::hash::Hash for UnionField<T> {
90+
fn hash<H: ::core::hash::Hasher>(&self, _state: &mut H) {}
91+
}
92+
93+
impl<T> ::core::cmp::PartialEq for UnionField<T> {
94+
fn eq(&self, _other: &UnionField<T>) -> bool {
95+
true
96+
}
97+
}
98+
99+
impl<T> ::core::cmp::Eq for UnionField<T> {}

src/io_uring.rs renamed to src/io_uring/mod.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
//! [rustix-uring]: https://crates.io/crates/rustix-uring
2525
#![allow(unsafe_code)]
2626

27+
mod bindgen_types;
28+
2729
use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd};
2830
use crate::{backend, io};
31+
use bindgen_types::*;
2932
use core::ffi::c_void;
3033
use core::mem::MaybeUninit;
3134
use core::ptr::{null_mut, write_bytes};
@@ -1210,7 +1213,7 @@ pub struct io_uring_cqe {
12101213
pub user_data: io_uring_user_data,
12111214
pub res: i32,
12121215
pub flags: IoringCqeFlags,
1213-
pub big_cqe: sys::__IncompleteArrayField<u64>,
1216+
pub big_cqe: IncompleteArrayField<u64>,
12141217
}
12151218

12161219
#[allow(missing_docs)]
@@ -1286,7 +1289,7 @@ pub struct io_uring_probe {
12861289
pub ops_len: u8,
12871290
pub resv: u16,
12881291
pub resv2: [u32; 3],
1289-
pub ops: sys::__IncompleteArrayField<io_uring_probe_op>,
1292+
pub ops: IncompleteArrayField<io_uring_probe_op>,
12901293
}
12911294

12921295
#[allow(missing_docs)]
@@ -1416,15 +1419,15 @@ pub struct buf_ring_tail_struct {
14161419
#[repr(C)]
14171420
#[derive(Debug, Default)]
14181421
pub struct buf_ring_bufs_struct {
1419-
pub bufs: sys::__IncompleteArrayField<io_uring_buf>,
1422+
pub bufs: IncompleteArrayField<io_uring_buf>,
14201423
}
14211424

14221425
#[allow(missing_docs)]
14231426
#[repr(C)]
14241427
#[derive(Debug, Default)]
14251428
pub struct tail_or_bufs_struct {
1426-
pub tail: sys::__BindgenUnionField<buf_ring_tail_struct>,
1427-
pub bufs: sys::__BindgenUnionField<buf_ring_bufs_struct>,
1429+
pub tail: UnionField<buf_ring_tail_struct>,
1430+
pub bufs: UnionField<buf_ring_bufs_struct>,
14281431
pub union_field: [u64; 2],
14291432
}
14301433

src/process/wait.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,6 @@ impl WaitIdStatus {
225225
}
226226
}
227227

228-
/// Returns a reference to the raw platform-specific `siginfo_t` struct.
229-
#[inline]
230-
pub const fn as_raw(&self) -> &backend::c::siginfo_t {
231-
&self.0
232-
}
233-
234228
#[cfg(linux_raw)]
235229
fn si_code(&self) -> u32 {
236230
self.0.si_code() as u32 // CLD_ consts are unsigned

src/system.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#![allow(unsafe_code)]
88

99
use crate::backend;
10-
#[cfg(linux_kernel)]
10+
#[cfg(target_os = "linux")]
1111
use crate::backend::c;
1212
use crate::ffi::CStr;
1313
#[cfg(not(any(target_os = "espidf", target_os = "emscripten", target_os = "vita")))]
@@ -20,7 +20,7 @@ pub use backend::system::types::Sysinfo;
2020
#[cfg(linux_kernel)]
2121
use crate::fd::AsFd;
2222
#[cfg(linux_kernel)]
23-
use c::c_int;
23+
use crate::ffi::c_int;
2424

2525
/// `uname()`—Returns high-level information about the runtime OS and
2626
/// hardware.
@@ -282,3 +282,35 @@ pub fn finit_module<Fd: AsFd>(fd: Fd, param_values: &CStr, flags: c_int) -> io::
282282
pub fn delete_module(name: &CStr, flags: c_int) -> io::Result<()> {
283283
backend::system::syscalls::delete_module(name, flags)
284284
}
285+
286+
#[cfg(test)]
287+
mod tests {
288+
#[allow(unused_imports)]
289+
use super::*;
290+
#[allow(unused_imports)]
291+
use crate::backend::c;
292+
293+
#[cfg(linux_kernel)]
294+
#[test]
295+
fn test_sysinfo_layouts() {
296+
// Don't assert the size for `Sysinfo` because `c::sysinfo` has a
297+
// computed-size padding field at the end that bindgen doesn't support,
298+
// and `c::sysinfo` may add fields over time.
299+
assert_eq!(
300+
core::mem::align_of::<Sysinfo>(),
301+
core::mem::align_of::<c::sysinfo>()
302+
);
303+
check_renamed_struct_field!(Sysinfo, sysinfo, uptime);
304+
check_renamed_struct_field!(Sysinfo, sysinfo, loads);
305+
check_renamed_struct_field!(Sysinfo, sysinfo, totalram);
306+
check_renamed_struct_field!(Sysinfo, sysinfo, freeram);
307+
check_renamed_struct_field!(Sysinfo, sysinfo, sharedram);
308+
check_renamed_struct_field!(Sysinfo, sysinfo, bufferram);
309+
check_renamed_struct_field!(Sysinfo, sysinfo, totalswap);
310+
check_renamed_struct_field!(Sysinfo, sysinfo, freeswap);
311+
check_renamed_struct_field!(Sysinfo, sysinfo, procs);
312+
check_renamed_struct_field!(Sysinfo, sysinfo, totalhigh);
313+
check_renamed_struct_field!(Sysinfo, sysinfo, freehigh);
314+
check_renamed_struct_field!(Sysinfo, sysinfo, mem_unit);
315+
}
316+
}

0 commit comments

Comments
 (0)