#![doc(test(attr(deny(warnings))))]
#![warn(missing_docs)]
#![cfg_attr(not(test), forbid(unsafe_code))]
use std::fmt::{self, Debug, Formatter, Result as FmtResult};
use std::io::{Error, Read, Write};
#[cfg(vectored)]
use std::io::{IoSlice, IoSliceMut};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
#[cfg(feature = "signals")]
mod signals;
#[derive(Clone, Debug)]
pub struct Handle(Arc<AtomicBool>);
impl Handle {
pub fn reopen(&self) {
self.0.store(true, Ordering::Relaxed);
}
pub fn stub() -> Self {
Handle(Arc::new(AtomicBool::new(false)))
}
}
pub struct Reopen<FD> {
signal: Arc<AtomicBool>,
constructor: Box<dyn Fn() -> Result<FD, Error> + Send>,
fd: Option<FD>,
}
impl<FD> Reopen<FD> {
pub fn new(constructor: Box<dyn Fn() -> Result<FD, Error> + Send>) -> Result<Self, Error> {
Self::with_handle(Handle::stub(), constructor)
}
pub fn with_handle(
handle: Handle,
constructor: Box<dyn Fn() -> Result<FD, Error> + Send>,
) -> Result<Self, Error> {
let fd = constructor()?;
Ok(Self {
signal: handle.0,
constructor,
fd: Some(fd),
})
}
pub fn handle(&self) -> Handle {
Handle(Arc::clone(&self.signal))
}
pub fn lock(&mut self) -> Result<&mut FD, Error> {
if self.signal.swap(false, Ordering::Relaxed) {
self.fd.take();
}
if self.fd.is_none() {
self.fd = Some((self.constructor)()?);
}
Ok(self.fd.as_mut().unwrap())
}
}
impl<FD: Debug> Debug for Reopen<FD> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("Reopen")
.field("signal", &self.signal)
.field("fd", &self.fd)
.field("constructor", &"...")
.finish()
}
}
impl<FD: Read> Read for Reopen<FD> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let fd = self.lock()?;
fd.read(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
let fd = self.lock()?;
fd.read_exact(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> {
let fd = self.lock()?;
fd.read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> Result<usize, Error> {
let fd = self.lock()?;
fd.read_to_string(buf)
}
#[cfg(vectored)]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize, Error> {
let fd = self.check()?;
fd.read_vectored(bufs)
}
}
impl<FD: Write> Write for Reopen<FD> {
fn flush(&mut self) -> Result<(), Error> {
let fd = self.lock()?;
fd.flush()
}
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
let fd = self.lock()?;
fd.write(buf)
}
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error> {
let fd = self.lock()?;
fd.write_all(buf)
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<(), Error> {
let fd = self.lock()?;
fd.write_fmt(fmt)
}
#[cfg(vectored)]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize, Error> {
let fd = self.check()?;
fd.write_vectored(bufs)
}
}