Reference ownership exercise
Sep. 5th, 2019 05:25 pmhttps://doc.rust-lang.org/stable/book/ is good to start with, but slow.
So I tried to see how to use pselect for a practical purpose. There is https://gist.github.com/AGWA/b0931a912a8b22b2d6178a3155e171f3, of course, with a lot of interesting juggling there. But if we are learning, we won't copy-paste, and instead do the other way around - rewrite the things that are wrapped in FdSet (which is probably a good idea, but we are learning) as functions that use references to libc::fd_set, and rewrite the functions to_fdset_ptr and to_ptr that do raw translations as a new trait implementation.
The goal:
The thing is,
I have a solution that works, and I think I know why it works, and the "straightforward" solution doesn't. In essence, https://doc.rust-lang.org/std/option/enum.Option.html#method.take is very important. (There's also a curious as_mut() method). The implementation of Iterators is very informative: https://doc.rust-lang.org/nomicon/borrow-splitting.html
So I tried to see how to use pselect for a practical purpose. There is https://gist.github.com/AGWA/b0931a912a8b22b2d6178a3155e171f3, of course, with a lot of interesting juggling there. But if we are learning, we won't copy-paste, and instead do the other way around - rewrite the things that are wrapped in FdSet (which is probably a good idea, but we are learning) as functions that use references to libc::fd_set, and rewrite the functions to_fdset_ptr and to_ptr that do raw translations as a new trait implementation.
The goal:
pub trait Nullable {
type N;
fn or_null(&self) -> *const Self::N;
}
impl<T> Nullable for Option<&T> {
...
}
pub trait MutNullable {
type N;
fn or_null_mut(&self) -> *mut Self::N;
}
impl<T> MutNullable for Option<&mut T> {
...
}
fn pselect(nfds: usize,
read: Option<&mut libc::fd_set>,
write: Option<&mut libc::fd_set>,
err: Option<&mut libc::fd_set>,
timeout: Option<&libc::timespec>,
sigmask: Option<&libc::sigset_t>) -> std::io::Result<usize> {
unsafe {
let i = libc::pselect(
nfds as libc::c_int,
read.or_null_mut(),
write.or_null_mut(),
err.or_null_mut(),
timeout.or_null(),
sigmask.or_null()
);
if i < 0 {
return Err(io::Error::last_os_error());
}
Ok(i as usize)
}
}The thing is,
libc::pselect(
nfds as libc::c_int,
read.map(|r| r as *mut libc::fd_set).unwrap_or_else(ptr::null_mut),
...
);works, impl<T> Nullable for Option<&T> {
type N = T;
fn or_null(&self) -> *const T {
self.map(|v| v as *const T).unwrap_or_else(ptr::null)
}
} also works, but impl<T> MutNullable for Option<&mut T> {
type N = T;
fn or_null_mut(&self) -> *mut T {
self.map(|r| r as *mut T).unwrap_or_else(ptr::null_mut)
}
}doesn't. Curious, eh?I have a solution that works, and I think I know why it works, and the "straightforward" solution doesn't. In essence, https://doc.rust-lang.org/std/option/enum.Option.html#method.take is very important. (There's also a curious as_mut() method). The implementation of Iterators is very informative: https://doc.rust-lang.org/nomicon/borrow-splitting.html