tag2upload_service_manager/
fmt_cmp.rs

1//! Like the `fmt-cmp` crate, but only handles comparisons to fixed strings
2
3use crate::prelude::*;
4
5struct State<'s> {
6    remain: Result<&'s str, Differs>,
7}
8
9#[derive(Copy, Clone)]
10struct Differs;
11
12impl From<Differs> for fmt::Error {
13    fn from(Differs: Differs) -> fmt::Error { fmt::Error }
14}
15
16impl fmt::Write for State<'_> {
17    fn write_str(&mut self, chunk: &str) -> fmt::Result {
18        self.remain = self.remain?.strip_prefix(chunk).ok_or(Differs);
19        self.remain?;
20        Ok(())
21    }
22}
23
24pub fn display_eq(s: &str, t: impl Display) -> bool {
25    let mut state = State { remain: Ok(s) };
26    match (write!(&mut state, "{}", t), state.remain) {
27        (Ok(()), Ok(remain)) => remain.is_empty(),
28        (_, Err(Differs)) => false,
29        (Err(fmt::Error), Ok(_)) => panic!("display impl panicked"),
30    }
31}
32
33#[test]
34fn test() {
35    struct DisplayStrs<'s>(&'s [&'s str]);
36    impl Display for DisplayStrs<'_> {
37        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38            for s in self.0 {
39                Display::fmt(s, f)?;
40            }
41            Ok(())
42        }
43    }
44
45    let chk = |eq, s, l| {
46        assert_eq!(
47            eq,
48            display_eq(s, DisplayStrs(l)),
49            "{s:?} {l:?}",
50        );
51    };
52
53    chk(true, "abc", &["abc"]);
54    chk(true, "abc", &["a", "bc"]);
55    chk(true, "abc", &["a", "", "bc"]);
56    chk(true, "abc", &["a", "", "bc", ""]);
57
58    chk(false, "abc", &["ab"]);
59    chk(false, "abc", &["a", "b"]);
60    chk(false, "abc", &["", "a", "", "b", ""]);
61
62    chk(false, "abc", &["abcd"]);
63    chk(false, "abc", &["ab", "cd"]);
64    chk(false, "abc", &["ab", "c", "d"]);
65    chk(false, "abc", &["ab", "c", "", "d"]);
66
67    chk(false, "abc", &["ab2"]);
68    chk(false, "abc", &["ab", "2"]);
69}