ndhistogram/axis/bininterval/
bininterval.rsuse std::{
convert::TryFrom,
error::Error,
fmt::{Display, LowerExp, UpperExp},
ops::{Range, RangeFrom, RangeTo},
};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum BinInterval<T> {
Underflow {
end: T,
},
Overflow {
start: T,
},
Bin {
start: T,
end: T,
},
}
impl<T> BinInterval<T> {
pub fn underflow(end: T) -> Self {
Self::Underflow { end }
}
pub fn overflow(start: T) -> Self {
Self::Overflow { start }
}
pub fn new(start: T, end: T) -> Self {
Self::Bin { start, end }
}
}
impl<T: Copy> BinInterval<T> {
pub fn start(&self) -> Option<T> {
match self {
Self::Underflow { end: _ } => None,
Self::Overflow { start } => Some(*start),
Self::Bin { start, end: _ } => Some(*start),
}
}
pub fn end(&self) -> Option<T> {
match self {
Self::Underflow { end } => Some(*end),
Self::Overflow { start: _ } => None,
Self::Bin { start: _, end } => Some(*end),
}
}
}
impl<T> From<Range<T>> for BinInterval<T> {
fn from(other: Range<T>) -> Self {
Self::Bin {
start: other.start,
end: other.end,
}
}
}
impl<T> From<RangeTo<T>> for BinInterval<T> {
fn from(other: RangeTo<T>) -> Self {
Self::Underflow { end: other.end }
}
}
impl<T> From<RangeFrom<T>> for BinInterval<T> {
fn from(other: RangeFrom<T>) -> Self {
Self::Overflow { start: other.start }
}
}
impl<T> TryFrom<BinInterval<T>> for Range<T> {
type Error = BinIntervalConversionError;
fn try_from(value: BinInterval<T>) -> Result<Self, Self::Error> {
if let BinInterval::Bin { start, end } = value {
return Ok(Self { start, end });
}
Err(BinIntervalConversionError)
}
}
impl<T> TryFrom<BinInterval<T>> for RangeTo<T> {
type Error = BinIntervalConversionError;
fn try_from(value: BinInterval<T>) -> Result<Self, Self::Error> {
if let BinInterval::Underflow { end } = value {
return Ok(Self { end });
}
Err(BinIntervalConversionError)
}
}
impl<T> TryFrom<BinInterval<T>> for RangeFrom<T> {
type Error = BinIntervalConversionError;
fn try_from(value: BinInterval<T>) -> Result<Self, Self::Error> {
if let BinInterval::Overflow { start } = value {
return Ok(Self { start });
}
Err(BinIntervalConversionError)
}
}
macro_rules! impl_display {
($Trait:ident) => {
impl<T: $Trait> $Trait for BinInterval<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Underflow { end } => {
write!(f, "(-inf, ")?;
end.fmt(f)?;
write!(f, ")")?;
}
Self::Overflow { start } => {
write!(f, "[")?;
start.fmt(f)?;
write!(f, ", inf)")?;
}
Self::Bin { start, end } => {
write!(f, "[")?;
start.fmt(f)?;
write!(f, ", ")?;
end.fmt(f)?;
write!(f, ")")?;
}
}
Ok(())
}
}
};
}
impl_display! {Display}
impl_display! {LowerExp}
impl_display! {UpperExp}
#[derive(Debug)]
pub struct BinIntervalConversionError;
impl Display for BinIntervalConversionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid range to bin interval conversion")
}
}
impl Error for BinIntervalConversionError {}