#[cfg(not(feature = "std"))]
use core::{any, fmt, ops, time::Duration};
#[cfg(feature = "std")]
use std::{any, fmt, ops, time::Duration};
#[cfg(not(feature = "std"))]
use alloc::{
format,
string::{String, ToString},
};
use derive_more as dm;
pub use error_stack::{self, Report, ResultExt};
pub trait Display: fmt::Display + fmt::Debug + Send + Sync + 'static {}
impl<A> Display for A where A: fmt::Display + fmt::Debug + Send + Sync + 'static {}
pub trait Debug: fmt::Debug + Send + Sync + 'static {}
impl<A> Debug for A where A: fmt::Debug + Send + Sync + 'static {}
#[derive(Debug)]
pub struct Dbg<A: Debug>(pub A);
impl<A: Debug> core::error::Error for Dbg<A> {}
impl Dbg<String> {
pub fn format(attachment: impl fmt::Debug) -> Self {
Self(format!("{attachment:?}"))
}
}
impl<A: Debug> fmt::Display for Dbg<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct KeyValue<K, V>(pub K, pub V);
impl<K: fmt::Display, V: fmt::Display> fmt::Display for KeyValue<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.0, self.1)
}
}
impl<C: core::error::Error + Send + Sync + 'static> core::error::Error for KeyValue<Type, C> {}
impl<C: core::error::Error + Send + Sync + 'static> core::error::Error
for KeyValue<&'static str, C>
{
}
impl<K: Display, V: Debug> KeyValue<K, Dbg<V>> {
pub const fn dbg(key: K, value: V) -> Self {
Self(key, Dbg(value))
}
}
#[macro_export]
macro_rules! kv {
(ty: $value: expr) => {
$crate::KeyValue($crate::attachment::Type::of_val(&$value), $value)
};
(type: $value: expr) => {
$crate::KeyValue($crate::Type::any_val(&$value), $value)
};
($($body:tt)+) => {
{
let (__key, __value)= $crate::__field!($($body)+);
$crate::KeyValue(__key, __value)
}
};
}
#[derive(Debug)]
pub struct Field<Id, S> {
id: Id,
status: S,
}
impl<Id: Display, S: Display> fmt::Display for Field<Id, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.id, self.status)
}
}
impl<Id: Display, S: Display> Field<Id, S> {
pub const fn new(key: Id, status: S) -> Self {
Self { id: key, status }
}
}
#[derive(PartialEq, Eq, derive_more::Deref)]
pub struct Type(&'static str);
impl Type {
#[must_use]
pub fn of<T>() -> Self {
Self(simple_type_name::<T>())
}
#[must_use]
pub fn any<T>() -> Self {
Self(any::type_name::<T>())
}
pub fn of_val<T: ?Sized>(_val: &T) -> Self {
Self(simple_type_name::<T>())
}
pub fn any_val<T: ?Sized>(_val: &T) -> Self {
Self(any::type_name::<T>())
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{}>", self.0)
}
}
impl fmt::Debug for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Type").field(&self.0).finish()
}
}
#[macro_export]
macro_rules! ty {
($type:ty) => {
$crate::Type::of::<$type>()
};
(full: $type:ty) => {
$crate::Type::any::<$type>()
};
}
#[derive(Debug, dm::Display)]
#[display("already present")]
pub struct AlreadyPresent;
#[derive(Debug, dm::Display)]
#[display("missing")]
pub struct Missing;
#[derive(Debug, dm::Display)]
#[display("unsupported")]
pub struct Unsupported;
#[derive(Debug, dm::Display)]
#[display("invalid")]
pub struct Invalid;
#[derive(Debug)]
pub struct Expectation<E, A> {
pub expected: E,
pub actual: A,
}
#[derive(Debug)]
pub struct FromTo<F, T>(pub F, pub T);
#[allow(dead_code)]
enum Symbol {
Vertical,
VerticalRight,
Horizontal,
HorizontalLeft,
HorizontalDown,
ArrowRight,
CurveRight,
Space,
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let utf8 = match self {
Self::Vertical => "\u{2502}", Self::VerticalRight => "\u{251c}", Self::Horizontal => "\u{2500}", Self::HorizontalLeft => "\u{2574}", Self::HorizontalDown => "\u{252c}", Self::ArrowRight => "\u{25b6}", Self::CurveRight => "\u{2570}", Self::Space => " ",
};
write!(f, "{utf8}")
}
}
impl<E: Display, A: Display> fmt::Display for Expectation<E, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let curve_right = Symbol::CurveRight;
let horizontal_left = Symbol::HorizontalLeft;
let expected = KeyValue("expected", &self.expected);
let actual = KeyValue("actual", &self.actual);
write!(f, "{expected}\n{curve_right}{horizontal_left}{actual}")
}
}
impl<F: Display, T: Display> fmt::Display for FromTo<F, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let curve_right = Symbol::CurveRight;
let horizontal_left = Symbol::HorizontalLeft;
let from = KeyValue("from", &self.0);
let to = KeyValue("to", &self.1);
write!(f, "{from}\n{curve_right}{horizontal_left}{to}")
}
}
#[derive(Debug)]
pub struct DisplayDuration(pub Duration);
impl fmt::Display for DisplayDuration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hms_string(self.0))
}
}
impl From<Duration> for DisplayDuration {
fn from(duration: Duration) -> Self {
Self(duration)
}
}
impl ops::Deref for DisplayDuration {
type Target = Duration;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[must_use]
pub fn hms_string(duration: Duration) -> String {
if duration.is_zero() {
return "ZERO".to_string();
}
let s = duration.as_secs();
let ms = duration.subsec_millis();
if s == 0 {
return format!("{ms}ms");
}
let (h, s) = (s / 3600, s % 3600);
let (m, s) = (s / 60, s % 60);
let mut hms = String::new();
if h != 0 {
hms += &format!("{h:02}H");
}
if m != 0 {
hms += &format!("{m:02}m");
}
hms += &format!("{s:02}s");
hms
}
#[must_use]
pub fn simple_type_name<T: ?Sized>() -> &'static str {
let full_type = any::type_name::<T>();
if full_type.contains(['<', '[']) {
return full_type;
}
full_type.rsplit_once("::").map_or(full_type, |t| t.1)
}
#[derive(Debug, dm::Display)]
#[display("idx [{0}: {}]", simple_type_name::<I>())]
pub struct Index<I: fmt::Display>(pub I);
#[cfg(test)]
mod test {
use super::*;
use crate::MyStruct;
#[test]
fn kv_macro() {
let foo = "Foo";
assert_eq!(kv!(foo), KeyValue("foo", "Foo"));
assert_eq!(kv!(ty: foo), KeyValue(Type::of_val(&foo), "Foo"));
let foo = 13;
assert_eq!(kv!(ty: foo), KeyValue(Type::of_val(&foo), 13));
assert_eq!(kv!(ty: 13), KeyValue(Type::of_val(&13), 13));
}
#[test]
fn kv_macro_var() {
let foo = "Foo";
let key_value = kv!(foo.to_owned());
assert_eq!(key_value, KeyValue("foo", String::from(foo)));
}
#[test]
fn kv_macro_struct() {
let my_struct = MyStruct {
my_field: None,
_string: String::from("Value"),
};
let key_value = kv!(my_struct.%my_field());
assert_eq!(key_value, KeyValue("my_field", None));
let key_value = kv!(my_struct.%_string);
assert_eq!(key_value, KeyValue("_string", String::from("Value")));
let key_value = kv!(my_struct.my_field);
assert_eq!(key_value, KeyValue("my_struct.my_field", None));
}
}