1 | use crate::coord::ranged1d::{ |
2 | AsRangedCoord, DefaultFormatting, DiscreteRanged, KeyPointHint, Ranged, |
3 | }; |
4 | use std::ops::Range; |
5 | |
6 | /// A range that is defined by a slice of values. |
7 | /// |
8 | /// Please note: the behavior of constructing an empty range may cause panic |
9 | #[derive(Clone)] |
10 | pub struct RangedSlice<'a, T: PartialEq>(&'a [T]); |
11 | |
12 | impl<'a, T: PartialEq> Ranged for RangedSlice<'a, T> { |
13 | type FormatOption = DefaultFormatting; |
14 | type ValueType = &'a T; |
15 | |
16 | fn range(&self) -> Range<&'a T> { |
17 | // If inner slice is empty, we should always panic |
18 | &self.0[0]..&self.0[self.0.len() - 1] |
19 | } |
20 | |
21 | fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 { |
22 | match self.0.iter().position(|x| &x == value) { |
23 | Some(pos) => { |
24 | let pixel_span = limit.1 - limit.0; |
25 | let value_span = self.0.len() - 1; |
26 | (f64::from(limit.0) |
27 | + f64::from(pixel_span) |
28 | * (f64::from(pos as u32) / f64::from(value_span as u32))) |
29 | .round() as i32 |
30 | } |
31 | None => limit.0, |
32 | } |
33 | } |
34 | |
35 | fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> { |
36 | let max_points = hint.max_num_points(); |
37 | let mut ret = vec![]; |
38 | let intervals = (self.0.len() - 1) as f64; |
39 | let step = (intervals / max_points as f64 + 1.0) as usize; |
40 | for idx in (0..self.0.len()).step_by(step) { |
41 | ret.push(&self.0[idx]); |
42 | } |
43 | ret |
44 | } |
45 | } |
46 | |
47 | impl<'a, T: PartialEq> DiscreteRanged for RangedSlice<'a, T> { |
48 | fn size(&self) -> usize { |
49 | self.0.len() |
50 | } |
51 | |
52 | fn index_of(&self, value: &&'a T) -> Option<usize> { |
53 | self.0.iter().position(|x| &x == value) |
54 | } |
55 | |
56 | fn from_index(&self, index: usize) -> Option<&'a T> { |
57 | if self.0.len() <= index { |
58 | return None; |
59 | } |
60 | Some(&self.0[index]) |
61 | } |
62 | } |
63 | |
64 | impl<'a, T: PartialEq> From<&'a [T]> for RangedSlice<'a, T> { |
65 | fn from(range: &'a [T]) -> Self { |
66 | RangedSlice(range) |
67 | } |
68 | } |
69 | |
70 | impl<'a, T: PartialEq> AsRangedCoord for &'a [T] { |
71 | type CoordDescType = RangedSlice<'a, T>; |
72 | type Value = &'a T; |
73 | } |
74 | |
75 | #[cfg (test)] |
76 | mod test { |
77 | use super::*; |
78 | #[test] |
79 | fn test_slice_range() { |
80 | let my_slice = [1, 2, 3, 0, -1, -2]; |
81 | let slice_range: RangedSlice<i32> = my_slice[..].into(); |
82 | |
83 | assert_eq!(slice_range.range(), &1..&-2); |
84 | assert_eq!( |
85 | slice_range.key_points(6), |
86 | my_slice.iter().collect::<Vec<_>>() |
87 | ); |
88 | assert_eq!(slice_range.map(&&0, (0, 50)), 30); |
89 | } |
90 | |
91 | #[test] |
92 | fn test_slice_range_discrete() { |
93 | let my_slice = [1, 2, 3, 0, -1, -2]; |
94 | let slice_range: RangedSlice<i32> = my_slice[..].into(); |
95 | |
96 | assert_eq!(slice_range.size(), 6); |
97 | assert_eq!(slice_range.index_of(&&3), Some(2)); |
98 | assert_eq!(slice_range.from_index(2), Some(&3)); |
99 | } |
100 | } |
101 | |