use std::{fs::File, os::unix::fs::MetadataExt as _, sync::mpsc}; use chrono::{DateTime, Local}; use egui::Id; use eyre::{Context, ContextCompat}; use rand::{Rng, rng}; pub fn random_id() -> Id { Id::new(rng().random::()) } /// An [mpsc::Sender] where the receiver is the GUI. #[derive(Clone)] pub struct GuiSender { tx: mpsc::Sender, ctx: egui::Context, } impl GuiSender { pub fn new(tx: mpsc::Sender, ctx: &egui::Context) -> Self { Self { tx, ctx: ctx.clone(), } } pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { self.tx.send(t)?; self.ctx.request_repaint(); Ok(()) } } #[track_caller] pub fn log_error(chain: eyre::Report, f: impl FnOnce() -> eyre::Result) -> Option { f().map_err(|e| e.wrap_err(chain)) .inspect_err(|e| log::error!("{e}")) .ok() } pub fn file_mtime(file: &File) -> eyre::Result> { (move || { let meta = file.metadata().wrap_err("Failed to stat file")?; let sec = meta.mtime(); let nsec = meta .mtime_nsec() .try_into() .wrap_err("Nanoseconds overflowed")?; DateTime::from_timestamp(sec, nsec) .wrap_err("Bad timestamp") .map(Into::into) })() .wrap_err("Failed to get file mtime") }