1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
pub use crate::lib::policies::casts::result::{UniformUnwrap, UniformUnwrapOrDefault}; use crate::uses::Async::{chan::*, fs::File, pre::*, sync::Once, task::*}; use crate::uses::{Sync::sync::Mutex, *}; pub async fn Term() -> Unblock<io::Stdout> { Unblock::new(io::stdout()) } pub async fn File() -> File { File::create("log.txt").await.expect("E| Couldn't create log file") } #[derive(Copy, Clone)] pub enum Level { ERROR = 0, WARNING = 1, INFO = 2, DEBUG = 3, } pub struct Logger; impl Logger { pub fn Setup<T, Fut, Fun>(out: Fun, l: Level) -> Logger where T: AsyncWrite + Unpin + Send, Fut: Future<Output = T> + Send, Fun: FnOnce() -> Fut + Send + 'static, { Self::setup_impl(out, l); Logger {} } pub fn Log(msg: String) { Self::setup_impl(EnsureOrder, Level::INFO); let sender = &unsafe { &LOGGER }.as_ref().expect("E| Logger not initialized").sender; sender.try_send(Message::M(msg)).expect("E| failed to send into log channel"); } pub fn AddPostmortem(f: impl FnOnce() + 'static) { Self::setup_impl(EnsureOrder, Level::INFO); unsafe { &LOGGER } .as_ref() .expect("E| Logger not initialized") .postmortem .lock() .unwrap() .get_mut() .push(Box::new(f)); } pub fn level() -> i32 { unsafe { LEVEL as i32 } } fn setup_impl<T, Fut, Fun>(out: Fun, l: Level) where T: AsyncWrite + Unpin + Send, Fut: Future<Output = T> + Send, Fun: FnOnce() -> Fut + Send + 'static, { static INIT: Once = Once::new(); INIT.call_once(move || { let (sender, reciever): (Sender<Message>, Receiver<Message>) = chan::unbounded(); let handle = task::spawn(async move { let mut out = out().await; while let Ok(msg) = reciever.recv().await { if let Message::M(msg) = msg { out.write_all(msg.as_bytes()).await.expect("E| Failed log write"); } else { out.flush().await.expect("E| Failed log flush"); break; } } }); let postmortem = Mutex::new(Cell::new(vec![])); unsafe { LEVEL = l; LOGGER = Some(LoggerState { handle, sender, postmortem }) } }); } } impl Drop for Logger { fn drop(&mut self) { unsafe { &LOGGER } .as_ref() .expect("E| Logger not initialized") .postmortem .lock() .unwrap() .take() .into_iter() .for_each(|f| f()); let LoggerState { handle, sender, .. } = unsafe { LOGGER.take() }.expect("E| You should only have one Logger"); task::block_on(async { sender.send(Message::Close).await.expect("E| failed to send close into log channel"); handle.await }) } } async fn EnsureOrder() -> Unblock<io::Stdout> { panic!("E| Logger called before it was set up"); } static mut LEVEL: Level = Level::INFO; static mut LOGGER: Option<LoggerState> = None; struct LoggerState { handle: Task<()>, sender: Sender<Message>, postmortem: Mutex<Cell<Vec<Box<dyn FnOnce() + 'static>>>>, } enum Message { M(String), Close, }