similar_asserts/
print.rs

1use std::borrow::Cow;
2use std::fmt::Debug;
3
4pub trait StringRepr: AsRef<str> {}
5
6impl StringRepr for str {}
7impl StringRepr for String {}
8impl<'a> StringRepr for Cow<'a, str> {}
9impl<T: StringRepr + ?Sized> StringRepr for &T {}
10
11/// Defines how the object is printed.
12pub enum PrintMode {
13    /// The regular print mode.  If an object does not return
14    /// something for this print mode it's not formattable.
15    Default,
16    /// Some objects have an extra expanded print mode with pretty newlines.
17    Expanded,
18}
19
20pub trait PrintObject<'a> {
21    fn print_object(self, mode: PrintMode) -> Option<Cow<'a, str>>;
22}
23
24impl<'a, 'b: 'a, T: StringRepr + ?Sized + 'a> PrintObject<'a> for (&'b T,) {
25    fn print_object(self, mode: PrintMode) -> Option<Cow<'a, str>> {
26        match mode {
27            PrintMode::Default => Some(Cow::Borrowed(self.0.as_ref())),
28            PrintMode::Expanded => None,
29        }
30    }
31}
32
33impl<'a, 'b: 'a, T: Debug + 'a> PrintObject<'a> for &'b (T,) {
34    fn print_object(self, mode: PrintMode) -> Option<Cow<'a, str>> {
35        Some(
36            match mode {
37                PrintMode::Default => format!("{:?}", self.0),
38                PrintMode::Expanded => format!("{:#?}", self.0),
39            }
40            .into(),
41        )
42    }
43}
44
45impl<'a, 'b: 'a, T: 'a> PrintObject<'a> for &'b mut (T,) {
46    fn print_object(self, _mode: PrintMode) -> Option<Cow<'a, str>> {
47        fn type_name_of_val<T>(_: T) -> &'static str {
48            std::any::type_name::<T>()
49        }
50        let s = type_name_of_val(&self.0).trim_start_matches('&');
51        if s.is_empty() {
52            None
53        } else {
54            Some(Cow::Borrowed(s))
55        }
56    }
57}
58
59#[test]
60fn test_object() {
61    macro_rules! print_object {
62        ($expr:expr, $mode:ident) => {{
63            use $crate::print::PrintObject;
64            #[allow(unused_mut)]
65            let mut _tmp = ($expr,);
66            _tmp.print_object($crate::print::PrintMode::$mode)
67                .map(|x| x.to_string())
68        }};
69    }
70
71    struct NoDebugNoString;
72
73    struct DoNotCallMe;
74
75    impl DoNotCallMe {
76        #[allow(unused)]
77        fn print_object(&self, mode: PrintMode) {
78            panic!("never call me");
79        }
80    }
81
82    assert_eq!(
83        print_object!(&DoNotCallMe, Default).as_deref(),
84        Some("similar_asserts::print::test_object::DoNotCallMe")
85    );
86    assert_eq!(
87        print_object!(&NoDebugNoString, Default).as_deref(),
88        Some("similar_asserts::print::test_object::NoDebugNoString")
89    );
90    assert_eq!(
91        print_object!(vec![1, 2, 3], Default).as_deref(),
92        Some("[1, 2, 3]")
93    );
94    assert_eq!(
95        print_object!(vec![1, 2, 3], Expanded).as_deref(),
96        Some("[\n    1,\n    2,\n    3,\n]")
97    );
98    assert_eq!(print_object!(&"Hello", Default).as_deref(), Some("Hello"));
99    assert_eq!(print_object!(&"Hello", Expanded).as_deref(), None);
100}