blob: 13be3d7f4340aa3881e39bc51aa128dca9e869b5 [file] [log] [blame]
use crate::coord::ranged1d::{
AsRangedCoord, DefaultFormatting, DiscreteRanged, KeyPointHint, Ranged,
};
use std::ops::Range;
/// A range that is defined by a slice of values.
///
/// Please note: the behavior of constructing an empty range may cause panic
#[derive(Clone)]
pub struct RangedSlice<'a, T: PartialEq>(&'a [T]);
impl<'a, T: PartialEq> Ranged for RangedSlice<'a, T> {
type FormatOption = DefaultFormatting;
type ValueType = &'a T;
fn range(&self) -> Range<&'a T> {
// If inner slice is empty, we should always panic
&self.0[0]..&self.0[self.0.len() - 1]
}
fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
match self.0.iter().position(|x| &x == value) {
Some(pos) => {
let pixel_span = limit.1 - limit.0;
let value_span = self.0.len() - 1;
(f64::from(limit.0)
+ f64::from(pixel_span)
* (f64::from(pos as u32) / f64::from(value_span as u32)))
.round() as i32
}
None => limit.0,
}
}
fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> {
let max_points = hint.max_num_points();
let mut ret = vec![];
let intervals = (self.0.len() - 1) as f64;
let step = (intervals / max_points as f64 + 1.0) as usize;
for idx in (0..self.0.len()).step_by(step) {
ret.push(&self.0[idx]);
}
ret
}
}
impl<'a, T: PartialEq> DiscreteRanged for RangedSlice<'a, T> {
fn size(&self) -> usize {
self.0.len()
}
fn index_of(&self, value: &&'a T) -> Option<usize> {
self.0.iter().position(|x| &x == value)
}
fn from_index(&self, index: usize) -> Option<&'a T> {
if self.0.len() <= index {
return None;
}
Some(&self.0[index])
}
}
impl<'a, T: PartialEq> From<&'a [T]> for RangedSlice<'a, T> {
fn from(range: &'a [T]) -> Self {
RangedSlice(range)
}
}
impl<'a, T: PartialEq> AsRangedCoord for &'a [T] {
type CoordDescType = RangedSlice<'a, T>;
type Value = &'a T;
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_slice_range() {
let my_slice = [1, 2, 3, 0, -1, -2];
let slice_range: RangedSlice<i32> = my_slice[..].into();
assert_eq!(slice_range.range(), &1..&-2);
assert_eq!(
slice_range.key_points(6),
my_slice.iter().collect::<Vec<_>>()
);
assert_eq!(slice_range.map(&&0, (0, 50)), 30);
}
#[test]
fn test_slice_range_discrete() {
let my_slice = [1, 2, 3, 0, -1, -2];
let slice_range: RangedSlice<i32> = my_slice[..].into();
assert_eq!(slice_range.size(), 6);
assert_eq!(slice_range.index_of(&&3), Some(2));
assert_eq!(slice_range.from_index(2), Some(&3));
}
}