sparklines 0.3.0

Sparklines library
Documentation
use crate::{BuildIndexer, Indexer};
use ordered_float::OrderedFloat;
use rangemap::RangeMap;

#[derive(Default)]
pub struct BuildRangemapIndexer;

pub struct RangemapIndexer {
    min: OrderedFloat<f64>,
    max: OrderedFloat<f64>,
    map: RangeMap<OrderedFloat<f64>, usize>,
}

fn next_up(v: f64) -> f64 {
    if v.is_nan() || v == f64::INFINITY {
        v
    } else if v == 0.0f64 && v.is_sign_negative() {
        f64::MIN_POSITIVE
    } else if v >= 0.0 {
        f64::from_bits(v.to_bits() + 1)
    } else {
        f64::from_bits(v.to_bits() - 1)
    }
}

impl Indexer<f64, usize> for RangemapIndexer {
    fn index(&self, v: f64) -> usize {
        let value = OrderedFloat(v).max(self.min).min(self.max);
        *self.map.get(&value).expect("value not in range")
    }
}

impl BuildIndexer<f64, usize> for BuildRangemapIndexer {
    type Indexer = RangemapIndexer;

    fn build_indexer<C>(&self, min: f64, max: f64, ticks: &[C]) -> Self::Indexer {
        let step = (max - min) / (ticks.len() as f64 - 1.0);
        let mut map = RangeMap::new();
        let mut start = min;
        for idx in 0..ticks.len() {
            let mut end = if idx == ticks.len() - 1 {
                max
            } else {
                min + step * (idx as f64 + 1.0)
            };
            if idx == ticks.len() - 1 {
                end = next_up(end);
            }
            map.insert(OrderedFloat(start)..OrderedFloat(end), idx);
            start = end;
        }
        RangemapIndexer {
            min: OrderedFloat(min),
            max: OrderedFloat(max),
            map,
        }
    }
}