Description
Firstly, I should say that I really like the basic ideas in RFC3128 (#87074) . I'm reporting a wrinkle which may or may not be soluble.
This program:
#![feature(io_safety)]
use std::os::unix::prelude::*;
fn main() -> std::io::Result<()> {
let file = std::fs::File::open("/dev/null")?;
let borrowed = file.as_fd();
let owned = borrowed.to_owned();
eprintln!("file={:?}\nborrd={:?}\nowned={:?}", &file, &borrowed, &owned);
Ok(())
}
Prints:
file=File { fd: 3, path: "/dev/null", read: true, write: false }
borrd=BorrowedFd { fd: 3 }
owned=BorrowedFd { fd: 3 }
A naive reader might have thought it would print:
file=File { fd: 3, path: "/dev/null", read: true, write: false }
borrd=BorrowedFd { fd: 3 }
owned=OwnedFd { fd: 4 }
But of course converting a borrowed to an owned fd is fallible. And there is no TryToOwned
. This no-op to_owned()
exists because BorrowedFd
is Copy
and therefore Clone
and eveyrhing Clone
has a no-op ToOwned
.
The ideal fix from a type system and traits point of view (other than going back in time and abolishing the blanket ToOwned for Clone
) would be for BorrowedFd
to somehow be a reference type. But it would have to actually be represented as an integer. pub struct BorrowableFdValue { x:() }
and transmuting c_int
via usize
to &BorrowableFdValue
and back would solve this but that is really quite stomach-churning (and the result can't be used in ffi the way the existing BorrowedFd
can).
Maybe the answer is to simply document this quirk. We should probably provide impl TryFrom<OwnedFd> from BorrowedFd
at the very least, and of course OwnedFd::try_clone()
.