burbomath 0.0.1

Burbokop's rust math library
Documentation
use super::{Clamp, MinusOne, One, Zero};
use crate::range::{Range, RangeInclusive};
use core::{
    error::Error,
    fmt::{Debug, Display},
    ops::{Add, Div, Mul, Sub},
};

pub fn map_into_range<T, I, O>(x: T, input: I, output: O) -> T
where
    T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
    I: Into<Range<T>>,
    O: Into<Range<T>>,
{
    let input: Range<T> = input.into();
    let output: Range<T> = output.into();
    (x - input.start.clone()) * (output.end - output.start.clone()) / (input.end - input.start)
        + output.start
}

#[derive(Debug)]
pub struct FitIntoRangeError<T> {
    pub x: T,
    pub input: Range<T>,
    pub output: Range<T>,
}

impl<T> Display for FitIntoRangeError<T> {
    fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        todo!()
    }
}

impl<T> Error for FitIntoRangeError<T> where T: Debug {}

pub fn fit_into_range<T, I, O>(x: T, input: I, output: O) -> Result<T, FitIntoRangeError<T>>
where
    T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + PartialOrd,
    I: Into<Range<T>>,
    O: Into<Range<T>>,
{
    let input: Range<T> = input.into();
    if input.contains(&x) {
        Ok(map_into_range(x, input, output))
    } else {
        Err(FitIntoRangeError {
            x,
            input,
            output: output.into(),
        })
    }
}

pub fn map_into_range_inclusive<T, I, O>(x: T, input: I, output: O) -> T
where
    T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
    I: Into<RangeInclusive<T>>,
    O: Into<RangeInclusive<T>>,
{
    let input: RangeInclusive<T> = input.into();
    let output: RangeInclusive<T> = output.into();
    (x - input.start.clone()) * (output.end - output.start.clone()) / (input.end - input.start)
        + output.start
}

#[derive(Debug)]
pub struct FitIntoRangeInclusiveError<T> {
    pub x: T,
    pub input: RangeInclusive<T>,
    pub output: RangeInclusive<T>,
}

impl<T> Display for FitIntoRangeInclusiveError<T> {
    fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        todo!()
    }
}

impl<T> Error for FitIntoRangeInclusiveError<T> where T: Debug {}

pub fn fit_into_range_inclusive<T, I, O>(
    x: T,
    input: I,
    output: O,
) -> Result<T, FitIntoRangeInclusiveError<T>>
where
    T: Clone + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + PartialOrd,
    I: Into<RangeInclusive<T>>,
    O: Into<RangeInclusive<T>>,
{
    let input: RangeInclusive<T> = input.into();
    if input.contains(&x) {
        Ok(map_into_range_inclusive(x, input, output))
    } else {
        Err(FitIntoRangeInclusiveError {
            x,
            input,
            output: output.into(),
        })
    }
}

pub fn clamp_into_range<T, I, O>(x: T, input: I, output: O) -> T
where
    T: Clone
        + Add<Output = T>
        + Sub<Output = T>
        + Mul<Output = T>
        + Div<Output = T>
        + Clamp<Output = T>,
    I: Into<RangeInclusive<T>>,
    O: Into<RangeInclusive<T>>,
{
    let input: RangeInclusive<T> = input.into();
    let output: RangeInclusive<T> = output.into();
    (x.clamp(input.clone()) - input.start.clone()) * (output.end - output.start.clone())
        / (input.end - input.start)
        + output.start
}

pub fn sign<T>(v: T) -> T
where
    T: Zero + One + MinusOne + PartialOrd,
{
    if v >= T::zero() {
        T::one()
    } else {
        T::minus_one()
    }
}