use std::io::Write;
use std::sync::OnceLock;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum Level {
Info = 0,
Warn = 1,
Error = 2,
}
impl Level {
#[inline]
const fn tag(self) -> &'static str {
match self {
Level::Info => "INFO",
Level::Warn => "WARN",
Level::Error => "ERROR",
}
}
pub const fn from_u32(n: u32) -> Level {
match n {
0 => Level::Info,
1 => Level::Warn,
_ => Level::Error,
}
}
}
pub type Sink = fn(Level, &str);
static SINK: OnceLock<Sink> = OnceLock::new();
pub fn set_sink(sink: Sink) {
let _ = SINK.set(sink);
}
#[doc(hidden)]
#[inline]
pub fn log(level: Level, args: std::fmt::Arguments<'_>) {
if let Some(sink) = SINK.get() {
sink(level, &args.to_string());
return;
}
let line = format_args!("[yog] [{}] {}", level.tag(), args);
if matches!(level, Level::Error) {
let _ = writeln!(std::io::stderr().lock(), "{line}");
} else {
let _ = writeln!(std::io::stdout().lock(), "{line}");
}
}
#[macro_export]
macro_rules! info {
($($arg:tt)*) => {
$crate::log($crate::Level::Info, ::core::format_args!($($arg)*))
};
}
#[macro_export]
macro_rules! warn {
($($arg:tt)*) => {
$crate::log($crate::Level::Warn, ::core::format_args!($($arg)*))
};
}
#[macro_export]
macro_rules! error {
($($arg:tt)*) => {
$crate::log($crate::Level::Error, ::core::format_args!($($arg)*))
};
}