use std::ops::{Add, AddAssign, Sub};
use bevy::prelude::Deref;
use num_traits::{Signed, Zero};
use rust_decimal::Decimal;
use thiserror::Error;
use crate::instrument::{AsDecimal, InstrumentSpec};
#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DirectionlessVolume<IS: InstrumentSpec>(IS::VolumeType);
impl<IS: InstrumentSpec> DirectionlessVolume<IS> {
pub fn new_unchecked(volume: IS::VolumeType) -> Self {
Self(volume)
}
pub fn new_checked(volume: IS::VolumeType) -> Result<Self, ()> {
if volume.is_negative() || volume.is_zero() {
return Err(());
}
Ok(Self(volume))
}
}
impl<IS: InstrumentSpec> Add for DirectionlessVolume<IS> {
type Output = Self;
fn add(
self,
rhs: Self,
) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<IS: InstrumentSpec> Add for &DirectionlessVolume<IS> {
type Output = DirectionlessVolume<IS>;
fn add(
self,
rhs: Self,
) -> Self::Output {
DirectionlessVolume::<IS>(self.0 + rhs.0)
}
}
impl<IS: InstrumentSpec> AddAssign for DirectionlessVolume<IS> {
fn add_assign(
&mut self,
rhs: Self,
) {
self.0 += rhs.0;
}
}
#[derive(Debug, Error)]
pub enum DirectionlessVolumeSubError {
#[error("Can not have negative directionless volume. Attemped to subtract: {lhs} - {rhs}.")]
NegativeVolume { lhs: Decimal, rhs: Decimal },
}
impl<IS: InstrumentSpec> Sub for DirectionlessVolume<IS> {
type Output = Result<Option<Self>, DirectionlessVolumeSubError>;
fn sub(
self,
rhs: Self,
) -> Self::Output {
if self.0 == rhs.0 {
return Ok(None);
}
if self.0 < rhs.0 {
return Err(
DirectionlessVolumeSubError::NegativeVolume {
lhs: self.as_decimal(),
rhs: rhs.as_decimal(),
},
);
}
Ok(Some(Self(self.0 - rhs.0)))
}
}