pub use log::{Level as LogLevel, Record as LogRecord, debug, error, info, trace, warn};
use std::sync::atomic::{AtomicBool, Ordering};
use cu::Atomic;
#[macro_export]
macro_rules! fmtand {
($mac:ident !( $($fmt_args:tt)* )) => {{
let s = format!($($fmt_args)*);
$crate::$mac!("{s}");
s
}}
}
pub(crate) static PRINT_LEVEL: Atomic<u8, Print> = Atomic::new_u8(Print::Normal as u8);
pub(crate) static USE_COLOR: AtomicBool = AtomicBool::new(true);
pub fn color_enabled() -> bool {
USE_COLOR.load(Ordering::Acquire)
}
static ENABLE_TRACE_HINT: AtomicBool = AtomicBool::new(true);
static ENABLE_PRINT_TIME: AtomicBool = AtomicBool::new(true);
#[inline(always)]
#[cfg(feature = "print")]
pub fn disable_trace_hint() {
ENABLE_TRACE_HINT.store(false, Ordering::Release);
}
#[inline(always)]
pub fn is_trace_hint_enabled() -> bool {
ENABLE_TRACE_HINT.load(Ordering::Acquire)
}
#[inline(always)]
#[cfg(feature = "print")]
pub fn disable_print_time() {
ENABLE_PRINT_TIME.store(false, Ordering::Release);
}
#[inline(always)]
pub fn is_print_time_enabled() -> bool {
ENABLE_PRINT_TIME.load(Ordering::Acquire)
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
pub enum Color {
Always,
Never,
#[default]
Auto,
}
impl std::fmt::Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Always => write!(f, "always"),
Self::Never => write!(f, "never"),
Self::Auto => write!(f, "auto"),
}
}
}
impl Color {
pub fn is_colored_for_stdout(self) -> bool {
use std::io::IsTerminal;
match self {
Self::Always => true,
Self::Never => false,
Self::Auto => std::io::stdout().is_terminal(),
}
}
pub fn from_os_args() -> Self {
let mut found_color = false;
for x in std::env::args() {
if found_color {
if x == "always" {
return Self::Always;
}
if x == "never" {
return Self::Never;
}
if x == "auto" {
return Self::Auto;
}
found_color = false;
continue;
}
if x == "--color" {
found_color = true;
continue;
}
if x == "--color=always" {
return Self::Always;
}
if x == "--color=never" {
return Self::Never;
}
if x == "--color=auto" {
return Self::Auto;
}
}
Self::Auto
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Print {
QuietQuiet,
Quiet,
Normal,
Verbose,
VerboseVerbose,
}
impl From<i8> for Print {
fn from(value: i8) -> Self {
match value {
..=-2 => Self::QuietQuiet,
-1 => Self::Quiet,
0 => Self::Normal,
1 => Self::Verbose,
2.. => Self::VerboseVerbose,
}
}
}
impl From<u8> for Print {
fn from(value: u8) -> Self {
match value {
0 => Self::QuietQuiet,
1 => Self::Quiet,
3 => Self::Verbose,
4 => Self::VerboseVerbose,
_ => Self::Normal,
}
}
}
impl From<Print> for u8 {
fn from(value: Print) -> Self {
value as Self
}
}
impl From<Print> for log::LevelFilter {
fn from(value: Print) -> Self {
match value {
Print::QuietQuiet => log::LevelFilter::Off,
Print::Quiet => log::LevelFilter::Error,
Print::Normal => log::LevelFilter::Info,
Print::Verbose => log::LevelFilter::Debug,
Print::VerboseVerbose => log::LevelFilter::Trace,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Prompt {
Interactive,
YesOrInteractive,
YesOrBlock,
Block,
}
impl From<u8> for Prompt {
fn from(value: u8) -> Self {
match value {
1 => Self::YesOrInteractive,
2 => Self::YesOrBlock,
3 => Self::Block,
_ => Self::Interactive,
}
}
}
impl From<Prompt> for u8 {
fn from(value: Prompt) -> Self {
value as Self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Lv {
Error,
Hint,
Print,
Warn,
Info,
Debug,
Trace,
Off,
}
impl Lv {
#[inline(always)]
pub fn enabled(self) -> bool {
self.can_print(PRINT_LEVEL.get())
}
pub fn can_print(self, level: Print) -> bool {
match self {
Lv::Off => false,
Lv::Error | Lv::Hint | Lv::Print => level != Print::QuietQuiet,
Lv::Warn | Lv::Info => level > Print::Quiet,
Lv::Debug => level > Print::Normal,
Lv::Trace => level == Print::VerboseVerbose,
}
}
}
impl From<log::Level> for Lv {
fn from(value: log::Level) -> Self {
match value {
log::Level::Error => Self::Error,
log::Level::Warn => Self::Warn,
log::Level::Info => Self::Info,
log::Level::Debug => Self::Debug,
log::Level::Trace => Self::Trace,
}
}
}
impl From<Lv> for log::Level {
fn from(value: Lv) -> Self {
match value {
Lv::Error => log::Level::Error,
Lv::Hint => log::Level::Warn,
Lv::Print => log::Level::Info,
Lv::Warn => log::Level::Warn,
Lv::Info => log::Level::Info,
Lv::Debug => log::Level::Debug,
Lv::Trace => log::Level::Trace,
Lv::Off => log::Level::Error,
}
}
}
impl From<u8> for Lv {
fn from(value: u8) -> Self {
match value {
0 => Lv::Error,
1 => Lv::Hint,
2 => Lv::Print,
3 => Lv::Warn,
4 => Lv::Info,
5 => Lv::Debug,
6 => Lv::Trace,
_ => Lv::Off,
}
}
}
impl From<Lv> for u8 {
fn from(value: Lv) -> Self {
value as u8
}
}
impl std::fmt::Display for Lv {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Lv::Error => "error".fmt(f),
Lv::Hint => "hint".fmt(f),
Lv::Print => "print".fmt(f),
Lv::Warn => "warn".fmt(f),
Lv::Info => "info".fmt(f),
Lv::Debug => "debug".fmt(f),
Lv::Trace => "trace".fmt(f),
Lv::Off => "off".fmt(f),
}
}
}
pub const E: Lv = Lv::Error;
pub const H: Lv = Lv::Hint;
pub const P: Lv = Lv::Print;
pub const W: Lv = Lv::Warn;
pub const I: Lv = Lv::Info;
pub const D: Lv = Lv::Debug;
pub const T: Lv = Lv::Trace;