#[macro_export]
macro_rules! impl_display_for_single_struct {
($Name: ident, $name: tt $(. $attr: tt)*) => {
impl std::fmt::Display for $Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.$name $(. $attr)*)
}
}
};
($Name: ident) => {
impl std::fmt::Display for $Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
}
}
#[macro_export]
macro_rules! impl_display_from_debug {
($Name: ident) => {
impl std::fmt::Display for $Name {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self:#?}")
}
}
};
}
#[macro_export]
macro_rules! impl_display_for_enum {
($Enum: ident; $($Variant: ident $(,)?)*) => {
impl std::fmt::Display for $Enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$($Enum::$Variant(v) => write!(f, "{}", v),)*
}
}
}
}
}
#[macro_export]
macro_rules! impl_u8_enum {
($Enum: ident; $($Variant: ident $(,)?)*) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum $Enum {
$($Variant,)*
}
$crate::impl_display_from_debug!($Enum);
impl From<u8> for $Enum {
fn from(byte: u8) -> Self {
match byte {
$(v if v == $Enum::$Variant as u8 => $Enum::$Variant,)*
_ => todo!("unknown: {byte}"),
}
}
}
impl From<$Enum> for u8 {
fn from(op: $Enum) -> u8 {
op as u8
}
}
};
($Enum: ident; $($Variant: ident = $val: expr $(,)?)*) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum $Enum {
$($Variant = $val,)*
}
$crate::impl_display_from_debug!($Enum);
impl From<u8> for $Enum {
fn from(byte: u8) -> Self {
match byte {
$($val => $Enum::$Variant,)*
_ => todo!("unknown opcode: {byte}"),
}
}
}
impl From<$Enum> for u8 {
fn from(op: $Enum) -> u8 {
op as u8
}
}
impl $Enum {
pub const fn take_arg(&self) -> bool {
90 <= (*self as u8) && (*self as u8) < 220
}
}
};
($Enum: ident; $size: tt; $($Variant: ident = $val: expr $(,)?)*) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr($size)]
pub enum $Enum {
$($Variant = $val,)*
}
$crate::impl_display_from_debug!($Enum);
impl From<$size> for $Enum {
fn from(byte: $size) -> Self {
match byte {
$($val => $Enum::$Variant,)*
_ => todo!("unknown opcode: {byte}"),
}
}
}
impl From<$Enum> for $size {
fn from(op: $Enum) -> $size {
op as $size
}
}
};
}
#[macro_export]
macro_rules! impl_display_for_enum_with_variant {
($Enum: ident; $($Variant: ident $(,)?)*) => {
impl std::fmt::Display for $Enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$($Enum::$Variant(v) => write!(f, "{} {}", stringify!($Variant), v),)*
}
}
}
}
}
#[macro_export]
macro_rules! switch_lang {
(
$should_english: literal => $msg: expr,
) => {{ $msg }};
(
$lang_name: literal => $msg: expr,
$($rest_lang_name: literal => $rest_msg: expr,)+
) => {{
if cfg!(feature = $lang_name) {
$msg
} else {
switch_lang!($($rest_lang_name => $rest_msg,)+)
}
}};
}
#[macro_export]
macro_rules! enum_unwrap {
($ex: expr, $Enum: path $(,)*) => {{
if let $Enum(res) = $ex { res } else { $crate::switch_unreachable!() }
}};
($ex: expr, $Enum: path :( $Cons: path :(_) ) $(,)*) => {{
if let $Enum($Cons(res)) = $ex { res } else { $crate::switch_unreachable!() }
}};
($ex: expr, $Enum: path :( $Cons: path :( $Cons2: path :(_) ) ) $(,)*) => {{
if let $Enum($Cons($Cons2(res))) = $ex { res } else { $crate::switch_unreachable!() }
}};
($ex: expr, $Enum: path {$($fields: ident $(,)*)*}) => {{
if let $Enum{$($fields,)*} = $ex { ($($fields,)*) } else { $crate::switch_unreachable!() }
}};
}
#[macro_export]
macro_rules! option_enum_unwrap {
($ex: expr, $Enum: path $(,)*) => {{
if let $Enum(res) = $ex { Some(res) } else { None }
}};
($ex: expr, $Enum: path :( $Cons: path :(_) ) $(,)*) => {{
if let $Enum($Cons(res)) = $ex { Some(res) } else { None }
}};
($ex: expr, $Enum: path :( $Cons: path :( $Cons2: path :(_) ) ) $(,)*) => {{
if let $Enum($Cons($Cons2(res))) = $ex { Some(res) } else { None }
}};
($ex: expr, $Enum: path {$($fields: ident $(,)*)*}) => {{
if let $Enum{$($fields,)*} = $ex { Some(($($fields,)*)) } else { None }
}};
}
#[macro_export]
macro_rules! fmt_option {
($ex: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}", x)
} else {
"".to_string()
}
};
($ex: expr $(,)*, else $els: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}", x)
} else {
$els.to_string()
}
};
(pre $prefix: expr, $ex: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}{}", $prefix, x)
} else {
"".to_string()
}
};
($ex: expr, post $postfix: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}{}", x, $postfix)
} else {
"".to_string()
}
};
($prefix: expr, $ex: expr, $postfix: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}{}{}", $prefix, x, $postfix)
} else {
"".to_string()
}
};
}
#[macro_export]
macro_rules! fmt_option_map {
($ex: expr, $f: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}", $f(x))
} else {
"".to_string()
}
};
($ex: expr $(,)*, else $els: expr, $f: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}", $f(x))
} else {
$els.to_string()
}
};
(pre $prefix: expr, $ex: expr, $f: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}{}", $prefix, $f(x))
} else {
"".to_string()
}
};
($ex: expr, post $postfix: expr, $f: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}{}", $f(x), $postfix)
} else {
"".to_string()
}
};
($prefix: expr, $ex: expr, $postfix: expr, $f: expr $(,)*) => {
if let Some(x) = &$ex {
format!("{}{}{}", $prefix, $f(x), $postfix)
} else {
"".to_string()
}
};
}
#[macro_export]
macro_rules! switch_unreachable {
() => {{
if cfg!(debug_assertions) {
unreachable!()
} else {
unsafe { std::hint::unreachable_unchecked() }
}
}};
}
#[macro_export]
macro_rules! assume_unreachable {
() => {{
unsafe { std::hint::unreachable_unchecked() }
}};
}
#[macro_export]
macro_rules! fn_name_full {
() => {{
const fn dummy() {}
fn type_name_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
let name = type_name_of(dummy); &name[..name.len() - 7] }};
}
#[macro_export]
macro_rules! fn_name {
() => {{
const fn dummy() {}
fn type_name_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
let mut names = type_name_of(dummy).rsplit("::");
let mut name = names.nth(1).unwrap_or("?");
while name == "{{closure}}" {
name = names.next().unwrap_or("?");
}
&name[..]
}};
}
#[macro_export]
macro_rules! caused_by {
() => {{
let fn_name = $crate::fn_name!();
&format!("{fn_name} at line {}", line!())
}};
}
#[macro_export]
macro_rules! addr {
($obj: expr) => {{
let s = format!("{:p}", &$obj);
let s = s.trim_start_matches("0x");
u64::from_str_radix(&s, 16).unwrap()
}};
}
#[macro_export]
macro_rules! addr_eq {
($l: expr, $r: expr $(,)*) => {{
&$l as *const _ == &$r as *const _
}};
}
#[macro_export]
macro_rules! ref_addr_eq {
($l: expr, $r: expr $(,)*) => {{
$l as *const _ == $r as *const _
}};
}
#[macro_export]
macro_rules! power_assert {
($l: expr, $op: tt, $r: expr $(,)*) => {
if !($l $op $r) {
let s_l = stringify!($l);
let s_r = stringify!($r);
let s_op = stringify!($op);
panic!(
"assertion failed: `{s_l} {s_op} {s_r}` (`{s_l}` = {:#?}, `{s_r}` = {:#?})",
$l, $r,
)
}
};
($cond: expr) => {
if !$cond {
let s_cond = stringify!($cond);
panic!("assertion failed: `{s_cond}` == {:#?}", $cond)
}
};
}
#[macro_export]
macro_rules! debug_power_assert {
($l: expr, $op: tt, $r: expr) => {
if cfg!(debug_assertions) {
erg_common::power_assert!($l, $op, $r)
}
};
($ex: expr) => {
if cfg!(debug_assertions) {
erg_common::power_assert!($ex)
}
};
}
#[macro_export]
macro_rules! debug_enum_assert {
($ex: expr, $Enum: ident :: $Variant: ident $(,)*) => {
debug_assert!(common::enum_is!($ex, $Enum::$Variant));
};
($ex: expr, $Enum: ident :: $Variant: ident, $Enum2: ident :: $Variant2: ident $(,)*) => {{
debug_assert!(common::enum_is!($ex, $Enum::$Variant, $Enum2::$Variant2));
}};
($ex: expr, $TupleCons: ident, $Enum: ident :: $Variant: ident $(,)*) => {{
debug_assert!(common::enum_is!($ex, $TupleCons, $Enum::$Variant));
}};
}
#[macro_export]
macro_rules! debug_info {
($output:ident) => {{
#[allow(unused_imports)]
use $crate::style::{colors::DEBUG, RESET};
write!(
$output,
"[{}DEBUG{}] {}:{:04}: ",
DEBUG,
RESET,
file!(),
line!()
)
.unwrap();
}};
() => {{
#[allow(unused_imports)]
use $crate::style::{colors::DEBUG, RESET};
print!("[{}DEBUG{}] {}:{:04}: ", DEBUG, RESET, file!(), line!());
}};
}
#[macro_export]
macro_rules! log {
(info $($arg: tt)*) => {{
$crate::log!(c DEBUG_MAIN, $($arg)*);
}};
(err $($arg: tt)*) => {{
$crate::log!(c DEBUG_ERROR, $($arg)*);
}};
(info_f $output:ident, $($arg: tt)*) => {{
$crate::log!(f+c $output, DEBUG_MAIN, $($arg)*);
}};
(err_f $output:ident, $($arg: tt)*) => {{
$crate::log!(f+c $output, DEBUG_ERROR, $($arg)*);
}};
(f $output: ident, $($arg: tt)*) => {{
if cfg!(feature = "debug") {
#[allow(unused_imports)]
use $crate::color::{RESET, colors::DEBUG_MAIN, colors::DEBUG_ERROR};
$crate::debug_info!($output);
write!($output, $($arg)*).unwrap();
write!($output, "{}", RESET).unwrap(); $output.flush().unwrap();
}
}};
(c $color:ident, $($arg: tt)*) => {{
if cfg!(feature = "debug") {
#[allow(unused_imports)]
use $crate::style::{RESET, colors::DEBUG_MAIN, colors::DEBUG_ERROR};
$crate::debug_info!();
print!("{}", $color);
println!($($arg)*);
print!("{}", RESET); }
}};
(f+c $output:ident, $color:ident, $($arg: tt)*) => {{
if cfg!(feature = "debug") {
#[allow(unused_imports)]
use $crate::style::{RESET, colors::DEBUG_MAIN};
$crate::debug_info!($output);
write!($output, "{}{}{}", $color, $($arg)*, RESET).unwrap();
write!($output, $($arg)*).unwrap();
write!($output, "{}", RESET).unwrap(); $output.flush().unwrap();
}
}};
($($arg: tt)*) => {{
if cfg!(feature = "debug") {
use $crate::style::*;
$crate::debug_info!();
println!($($arg)*);
print!("{}", RESET); }
}};
}
#[macro_export]
macro_rules! log_with_time {
(f $output: ident, $($arg: tt)*) => {
if cfg!(feature = "debug") {
write!($output, "{}: ", $crate::datetime::now()).unwrap();
write!($output, $($arg)*).unwrap();
$output.flush().unwrap();
}
};
($($arg: tt)*) => {
if cfg!(feature = "debug") {
print!("{}: ", $crate::datetime::now());
println!($($arg)*);
}
};
}
#[macro_export]
macro_rules! fmt_dbg {
($arg: expr $(,)*) => {
if cfg!(feature = "debug") { print!("{}:{:04}:\n", file!(), line!());
print!("{} = ", stringify!($arg));
println!("{}", $arg);
}
};
($head: expr, $($arg: expr $(,)*)+) => {
if cfg!(feature = "debug") { print!("{}:{:04}:\n", file!(), line!());
print!("{} = ", stringify!($head));
println!("{}", $head);
$crate::fmt_dbg!(rec $($arg,)+);
}
};
(rec $arg: expr,) => {
if cfg!(feature = "debug") {
print!("{} = ", stringify!($arg));
println!("{}", $arg);
}
};
(rec $head: expr, $($arg: expr,)+) => {
if cfg!(feature = "debug") {
print!("{} = ", stringify!($head));
println!("{}", $head);
$crate::fmt_dbg!(rec $($arg,)+);
}
};
}