From: Ian Jackson Date: Sun, 25 Feb 2024 00:53:36 +0000 (+0000) Subject: nix: Use cfg rather than trait hackery X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=d05864812aac6bcb5c3f8158ae2711d96975bc9b;p=hippotat.git nix: Use cfg rather than trait hackery Signed-off-by: Ian Jackson --- diff --git a/Cargo.lock b/Cargo.lock index 7ab5efb..f385461 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -538,6 +538,7 @@ version = "1.1.10" dependencies = [ "backtrace", "base64", + "cfg-if", "clap", "easy-ext", "educe", diff --git a/Cargo.lock.minimal b/Cargo.lock.minimal index d89736f..334b99a 100644 --- a/Cargo.lock.minimal +++ b/Cargo.lock.minimal @@ -566,6 +566,7 @@ version = "1.1.10" dependencies = [ "backtrace", "base64", + "cfg-if 1.0.0", "clap", "easy-ext", "educe", diff --git a/Cargo.toml b/Cargo.toml index 7605b39..6021933 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ backtrace = "0.3.3" base64 = "0.21" # clap 3 would work too at the time of writing, but it lacks the `wrap_help` # feature - that's built-in there. +cfg-if = "1" clap = { version = "4", features = ["derive", "wrap_help"] } easy-ext = "1" educe = ">=0.4.1, <0.6" diff --git a/debian/control b/debian/control index b0828f6..3e00749 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 12), cargo, rustc, python3-sphinx, # debian/update-build-deps manages these: librust-backtrace-dev (>= 0.3.3~) , librust-base64-dev (>= 0.21~) , + librust-cfg-if-dev (>= 1~) , librust-clap+derive-dev (>= 4~) , librust-easy-ext-dev (>= 1~) , librust-educe-dev (>= 0.4.1~) , diff --git a/src/compat.rs b/src/compat.rs index 445c758..eef04fe 100644 --- a/src/compat.rs +++ b/src/compat.rs @@ -1,67 +1,20 @@ +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 { - 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::. - // (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 { - type Arg = c_int; - unsafe fn arg(&self, fd: c_int) -> c_int { fd.as_raw_fd() } - } - impl Select for Option { - 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, 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, + ) }