Skip to main content

safelog/
util.rs

1//! Helper functions for writing redacted strings.
2
3use 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`.
8pub fn write_start_redacted(
9    f: &mut fmt::Formatter,
10    input: &str,
11    chars: usize,
12    ellipsis: &str,
13) -> fmt::Result {
14    if let Some((pos, _)) = input.char_indices().nth(chars) {
15        let slice = input
16            .get(..pos)
17            .expect("Mismatched character offset calculation");
18        write!(f, "{slice}{ellipsis}")
19    } else {
20        write!(f, "{input}")
21    }
22}
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`.
27pub fn write_end_redacted(
28    f: &mut fmt::Formatter,
29    input: &str,
30    chars: usize,
31    ellipsis: &str,
32) -> fmt::Result {
33    if chars == 0 {
34        if input.is_empty() {
35            Ok(())
36        } else {
37            write!(f, "{ellipsis}")
38        }
39    } else if let Some((pos, _)) = input.char_indices().nth_back(chars - 1)
40        && pos != 0
41    {
42        let slice = input
43            .get(pos..)
44            .expect("Mismatched character offset calculation");
45        write!(f, "{ellipsis}{slice}")
46    } else {
47        write!(f, "{input}")
48    }
49}
50
51#[cfg(test)]
52mod 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}