#![doc(html_root_url = "https://docs.rs/reopen/0.3.0/reopen/")]
#![warn(missing_docs)]
use std::io::{Error, Read, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
#[cfg(unix)]
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<Fn() -> Result<FD, Error> + Send>,
fd: Option<FD>,
}
impl<FD> Reopen<FD> {
pub fn new(constructor: Box<Fn() -> Result<FD, Error> + Send>) -> Result<Self, Error> {
Self::with_handle(Handle::stub(), constructor)
}
pub fn with_handle(
handle: Handle,
constructor: Box<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))
}
fn check(&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: Read> Read for Reopen<FD> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
self.check().and_then(|fd| fd.read(buf))
}
}
impl<FD: Write> Write for Reopen<FD> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
self.check().and_then(|fd| fd.write(buf))
}
fn flush(&mut self) -> Result<(), Error> {
self.check().and_then(Write::flush)
}
}