Skip to main content

display_more/
display_slice.rs

1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16
17/// Implement `Display` for `&[T]` if T is `Display`.
18///
19/// It outputs at most `limit` elements, excluding those from the 5th to the second-to-last one:
20/// - `DisplaySlice{ slice: &[1,2,3,4,5,6], ...}` outputs: `"[1,2,3,4,...,6]"`.
21pub struct DisplaySlice<'a, T: fmt::Display> {
22    slice: &'a [T],
23    /// The maximum number of elements to display. by default, it is 5.
24    limit: Option<usize>,
25    /// The separator between elements. by default, it is ",".
26    separator: &'a str,
27}
28
29impl<'a, T: fmt::Display> DisplaySlice<'a, T> {
30    pub fn new(slice: &'a [T]) -> Self {
31        Self {
32            slice,
33            limit: None,
34            separator: ",",
35        }
36    }
37
38    pub fn at_most(mut self, limit: Option<usize>) -> Self {
39        self.limit = limit;
40        self
41    }
42
43    pub fn sep(mut self, separator: &'a str) -> Self {
44        self.separator = separator;
45        self
46    }
47
48    pub fn limit(&self) -> usize {
49        self.limit.unwrap_or(5)
50    }
51}
52
53impl<T: fmt::Display> fmt::Display for DisplaySlice<'_, T> {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        let limit = self.limit();
56
57        if limit == 0 {
58            return write!(f, "[..]");
59        }
60
61        let slice = self.slice;
62        let len = slice.len();
63
64        write!(f, "[")?;
65
66        let sep = self.separator;
67
68        if len > limit {
69            for t in slice[..(limit - 1)].iter() {
70                write!(f, "{}{}", t, sep)?;
71            }
72
73            write!(f, "..{}", sep)?;
74            write!(f, "{}", slice.last().unwrap())?;
75        } else {
76            for (i, t) in slice.iter().enumerate() {
77                if i > 0 {
78                    write!(f, "{}", sep)?;
79                }
80
81                write!(f, "{}", t)?;
82            }
83        }
84
85        write!(f, "]")
86    }
87}
88
89/// Implement `Display` for `&[T]` if T is `Display`.
90///
91/// It outputs at most `MAX` elements, excluding those from the 5th to the second-to-last one:
92/// - `DisplaySlice(&[1,2,3,4,5,6])` outputs: `"[1,2,3,4,...,6]"`.
93///
94/// # Example
95///
96/// ```rust
97/// use display_more::DisplaySliceExt;
98///
99/// let a = vec![1, 2, 3, 4, 5, 6];
100/// assert_eq!(a.display().to_string(), "[1,2,3,4,..,6]");
101/// ```
102pub trait DisplaySliceExt<'a, T: fmt::Display> {
103    fn display(&'a self) -> DisplaySlice<'a, T>;
104
105    /// Display at most `n` elements.
106    fn display_n(&'a self, n: usize) -> DisplaySlice<'a, T> {
107        self.display().at_most(Some(n))
108    }
109}
110
111impl<T> DisplaySliceExt<'_, T> for [T]
112where T: fmt::Display
113{
114    fn display(&self) -> DisplaySlice<T> {
115        DisplaySlice::new(self)
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::DisplaySlice;
122    use crate::DisplaySliceExt;
123
124    #[test]
125    fn test_display_slice() {
126        let a = vec![1, 2, 3, 4];
127        assert_eq!("[1,2,3,4]", DisplaySlice::new(&a).to_string());
128
129        let a = vec![1, 2, 3, 4, 5];
130        assert_eq!("[1,2,3,4,5]", DisplaySlice::new(&a).to_string());
131
132        let a = vec![1, 2, 3, 4, 5, 6];
133        assert_eq!("[1,2,3,4,..,6]", DisplaySlice::new(&a).to_string());
134
135        let a = vec![1, 2, 3, 4, 5, 6, 7];
136        assert_eq!("[1,2,3,4,..,7]", DisplaySlice::new(&a).to_string());
137
138        // with limit
139
140        let a = vec![1, 2, 3, 4, 5, 6, 7];
141        assert_eq!(
142            "[1,..,7]",
143            DisplaySlice::new(&a).at_most(Some(2)).to_string()
144        );
145
146        assert_eq!("[1,..,7]", a.display().at_most(Some(2)).to_string());
147
148        assert_eq!("[1,..,7]", a.display_n(2).to_string());
149
150        assert_eq!("[..,7]", a.display_n(1).to_string());
151
152        assert_eq!("[..]", a.display_n(0).to_string());
153    }
154
155    #[test]
156    fn test_display_slice_separator() {
157        let a = vec![1, 2, 3];
158        assert_eq!("[1, 2, 3]", a.display().sep(", ").to_string());
159
160        let a = vec![1, 2, 3, 4, 5, 6];
161        assert_eq!("[1, 2, 3, 4, .., 6]", a.display().sep(", ").to_string());
162
163        assert_eq!("[1|..|6]", a.display_n(2).sep("|").to_string());
164
165        assert_eq!("[1 2 3 4 .. 6]", a.display().sep(" ").to_string());
166
167        assert_eq!("[1234..6]", a.display().sep("").to_string());
168        assert_eq!("[1..6]", a.display_n(2).sep("").to_string());
169
170        // limit=1 with custom separator
171        assert_eq!("[.. 6]", a.display_n(1).sep(" ").to_string());
172
173        // limit=0 is unaffected by separator
174        assert_eq!("[..]", a.display_n(0).sep(" ").to_string());
175    }
176}