use std::{os::fd::RawFd, sync::OnceLock}; use circular_buffer::CircularBuffer; use iddqd::{BiHashItem, IdOrdItem}; use mio::Token; use crate::prelude::*; const ERROR_BUFFER_LEN: usize = 8; #[derive(Debug)] pub struct FdInfo { pub fd: RawFd, pub kind: FdKind, pub name: OnceLock>, pub error_buffer: CircularBuffer, } impl FdInfo { pub fn new(fd: Fd, kind: FdKind) -> Self { Self { fd: fd.as_raw_fd(), kind, name: Default::default(), error_buffer: Default::default(), } } pub fn new_with_name(fd: Fd, kind: FdKind, name: Box) -> Self { Self { fd: fd.as_raw_fd(), kind, name: OnceLock::from(name), error_buffer: Default::default(), } } } impl FdInfo { pub(crate) fn guess_name(fd: Fd) -> Result, IoError> { let dev_fd_path = Path::new("/dev/fd").join(fd.as_raw_fd().to_string()); fs_err::read_link(dev_fd_path) .map(PathBuf::into_os_string) .map(OsString::into_boxed_os_str) } pub fn name(&self) -> &OsStr { if let Some(name) = self.name.get() { return name; } match Self::guess_name(self.fd) { Ok(name) => { let prev = self.name.set(Box::from(name)); debug_assert_eq!(prev, Ok(())); }, Err(e) => { warn!( "can't read link for {} /dev/fd/{}: {e}", self.kind.name_str(), self.fd, ); return OsStr::new("«unknown»"); }, } self.name.get().unwrap_or_else(|| unreachable!()) } } impl IdOrdItem for FdInfo { type Key<'a> = &'a RawFd; fn key(&self) -> &RawFd { &self.fd } iddqd::id_upcast!(); } #[derive(Copy)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[non_exhaustive] pub enum FdKind { File, Socket, SockStream, Poller, Unknown, } impl FdKind { pub fn name_str(self) -> &'static str { use FdKind::*; match self { File => "file", Socket => "socket", SockStream => "socket stream", Poller => "poller", Unknown => "«unknown»", } } } impl Default for FdKind { fn default() -> FdKind { FdKind::Unknown } } #[derive(Copy)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TokenFd { pub token: Token, pub fd: RawFd, } impl BiHashItem for TokenFd { type K1<'a> = Token; type K2<'a> = RawFd; fn key1(&self) -> Token { self.token } fn key2(&self) -> RawFd { self.fd } iddqd::bi_upcast!(); } impl From for (Token, RawFd) { fn from(TokenFd { token, fd }: TokenFd) -> (Token, RawFd) { (token, fd) } } impl From<(Token, RawFd)> for TokenFd { fn from((token, fd): (Token, RawFd)) -> TokenFd { TokenFd { token, fd } } }