#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![warn(clippy::print_stdout, clippy::print_stderr)]
#![cfg_attr(target_pointer_width = "64", warn(clippy::trivially_copy_pass_by_ref))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![no_std]
use core::any::Any;
use core::fmt::Debug;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
pub trait AnyDebug: Any + Debug {
#[cfg(feature = "type_name")]
fn type_name(&self) -> &'static str;
}
impl<T: Any + Debug> AnyDebug for T {
#[cfg(feature = "type_name")]
fn type_name(&self) -> &'static str {
core::any::type_name::<Self>()
}
}
impl dyn AnyDebug {
pub fn downcast_ref<T: AnyDebug>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref::<T>()
}
pub fn downcast_mut<T: AnyDebug>(&mut self) -> Option<&mut T> {
(self as &mut dyn Any).downcast_mut::<T>()
}
#[cfg(feature = "alloc")]
pub fn downcast<T: AnyDebug>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if self.is::<T>() {
Ok((self as Box<dyn Any>).downcast::<T>().unwrap())
} else {
Err(self)
}
}
pub fn is<T: AnyDebug>(&self) -> bool {
let this: &dyn Any = self;
this.is::<T>()
}
}
impl dyn AnyDebug + Send {
pub fn downcast_ref<T: AnyDebug>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref::<T>()
}
pub fn downcast_mut<T: AnyDebug>(&mut self) -> Option<&mut T> {
(self as &mut dyn Any).downcast_mut::<T>()
}
#[cfg(feature = "alloc")]
pub fn downcast<T: AnyDebug>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if self.is::<T>() {
Ok((self as Box<dyn Any>).downcast::<T>().unwrap())
} else {
Err(self)
}
}
pub fn is<T: AnyDebug>(&self) -> bool {
let this: &dyn Any = self;
this.is::<T>()
}
}
impl dyn AnyDebug + Send + Sync {
pub fn downcast_ref<T: AnyDebug>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref::<T>()
}
pub fn downcast_mut<T: AnyDebug>(&mut self) -> Option<&mut T> {
(self as &mut dyn Any).downcast_mut::<T>()
}
#[cfg(feature = "alloc")]
pub fn downcast<T: AnyDebug>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if self.is::<T>() {
Ok((self as Box<dyn Any>).downcast::<T>().unwrap())
} else {
Err(self)
}
}
pub fn is<T: AnyDebug>(&self) -> bool {
let this: &dyn Any = self;
this.is::<T>()
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use crate::AnyDebug;
use alloc::{boxed::Box, format};
#[derive(Debug)]
struct SomeMessage(u32);
#[test]
#[cfg(feature = "type_name")]
fn any_debug_correct_typename() {
let val = SomeMessage(4);
let val: &dyn AnyDebug = &val;
assert!(val.type_name().contains("SomeMessage"));
}
#[test]
fn any_debug_shared_correct_debug() {
let val = SomeMessage(5);
let val: &dyn AnyDebug = &val;
let format_result = format!("{val:?}");
assert!(format_result.contains("SomeMessage"));
assert!(format_result.contains("5"));
}
#[test]
fn any_debug_excl_correct_debug() {
let mut val = SomeMessage(6);
let val: &mut dyn AnyDebug = &mut val;
let format_result = format!("{val:?}");
assert!(format_result.contains("SomeMessage"));
assert!(format_result.contains("6"));
}
#[test]
fn any_debug_box_correct_debug() {
let val = SomeMessage(7);
let val: Box<dyn AnyDebug> = Box::new(val);
let format_result = format!("{val:?}");
assert!(format_result.contains("SomeMessage"));
assert!(format_result.contains("7"));
}
#[test]
fn any_debug_normal_is() {
let val = SomeMessage(10);
let val: &dyn AnyDebug = &val;
assert!(val.is::<SomeMessage>());
assert!(!val.is::<u32>());
}
#[test]
fn any_debug_normal_downcast_ref() {
let val = SomeMessage(11);
let val: &dyn AnyDebug = &val;
assert_eq!(val.downcast_ref::<SomeMessage>().unwrap().0, 11);
}
#[test]
fn any_debug_normal_downcast_mut() {
let mut val = SomeMessage(12);
let val_mut: &mut dyn AnyDebug = &mut val;
val_mut.downcast_mut::<SomeMessage>().unwrap().0 = 13;
assert!(val_mut.downcast_mut::<u32>().is_none());
assert_eq!(val.0, 13);
}
#[test]
#[cfg(feature = "alloc")]
fn any_debug_normal_downcast() {
let val = SomeMessage(14);
let val: Box<dyn AnyDebug> = Box::new(val);
let val = val.downcast::<u32>().unwrap_err();
let val = val.downcast::<SomeMessage>().unwrap();
assert_eq!(val.0, 14);
}
#[test]
fn any_debug_send_is() {
let val = SomeMessage(20);
let val: &(dyn AnyDebug + Send) = &val;
assert!(val.is::<SomeMessage>());
assert!(!val.is::<u32>());
}
#[test]
fn any_debug_send_downcast_ref() {
let val = SomeMessage(21);
let val: &(dyn AnyDebug + Send) = &val;
assert_eq!(val.downcast_ref::<SomeMessage>().unwrap().0, 21);
}
#[test]
fn any_debug_send_downcast_mut() {
let mut val = SomeMessage(22);
let val_mut: &mut (dyn AnyDebug + Send) = &mut val;
val_mut.downcast_mut::<SomeMessage>().unwrap().0 = 23;
assert!(val_mut.downcast_mut::<u32>().is_none());
assert_eq!(val.0, 23);
}
#[test]
#[cfg(feature = "alloc")]
fn any_debug_send_downcast() {
let val = SomeMessage(24);
let val: Box<(dyn AnyDebug + Send)> = Box::new(val);
let val = val.downcast::<u32>().unwrap_err();
let val = val.downcast::<SomeMessage>().unwrap();
assert_eq!(val.0, 24);
}
#[test]
fn any_debug_send_sync_is() {
let val = SomeMessage(30);
let val: &(dyn AnyDebug + Send + Sync) = &val;
assert!(val.is::<SomeMessage>());
assert!(!val.is::<u32>());
}
#[test]
fn any_debug_send_sync_downcast_ref() {
let val = SomeMessage(31);
let val: &(dyn AnyDebug + Send + Sync) = &val;
assert_eq!(val.downcast_ref::<SomeMessage>().unwrap().0, 31);
}
#[test]
fn any_debug_send_sync_downcast_mut() {
let mut val = SomeMessage(32);
let val_mut: &mut (dyn AnyDebug + Send + Sync) = &mut val;
val_mut.downcast_mut::<SomeMessage>().unwrap().0 = 33;
assert!(val_mut.downcast_mut::<u32>().is_none());
assert_eq!(val.0, 33);
}
#[test]
#[cfg(feature = "alloc")]
fn any_debug_send_sync_downcast() {
let val = SomeMessage(34);
let val: Box<(dyn AnyDebug + Send + Sync)> = Box::new(val);
let val = val.downcast::<u32>().unwrap_err();
let val = val.downcast::<SomeMessage>().unwrap();
assert_eq!(val.0, 34);
}
}