chiark / gitweb /
nix: Use cfg rather than trait hackery
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Feb 2024 00:53:36 +0000 (00:53 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Feb 2024 17:13:37 +0000 (17:13 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock
Cargo.lock.minimal
Cargo.toml
debian/control
src/compat.rs

index 7ab5efb2a8d1f1f95c7ee292ed89c44d132d585c..f38546111e33c5a8c6133db64e609e99dc8979bc 100644 (file)
@@ -538,6 +538,7 @@ version = "1.1.10"
 dependencies = [
  "backtrace",
  "base64",
+ "cfg-if",
  "clap",
  "easy-ext",
  "educe",
index d89736fd8e2b4db30f1f35da75277c58becc666b..334b99a2048ecc13d6f408400163942474b3580f 100644 (file)
@@ -566,6 +566,7 @@ version = "1.1.10"
 dependencies = [
  "backtrace",
  "base64",
+ "cfg-if 1.0.0",
  "clap",
  "easy-ext",
  "educe",
index 7605b391eb88e7da9299e0deecb91e3f2fedcc59..6021933148751486e46871910002ebd40d93f7e4 100644 (file)
@@ -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"
index b0828f61fa4fee3067a70472f226a57879a50665..3e00749f55f4aa5a2886812d479a7c331f1b1c35 100644 (file)
@@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 12), cargo, rustc, python3-sphinx,
 # 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>,
index 445c758e3eaf4c7e4c08016c3a18bd31870bf0cd..eef04fe047b85878050e0cc4d8f206c156f7a71b 100644 (file)
@@ -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<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,
+  )
 }