Skip to main content

display_more/
display_into_iter.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
17use crate::display_iterator_options::DisplayIteratorOptions;
18
19/// Implement `Display` for cloneable iter sources that yield `&T`.
20///
21/// It outputs at most `limit` elements, excluding those from the 5th to the second-to-last one.
22pub struct DisplayIntoIter<'a, T, S>
23where
24    T: fmt::Display + 'a,
25    S: Clone + IntoIterator<Item = &'a T>,
26    S::IntoIter: DoubleEndedIterator + ExactSizeIterator,
27{
28    items: S,
29    options: DisplayIteratorOptions<'a>,
30}
31
32impl<'a, T, S> DisplayIntoIter<'a, T, S>
33where
34    T: fmt::Display + 'a,
35    S: Clone + IntoIterator<Item = &'a T>,
36    S::IntoIter: DoubleEndedIterator + ExactSizeIterator,
37{
38    pub fn new(items: S) -> Self {
39        Self {
40            items,
41            options: DisplayIteratorOptions::default(),
42        }
43    }
44
45    pub fn at_most(mut self, limit: Option<usize>) -> Self {
46        self.options.limit = limit;
47        self
48    }
49
50    pub fn sep(mut self, separator: &'a str) -> Self {
51        self.options.separator = separator;
52        self
53    }
54
55    pub fn braces(mut self, left: &'a str, right: &'a str) -> Self {
56        self.options.left_brace = left;
57        self.options.right_brace = right;
58        self
59    }
60
61    pub fn ellipsis(mut self, s: &'a str) -> Self {
62        self.options.ellipsis = s;
63        self
64    }
65
66    pub fn elem(mut self, prefix: &'a str, suffix: &'a str) -> Self {
67        self.options.elem_prefix = prefix;
68        self.options.elem_suffix = suffix;
69        self
70    }
71
72    pub fn show_count(mut self) -> Self {
73        self.options.show_count = true;
74        self
75    }
76
77    pub fn limit(&self) -> usize {
78        self.options.limit()
79    }
80}
81
82impl<'a, T, S> fmt::Display for DisplayIntoIter<'a, T, S>
83where
84    T: fmt::Display + 'a,
85    S: Clone + IntoIterator<Item = &'a T>,
86    S::IntoIter: DoubleEndedIterator + ExactSizeIterator,
87{
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        let limit = self.limit();
90        let len = self.items.clone().into_iter().len();
91        let truncated = len > limit;
92        let options = &self.options;
93
94        let ell;
95        let ellipsis = if options.show_count && truncated {
96            ell = format!("{}({len} total)", options.ellipsis);
97            &ell
98        } else {
99            options.ellipsis
100        };
101
102        if limit == 0 {
103            return write!(f, "{}{ellipsis}{}", options.left_brace, options.right_brace);
104        }
105
106        write!(f, "{}", options.left_brace)?;
107
108        let (pre, suf, sep) = (options.elem_prefix, options.elem_suffix, options.separator);
109
110        if truncated {
111            let mut iter = self.items.clone().into_iter();
112
113            for _ in 0..(limit - 1) {
114                let item = iter.next().unwrap();
115                write!(f, "{pre}{item}{suf}{sep}")?;
116            }
117
118            write!(f, "{ellipsis}{sep}")?;
119            write!(
120                f,
121                "{pre}{}{suf}",
122                self.items.clone().into_iter().next_back().unwrap()
123            )?;
124        } else {
125            for (i, item) in self.items.clone().into_iter().enumerate() {
126                if i > 0 {
127                    write!(f, "{sep}")?;
128                }
129
130                write!(f, "{pre}{item}{suf}")?;
131            }
132        }
133
134        write!(f, "{}", options.right_brace)
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use std::collections::BTreeSet;
141
142    use super::DisplayIntoIter;
143
144    #[derive(Clone)]
145    struct Items<'a, T>(&'a [T]);
146
147    impl<'a, T> IntoIterator for Items<'a, T> {
148        type Item = &'a T;
149        type IntoIter = std::slice::Iter<'a, T>;
150
151        fn into_iter(self) -> Self::IntoIter {
152            self.0.iter()
153        }
154    }
155
156    #[test]
157    fn test_display_into_iter_slice() {
158        let values = [1, 2, 3, 4, 5, 6];
159        assert_eq!(
160            "[1,2,3,4,..,6]",
161            DisplayIntoIter::new(values.iter()).to_string()
162        );
163    }
164
165    #[test]
166    fn test_display_into_iter_btreeset() {
167        let values = (1..=6).collect::<BTreeSet<_>>();
168        assert_eq!("[1,2,3,4,..,6]", DisplayIntoIter::new(&values).to_string());
169    }
170
171    #[test]
172    fn test_display_into_iter_custom_container() {
173        let values = [1, 2, 3, 4, 5, 6];
174        assert_eq!(
175            "[1,2,..,6]",
176            DisplayIntoIter::new(Items(&values))
177                .at_most(Some(3))
178                .to_string()
179        );
180    }
181
182    #[test]
183    fn test_display_into_iter_limit_edges() {
184        let values = [1, 2, 3, 4, 5, 6];
185
186        assert_eq!(
187            "[..]",
188            DisplayIntoIter::new(values.iter())
189                .at_most(Some(0))
190                .to_string()
191        );
192        assert_eq!(
193            "[..,6]",
194            DisplayIntoIter::new(values.iter())
195                .at_most(Some(1))
196                .to_string()
197        );
198    }
199
200    #[test]
201    fn test_display_into_iter_combined_formatting() {
202        let values = [1, 2, 3, 4, 5, 6, 7];
203
204        assert_eq!(
205            "{'1' | '2' | '3' | '4' | ...(7 total) | '7'}",
206            DisplayIntoIter::new(values.iter())
207                .ellipsis("...")
208                .show_count()
209                .elem("'", "'")
210                .sep(" | ")
211                .braces("{", "}")
212                .to_string()
213        );
214    }
215}