1
//! Helper functions for writing redacted strings.
2

            
3
use std::fmt;
4

            
5
/// Write up to `chars` _characters_ from the start of `input` onto `f`.
6
///
7
/// If any characters are removed, replace them with `ellipsis`.
8
104
pub fn write_start_redacted(
9
104
    f: &mut fmt::Formatter,
10
104
    input: &str,
11
104
    chars: usize,
12
104
    ellipsis: &str,
13
104
) -> fmt::Result {
14
104
    if let Some((pos, _)) = input.char_indices().nth(chars) {
15
92
        let slice = input
16
92
            .get(..pos)
17
92
            .expect("Mismatched character offset calculation");
18
92
        write!(f, "{slice}{ellipsis}")
19
    } else {
20
12
        write!(f, "{input}")
21
    }
22
104
}
23

            
24
/// Write up to `chars`  _characters_ from the end of `input` onto `f`.
25
///
26
/// If any characters are removed, replace them with `ellipsis`.
27
62096
pub fn write_end_redacted(
28
62096
    f: &mut fmt::Formatter,
29
62096
    input: &str,
30
62096
    chars: usize,
31
62096
    ellipsis: &str,
32
62096
) -> fmt::Result {
33
62096
    if chars == 0 {
34
6
        if input.is_empty() {
35
2
            Ok(())
36
        } else {
37
4
            write!(f, "{ellipsis}")
38
        }
39
62090
    } else if let Some((pos, _)) = input.char_indices().nth_back(chars - 1)
40
62084
        && pos != 0
41
    {
42
62080
        let slice = input
43
62080
            .get(pos..)
44
62080
            .expect("Mismatched character offset calculation");
45
62080
        write!(f, "{ellipsis}{slice}")
46
    } else {
47
10
        write!(f, "{input}")
48
    }
49
62096
}
50

            
51
#[cfg(test)]
52
mod test {
53
    // @@ begin test lint list maintained by maint/add_warning @@
54
    #![allow(clippy::bool_assert_comparison)]
55
    #![allow(clippy::clone_on_copy)]
56
    #![allow(clippy::dbg_macro)]
57
    #![allow(clippy::mixed_attributes_style)]
58
    #![allow(clippy::print_stderr)]
59
    #![allow(clippy::print_stdout)]
60
    #![allow(clippy::single_char_pattern)]
61
    #![allow(clippy::unwrap_used)]
62
    #![allow(clippy::unchecked_time_subtraction)]
63
    #![allow(clippy::useless_vec)]
64
    #![allow(clippy::needless_pass_by_value)]
65
    #![allow(clippy::string_slice)] // See arti#2571
66
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
67

            
68
    use super::*;
69

            
70
    struct Fmt<'a> {
71
        string: &'a str,
72
        n: usize,
73
        start: bool,
74
    }
75

            
76
    impl<'a> fmt::Display for Fmt<'a> {
77
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78
            if self.start {
79
                write_start_redacted(f, self.string, self.n, "…")
80
            } else {
81
                write_end_redacted(f, self.string, self.n, "…")
82
            }
83
        }
84
    }
85

            
86
    fn rstart(string: &str, n: usize) -> String {
87
        Fmt {
88
            string,
89
            n,
90
            start: true,
91
        }
92
        .to_string()
93
    }
94

            
95
    fn rend(string: &str, n: usize) -> String {
96
        Fmt {
97
            string,
98
            n,
99
            start: false,
100
        }
101
        .to_string()
102
    }
103

            
104
    #[test]
105
    fn test_redact_start() {
106
        assert_eq!(&rstart("hello world", 2), "he…");
107
        assert_eq!(&rstart("he", 2), "he");
108
        assert_eq!(&rstart("h", 2), "h");
109
        assert_eq!(&rstart("", 2), "");
110

            
111
        assert_eq!(&rstart("", 0), "");
112
        assert_eq!(&rstart("hello", 0), "…");
113

            
114
        assert_eq!(&rstart("分久必合,合久必分", 2), "分久…");
115
        assert_eq!(&rstart("分久必合,合久必分", 4), "分久必合…");
116
        assert_eq!(&rstart("分久必合,合久必分", 9), "分久必合,合久必分");
117
        assert_eq!(&rstart("分久必合,合久必分", 10), "分久必合,合久必分");
118
        assert_eq!(&rstart("分久必合,合久必分", 0), "…");
119
    }
120

            
121
    #[test]
122
    fn test_redact_end() {
123
        assert_eq!(&rend("hello world", 2), "…ld");
124
        assert_eq!(&rend("he", 2), "he");
125
        assert_eq!(&rend("h", 2), "h");
126
        assert_eq!(&rend("", 2), "");
127

            
128
        assert_eq!(&rend("", 0), "");
129
        assert_eq!(&rend("hello", 0), "…");
130

            
131
        assert_eq!(&rend("分久必合,合久必分", 2), "…必分");
132
        assert_eq!(&rend("分久必合,合久必分", 4), "…合久必分");
133
        assert_eq!(&rend("分久必合,合久必分", 9), "分久必合,合久必分");
134
        assert_eq!(&rend("分久必合,合久必分", 10), "分久必合,合久必分");
135
        assert_eq!(&rend("分久必合,合久必分", 0), "…");
136
    }
137
}