1use std::ops::{Index, IndexMut};
2
3use color::Color;
4
5#[derive(Debug, Clone, PartialEq)]
7pub struct Legend {
8 pub text: String,
10 pub size_idx: usize,
12 pub color: Color,
14}
15
16impl Legend {
17 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#[derive(Debug, Clone, Default)]
29pub struct Legends([Option<Legend>; 9]);
30
31impl Legends {
32 #[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 pub fn iter(&self) -> std::slice::Iter<Option<Legend>> {
50 self.0.iter()
51 }
52}
53
54impl From<[Option<Legend>; 9]> for Legends {
55 fn from(value: [Option<Legend>; 9]) -> Self {
57 Self(value)
58 }
59}
60
61impl From<[[Option<Legend>; 3]; 3]> for Legends {
62 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 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 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 fn index(&self, index: usize) -> &Self::Output {
97 self.0.index(index)
98 }
99}
100
101impl IndexMut<usize> for Legends {
102 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 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 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}