keyset_key/
legend.rs

1use std::ops::{Index, IndexMut};
2
3use color::Color;
4
5/// A single legend
6#[derive(Debug, Clone, PartialEq)]
7pub struct Legend {
8    /// The legend text
9    pub text: String,
10    /// The legend size
11    pub size_idx: usize,
12    /// The legend colour
13    pub color: Color,
14}
15
16impl Legend {
17    /// Create a new [`Legend`]
18    pub fn new(text: impl Into<String>, size_idx: usize, color: Color) -> Self {
19        Self {
20            text: text.into(),
21            size_idx,
22            color,
23        }
24    }
25}
26
27/// A set of legends for a key
28#[derive(Debug, Clone, Default)]
29pub struct Legends([Option<Legend>; 9]);
30
31impl Legends {
32    /// An example non-blank set of legends
33    #[must_use]
34    pub fn example() -> Self {
35        Self([
36            Some(Legend::new("!", 4, Color::new(0.0, 0.0, 0.0))),
37            None,
38            Some(Legend::new("¹", 4, Color::new(0.0, 0.0, 0.0))),
39            None,
40            None,
41            None,
42            Some(Legend::new("1", 4, Color::new(0.0, 0.0, 0.0))),
43            None,
44            Some(Legend::new("¡", 4, Color::new(0.0, 0.0, 0.0))),
45        ])
46    }
47
48    /// Creates an iterator in a left-to-right, top-to-bottom order
49    pub fn iter(&self) -> std::slice::Iter<Option<Legend>> {
50        self.0.iter()
51    }
52}
53
54impl From<[Option<Legend>; 9]> for Legends {
55    /// Converts from an array in left-to-right, top-to-bottom order
56    fn from(value: [Option<Legend>; 9]) -> Self {
57        Self(value)
58    }
59}
60
61impl From<[[Option<Legend>; 3]; 3]> for Legends {
62    /// Converts from an array of arrays in row-major order
63    fn from(mut value: [[Option<Legend>; 3]; 3]) -> Self {
64        let mut arr = <[Option<Legend>; 9]>::default();
65        arr[0..3].swap_with_slice(&mut value[0]);
66        arr[3..6].swap_with_slice(&mut value[1]);
67        arr[6..9].swap_with_slice(&mut value[2]);
68        Self(arr)
69    }
70}
71
72impl IntoIterator for Legends {
73    type Item = Option<Legend>;
74    type IntoIter = <[Option<Legend>; 9] as IntoIterator>::IntoIter;
75
76    /// Creates an iterator in a left-to-right, top-to-bottom order
77    fn into_iter(self) -> Self::IntoIter {
78        self.0.into_iter()
79    }
80}
81
82impl<'a> IntoIterator for &'a Legends {
83    type Item = &'a Option<Legend>;
84    type IntoIter = <&'a [Option<Legend>; 9] as IntoIterator>::IntoIter;
85
86    /// Creates an iterator in a left-to-right, top-to-bottom order
87    fn into_iter(self) -> Self::IntoIter {
88        self.0.iter()
89    }
90}
91
92impl Index<usize> for Legends {
93    type Output = Option<Legend>;
94
95    /// Indexes the legends arranged in left-to-right, top-to-bottom order
96    fn index(&self, index: usize) -> &Self::Output {
97        self.0.index(index)
98    }
99}
100
101impl IndexMut<usize> for Legends {
102    /// Mutably indexes the legends arranged in left-to-right, top-to-bottom order
103    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
104        self.0.index_mut(index)
105    }
106}
107
108impl Index<(usize, usize)> for Legends {
109    type Output = Option<Legend>;
110
111    /// Indexes the legends using a `(column, row)` tuple
112    fn index(&self, (column, row): (usize, usize)) -> &Self::Output {
113        self.0.index(row * 3 + column)
114    }
115}
116
117impl IndexMut<(usize, usize)> for Legends {
118    /// Mutably indexes the legends using a `(column, row)` tuple
119    fn index_mut(&mut self, (column, row): (usize, usize)) -> &mut Self::Output {
120        self.0.index_mut(row * 3 + column)
121    }
122}
123
124#[cfg(test)]
125pub mod tests {
126    use super::*;
127
128    #[test]
129    fn legend_new() {
130        let legend = Legend::new("test", 4, Color::new(0.0, 0.2, 0.4));
131
132        assert_eq!(legend.text, "test");
133        assert_eq!(legend.size_idx, 4);
134        assert_eq!(legend.color, Color::new(0.0, 0.2, 0.4));
135    }
136
137    #[test]
138    fn legends_example() {
139        let legends = Legends::example();
140        let legend_is_some = [true, false, true, false, false, false, true, false, true];
141
142        for (legend, is_some) in legends.into_iter().zip(legend_is_some) {
143            assert_eq!(legend.is_some(), is_some);
144        }
145    }
146
147    #[test]
148    fn legends_iter() {
149        let legends = Legends::default();
150        let mut iter = legends.iter();
151
152        for _ in 0..9 {
153            assert!(iter.next().is_some());
154        }
155        assert!(iter.next().is_none());
156    }
157
158    #[test]
159    fn legends_from() {
160        let legends: Legends = [
161            Some(Legend::new("A", 3, Color::new(0.0, 0.2, 0.4))),
162            None,
163            None,
164            None,
165            Some(Legend::new("B", 4, Color::new(0.3, 0.5, 0.7))),
166            None,
167            None,
168            None,
169            Some(Legend::new("C", 5, Color::new(0.6, 0.8, 1.0))),
170        ]
171        .into();
172        let legend_is_some = [true, false, false, false, true, false, false, false, true];
173
174        for (legend, is_some) in legends.into_iter().zip(legend_is_some) {
175            assert_eq!(legend.is_some(), is_some);
176        }
177
178        let legends: Legends = [
179            [
180                Some(Legend::new("A", 3, Color::new(0.0, 0.2, 0.4))),
181                None,
182                None,
183            ],
184            [
185                None,
186                Some(Legend::new("B", 4, Color::new(0.3, 0.5, 0.7))),
187                None,
188            ],
189            [
190                None,
191                None,
192                Some(Legend::new("C", 5, Color::new(0.6, 0.8, 1.0))),
193            ],
194        ]
195        .into();
196
197        for (legend, is_some) in legends.into_iter().zip(legend_is_some) {
198            assert_eq!(legend.is_some(), is_some);
199        }
200    }
201
202    #[test]
203    fn legends_into_iter() {
204        let mut iter = Legends::default().into_iter();
205
206        for _ in 0..9 {
207            assert!(iter.next().is_some());
208        }
209        assert!(iter.next().is_none());
210    }
211
212    #[test]
213    fn legends_index() {
214        let legends = Legends::example();
215
216        assert_eq!(legends[0].as_ref().unwrap().text, "!");
217        assert_eq!(legends[2].as_ref().unwrap().text, "¹");
218        assert_eq!(legends[6].as_ref().unwrap().text, "1");
219        assert_eq!(legends[8].as_ref().unwrap().text, "¡");
220
221        assert_eq!(legends[(0, 0)].as_ref().unwrap().text, "!");
222        assert_eq!(legends[(2, 0)].as_ref().unwrap().text, "¹");
223        assert_eq!(legends[(0, 2)].as_ref().unwrap().text, "1");
224        assert_eq!(legends[(2, 2)].as_ref().unwrap().text, "¡");
225    }
226
227    #[test]
228    fn legends_index_mut() {
229        let mut legends = Legends::default();
230
231        legends[0] = Some(Legend::new("A", 4, Color::new(0.2, 0.4, 0.6)));
232        legends[2] = Some(Legend::new("B", 4, Color::new(0.2, 0.4, 0.6)));
233        legends[6] = Some(Legend::new("C", 4, Color::new(0.2, 0.4, 0.6)));
234        legends[8] = Some(Legend::new("D", 4, Color::new(0.2, 0.4, 0.6)));
235        assert_eq!(legends[0].as_ref().unwrap().text, "A");
236        assert_eq!(legends[2].as_ref().unwrap().text, "B");
237        assert_eq!(legends[6].as_ref().unwrap().text, "C");
238        assert_eq!(legends[8].as_ref().unwrap().text, "D");
239
240        legends[(0, 0)] = Some(Legend::new("A", 4, Color::new(0.2, 0.4, 0.6)));
241        legends[(2, 0)] = Some(Legend::new("B", 4, Color::new(0.2, 0.4, 0.6)));
242        legends[(0, 2)] = Some(Legend::new("C", 4, Color::new(0.2, 0.4, 0.6)));
243        legends[(2, 2)] = Some(Legend::new("D", 4, Color::new(0.2, 0.4, 0.6)));
244        assert_eq!(legends[(0, 0)].as_ref().unwrap().text, "A");
245        assert_eq!(legends[(2, 0)].as_ref().unwrap().text, "B");
246        assert_eq!(legends[(0, 2)].as_ref().unwrap().text, "C");
247        assert_eq!(legends[(2, 2)].as_ref().unwrap().text, "D");
248    }
249}