file-reopen 0.1.0

reopen file on signal
Documentation
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

pub struct File {
    path: PathBuf,
    file: fs::File,
    should_rotate: Arc<AtomicBool>,
    sig_id: signal_hook::SigId,
}

impl File {
    pub fn open(path: impl AsRef<Path>) -> Result<Self, io::Error> {
        let flag = Arc::default();
        let file = Self::do_open(&path)?;

        let sig_id =
            signal_hook::flag::register(signal_hook::consts::signal::SIGHUP, Arc::clone(&flag))?;

        let file = File {
            path: path.as_ref().to_owned(),
            file,
            should_rotate: Arc::clone(&flag),
            sig_id,
        };
        Ok(file)
    }

    fn do_open(path: impl AsRef<Path>) -> Result<fs::File, io::Error> {
        fs::OpenOptions::new().append(true).create(true).open(path)
    }

    fn reopen_if_needed(&mut self) -> Result<(), io::Error> {
        if self.should_rotate.swap(false, Ordering::Relaxed) {
            self.file.sync_all()?;
            self.file = Self::do_open(&self.path)?;
        }
        Ok(())
    }
}

impl Drop for File {
    fn drop(&mut self) {
        signal_hook::low_level::unregister(self.sig_id);
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.reopen_if_needed()?;
        self.file.write(buf)
    }

    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
        self.reopen_if_needed()?;
        self.file.write_vectored(bufs)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}