pub mod err;
use err::*;
use lazy_static::lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref LOG_LK: Mutex<u64> = Mutex::new(0);
}
#[macro_export]
macro_rules! map {
() => {{
std::collections::HashMap::new()
}};
(B) => {{
std::collections::BTreeMap::new()
}};
($(||)+) => {{
std::collections::HashMap::new
}};
(B $(||)+) => {{
std::collections::BTreeMap::new
}};
($($k: expr => $v: expr),+ $(,)*) => {{
let mut m = std::collections::HashMap::with_capacity([$(&$k),*].len());
$(m.insert($k, $v);)*
m
}};
(B $($k: expr => $v: expr),+ $(,)*) => {{
let mut m = map! {B};
$(m.insert($k, $v);)*
m
}};
}
#[macro_export]
macro_rules! vct {
() => {
Vec::new()
};
($(||)+) => {
Vec::new
};
($($v: expr),+ $(,)*) => {{
vec![$($v),*]
}};
($elem:expr; $n:expr) => {{
vec![$elem; $n]
}};
}
#[macro_export]
macro_rules! alt {
($condition: expr, $ops: block, $ops2: block) => {{
if $condition $ops else $ops2
}};
($condition: expr, $ops: block) => {{
if $condition $ops
}};
($condition: expr, $ops: expr, $ops2: expr) => {{
if $condition { $ops } else { $ops2 }
}};
($condition: expr, $ops: expr) => {{
if $condition { $ops }
}};
}
#[macro_export]
macro_rules! info {
($ops: expr) => {{
$ops.c($crate::d!()).map_err($crate::p)
}};
($ops: expr, $msg: expr) => {{
$ops.c($crate::d!($msg)).map_err($crate::p)
}};
}
#[macro_export]
macro_rules! omit {
($ops: expr) => {{
let _ = $ops;
}};
}
#[macro_export]
macro_rules! info_omit {
($ops: expr) => {{
$crate::omit!($crate::info!($ops));
}};
($ops: expr, $msg: expr) => {{
$crate::omit!($crate::info!($ops, $msg));
}};
}
#[macro_export]
macro_rules! d {
($x: expr) => {{
let mut res = "\x1b[31m".to_string();
res.push_str(&$x.to_string());
res.push_str("\x1b[00m");
res.push_str(&d!());
res
}};
() => {{
format!("\n├── \x1b[01mfile:\x1b[00m {}\n└── \x1b[01mline:\x1b[00m {}",
file!(), line!())
}};
}
#[macro_export]
macro_rules! pd {
($x: expr) => {{
eprintln!("\n{}", $crate::d!($x));
}};
}
#[macro_export]
macro_rules! ts {
() => {{
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
}};
}
#[macro_export]
macro_rules! datetime_local {
($ts: expr) => {{
crate::gen_datetime_local($ts as i64)
}};
() => {{
datetime_local!($crate::ts!())
}};
}
pub fn gen_datetime_local(ts: i64) -> String {
time::OffsetDateTime::from_unix_timestamp(ts)
.to_offset(time::offset!(+8))
.format("%F %T")
}
#[inline(always)]
#[cfg(target_os = "linux")]
fn get_pidns(pid: u32) -> Result<String> {
std::fs::read_link(format!("/proc/{}/ns/pid", pid))
.c(crate::d!())
.map(|p| {
p.to_string_lossy()
.trim_start_matches("pid:[")
.trim_end_matches(']')
.to_owned()
})
}
#[inline(always)]
#[cfg(not(target_os = "linux"))]
fn get_pidns(_pid: u32) -> Result<String> {
Ok("NULL".to_owned())
}
pub fn genlog(mut e: Box<dyn MyError>) -> String {
let pid = std::process::id();
let ns = get_pidns(pid).unwrap();
let mut logn = LOG_LK.lock().unwrap();
let mut res = format!(
"\n\x1b[31;01m{n:>0width$} [pidns: {ns}][pid: {pid}] {time}\x1b[00m",
width = 6,
n = logn,
ns = ns,
pid = pid,
time = datetime_local!(),
);
res.push_str(&e.display_chain());
*logn += 1;
res
}
#[inline(always)]
pub fn p(e: Box<dyn MyError>) {
eprintln!("{}", genlog(e));
}
#[macro_export]
macro_rules! die {
($e:expr) => {{
$crate::pd!($e);
$crate::die!();
}};
() => {
panic!();
};
}
#[inline(always)]
pub fn pdie(e: Box<dyn MyError>) -> ! {
p(e);
crate::die!();
}
#[macro_export]
macro_rules! pnk {
($ops: expr) => {{
$ops.c($crate::d!()).unwrap_or_else(|e| $crate::pdie(e))
}};
($ops: expr, $msg: expr) => {{
$ops.c($crate::d!($msg)).unwrap_or_else(|e| $crate::pdie(e))
}};
}
#[macro_export]
macro_rules! sleep_ms {
($n: expr) => {{
std::thread::sleep(std::time::Duration::from_millis($n));
}};
}
#[macro_export]
macro_rules! eg {
($msg: expr) => {{
Box::new($crate::err::SimpleError::new($crate::d!($msg), None))
as Box<dyn MyError>
}};
(@$msg: expr) => {
$crate::eg!(format!("{:#?}", $msg))
};
() => {
$crate::eg!("...")
};
}
#[macro_export]
macro_rules! so_eq {
($lv: expr, $rv: expr) => {{
let l = $lv;
let r = $rv;
if l != r {
return Err($crate::eg!(format!(
"Assert failed: {:?} == {:?}",
l, r
)));
}
}};
}
#[macro_export]
macro_rules! so_ne {
($lv: expr, $rv: expr) => {{
let l = $lv;
let r = $rv;
if l == r {
return Err($crate::eg!(format!(
"Assert failed: {:?} != {:?}",
l, r
)));
}
}};
}
#[macro_export]
macro_rules! so_le {
($lv: expr, $rv: expr) => {{
let l = $lv;
let r = $rv;
if l > r {
return Err($crate::eg!(format!(
"Assert failed: {:?} <= {:?}",
l, r
)));
}
}};
}
#[macro_export]
macro_rules! ok {
() => {{
let ok: std::io::Result<_> = Ok(());
ok.c(d!())
}};
}
#[cfg(test)]
mod tests {
#![allow(non_snake_case)]
use super::*;
use std::process;
#[test]
fn T_get_pidns() {
let ns_name = pnk!(get_pidns(process::id()));
assert!(1 < ns_name.len());
}
#[test]
#[should_panic]
fn T_display_style() {
let l1 = || -> Result<()> { Err(eg!("Some error occur!")) };
let l2 = || -> Result<()> { l1().c(d!()) };
let l3 = || -> Result<()> { l2().c(d!()) };
let l4 = || -> Result<()> { l3().c(d!()) };
pnk!(l4());
}
#[test]
fn T_map() {
let s1 = map! {1 => 2, 2 => 4};
let s2 = map! {B 1 => 2, 2 => 4};
assert_eq!(s1.len(), s2.len());
for (idx, (k, v)) in s2.into_iter().enumerate() {
assert_eq!(1 + idx, k);
assert_eq!(2 * k, v);
}
}
}