fmt_compare_nostd/
lib.rs

1//! Utility functions for Display/Debug trait comparison in no_std environment.
2//!
3//! This crate provides functions to compare output of Display and Debug traits against &str
4//! in no_std env. No `alloc` nor `std` is used.
5//!
6//! # Quick Start
7//!
8//! ```
9//! #![no_std]
10//! use fmt_compare_nostd::eq_display;
11//! use core::fmt::{Display, Formatter, Result};
12//!
13//! struct D {}
14//!
15//! impl Display for D {
16//!    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
17//!        write!(f, "Display D")
18//!    }
19//! }
20//!
21//! # fn main() {
22//! assert!(eq_display(&D {}, "Display D"));
23//! # }
24//! ```
25
26use core::fmt::{Debug, Display, Result, Write};
27
28pub fn eq_display(d: &impl Display, s: &str) -> bool {
29    let mut cmp = Comparator::new(s);
30    write!(&mut cmp, "{}", d).is_ok() && cmp.is_valid()
31}
32
33pub fn eq_debug(d: &impl Debug, s: &str) -> bool {
34    let mut cmp = Comparator::new(s);
35    write!(&mut cmp, "{:?}", d).is_ok() && cmp.is_valid()
36}
37
38struct Comparator<'a> {
39    to_compare: &'a str,
40}
41
42impl<'a> Comparator<'a> {
43    fn new(s: &'a str) -> Self {
44        Self { to_compare: s }
45    }
46
47    fn is_valid(&self) -> bool {
48        // this is needed for situation where we have long &str on one side, and several shorter expressions
49        // on other side, which don't sum up to len(&str). For example without this condition this will yield true:
50        // write!("{} {}", "A","B") vs "A B C".
51        self.to_compare.is_empty()
52    }
53}
54
55impl<'a> Write for Comparator<'a> {
56    fn write_str(&mut self, s: &str) -> Result {
57        if s.eq(self.to_compare) {
58            self.to_compare = "";
59            return Ok(());
60        }
61
62        if self.to_compare.starts_with(s) && self.to_compare.len() >= s.len() {
63            self.to_compare = &self.to_compare[s.len()..];
64        } else {
65            return Err(core::fmt::Error);
66        }
67        Ok(())
68    }
69}
70
71#[cfg(test)]
72mod tests {
73
74    use core::fmt::{Display, Formatter, Result};
75
76    #[derive(Debug)]
77    struct D {}
78
79    impl Display for D {
80        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
81            write!(f, "Display D")
82        }
83    }
84
85    mod display {
86        use super::D;
87        use crate::eq_display;
88
89        #[test]
90        fn it_works() {
91            assert!(eq_display(&D {}, "Display D"));
92        }
93
94        #[test]
95        fn too_short() {
96            assert!(!eq_display(&D {}, "Display"));
97        }
98
99        #[test]
100        fn too_long() {
101            assert!(!eq_display(&D {}, "Display DD"));
102        }
103
104        #[test]
105        fn different() {
106            assert!(!eq_display(&D {}, "Totally different str"));
107        }
108    }
109
110    mod debug {
111        use super::D;
112        use crate::eq_debug;
113
114        #[test]
115        fn it_works() {
116            assert!(eq_debug(&D {}, "D"));
117        }
118
119        #[test]
120        fn too_short() {
121            assert!(!eq_debug(&D {}, ""));
122        }
123
124        #[test]
125        fn too_long() {
126            assert!(!eq_debug(&D {}, "DD"));
127        }
128
129        #[test]
130        fn different() {
131            assert!(!eq_debug(&D {}, "A"));
132        }
133    }
134}