# debian/update-build-deps manages these:
librust-backtrace-dev (>= 0.3.3~) <!upstream-cargo>,
librust-base64-dev (>= 0.21~) <!upstream-cargo>,
+ librust-cfg-if-dev (>= 1~) <!upstream-cargo>,
librust-clap+derive-dev (>= 4~) <!upstream-cargo>,
librust-easy-ext-dev (>= 1~) <!upstream-cargo>,
librust-educe-dev (>= 0.4.1~) <!upstream-cargo>,
+use cfg_if::cfg_if;
use crate::prelude::*;
-/// Version of [`nix::sys::uio::writev`] with a known type for the fd
+/// Version of [`nix::sys::uio::writev`] with a fixed type for the fd
//
/// * nix <=0.26 has `fd: c_int`
/// * nix >=0.27 has `fd: impl AsFd`
pub unsafe fn writev(fd: c_int, iov: &[IoSlice]) -> nix::Result<usize> {
- use std::mem::MaybeUninit;
- use std::os::fd::AsRawFd as _;
-
- // This is not so straightforward. To provide `impl AsFd` we
- // need to specify something with a concrete type, so that the
- // compiler can select the AsFd impl. But c_int doesn't impl AsFd.
- //
- // So we must pass something whose type is statically inferrable,
- // but differs with the two nix versions.
- //
- // Selection based on presence/absence of names is no good because
- // the ambiguity errors mean we can't rely on shadowing.
- //
- // We could depend on the type of `writev`, but when it's a generic
- // function it doesn't *have* a type.
- //
- // But! nix changed the type of `OpenptyResult`, as part of the
- // same fd-safety update. We can use that. We use the type of its
- // fields, which is either OwnedFd (the new io-safe type from std)
- // or RawFd aka c_int. We can't *name* the type, since we can't
- // get the type name of the field.
- //
- // But we can trick the compiler into *infeerring* from that type
- // to give us a value None::<WhateverOpenPtyResultHas>.
- // (We mustn't actually create an OwnedFd since those close the fd
- // on drop!)
-
- trait Select {
- type Arg;
- unsafe fn arg(&self, fd: c_int) -> Self::Arg;
- }
- impl Select for Option<c_int> {
- type Arg = c_int;
- unsafe fn arg(&self, fd: c_int) -> c_int { fd.as_raw_fd() }
- }
- impl Select for Option<OwnedFd> {
- type Arg = BorrowedFd<'static>;
- unsafe fn arg(&self, fd: c_int) -> BorrowedFd<'static> {
- BorrowedFd::borrow_raw(fd)
- }
- }
-
- let select = if false {
- #[allow(invalid_value)] // SAFETY: UB, but inside `if false`
- unsafe {
- let x: nix::pty::OpenptyResult = MaybeUninit::uninit().assume_init();
- Some(x.master) // decides the type of the if, therefore of the select
- }
- } else {
- // this branch actually runs
- None
- };
-
- nix::sys::uio::writev(select.arg(fd), iov)
-
- // `select`, which might be Option<OwnedFd>, gets dropped here,
- // but it's always None. We hope the compiler will notice this
- // and remove the unreachable call to close(2).
+ nix::sys::uio::writev(
+ { cfg_if! {
+ if #[cfg(nix_0_27)] {
+ BorrowedFd::borrow_raw(fd)
+ } else {
+ fd
+ }
+ }},
+ iov,
+ )
}