use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::Sum;
use std::ops::{Add, Div, Mul, Sub};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::UnitOfMeasure;
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct Measurement<T, U>
where
U: UnitOfMeasure<T>,
{
pub(super) value: T,
pub(super) unit: U,
}
impl<U> Hash for Measurement<f32, U>
where
U: UnitOfMeasure<f32> + Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.value.to_bits().hash(state);
self.unit.hash(state);
}
}
impl<T, U> Measurement<T, U>
where
U: UnitOfMeasure<T>,
{
pub fn new(value: T, unit: U) -> Self {
Self { value, unit }
}
pub fn value(&self) -> &T {
&self.value
}
pub fn unit(&self) -> &U {
&self.unit
}
pub fn symbol(&self) -> &str {
self.unit.symbol()
}
pub fn from_si(value: T, unit: U) -> Self {
Self {
value: U::from_si(value, &unit),
unit,
}
}
pub fn to_si(&self) -> T {
self.unit.to_si(&self.value)
}
pub fn convert_to(&self, other: U) -> Self {
Self {
value: self.unit.convert_to(&self.value, &other),
unit: other,
}
}
}
macro_rules! abs_impl {
($($t:ty)*) => ($(
impl<U> Measurement<$t, U>
where
U: UnitOfMeasure<$t> + Copy,
{
pub fn abs(&self) -> Self {
Self {
value: self.value.abs(),
unit: self.unit,
}
}
}
)*)
}
abs_impl! { f32 f64 i8 i16 i32 i64 }
impl<T, U> Default for Measurement<T, U>
where
T: Default,
U: UnitOfMeasure<T>,
{
fn default() -> Self {
Self::new(T::default(), U::si())
}
}
impl<T, U> fmt::Display for Measurement<T, U>
where
T: std::fmt::Display,
U: UnitOfMeasure<T>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let tmp = if let Some(precision) = f.precision() {
format!("{:.precision$} {}", self.value, self.symbol())
} else {
format!("{} {}", self.value, self.symbol())
};
f.pad_integral(true, "", &tmp)
}
}
impl<T, U> PartialOrd for Measurement<T, U>
where
T: PartialOrd,
U: UnitOfMeasure<T>,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.to_si().partial_cmp(&other.to_si())
}
}
impl<T, U> Ord for Measurement<T, U>
where
T: Ord,
U: UnitOfMeasure<T>,
{
fn cmp(&self, other: &Self) -> Ordering {
self.to_si().cmp(&other.to_si())
}
}
impl<T, U> PartialEq for Measurement<T, U>
where
T: PartialEq,
U: UnitOfMeasure<T>,
{
fn eq(&self, other: &Self) -> bool {
self.to_si() == other.to_si()
}
}
impl<T, U> Eq for Measurement<T, U>
where
T: PartialEq,
U: UnitOfMeasure<T>,
{
}
impl<T, U> Add for Measurement<T, U>
where
T: Add<Output = T>,
U: UnitOfMeasure<T>,
{
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::from_si(self.to_si() + rhs.to_si(), self.unit)
}
}
impl<T, U> Sub for Measurement<T, U>
where
T: Sub<Output = T>,
U: UnitOfMeasure<T>,
{
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::from_si(self.to_si() - rhs.to_si(), self.unit)
}
}
impl<T, U> Mul for Measurement<T, U>
where
T: Mul<Output = T>,
U: UnitOfMeasure<T>,
{
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::from_si(self.to_si() * rhs.to_si(), self.unit)
}
}
impl<T, U> Mul<T> for Measurement<T, U>
where
T: Mul<Output = T>,
U: UnitOfMeasure<T>,
{
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
Self::from_si(self.to_si() * rhs, self.unit)
}
}
impl<T, U> Div for Measurement<T, U>
where
T: Div<Output = T>,
U: UnitOfMeasure<T>,
{
type Output = T;
fn div(self, rhs: Self) -> Self::Output {
self.to_si() / rhs.to_si()
}
}
impl<T, U> Div<T> for Measurement<T, U>
where
T: Div<Output = T>,
U: UnitOfMeasure<T>,
{
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
Self::from_si(self.to_si() / rhs, self.unit)
}
}
impl<T, U> Sum for Measurement<T, U>
where
T: Default + Add<Output = T>,
U: UnitOfMeasure<T>,
{
fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
match iter.next() {
Some(first) => iter.fold(first, |acc, x| acc + x),
None => Self::default(),
}
}
}
impl<T, U> From<Measurement<T, U>> for f32
where
T: Into<f32>,
U: UnitOfMeasure<T>,
{
fn from(value: Measurement<T, U>) -> Self {
value.to_si().into()
}
}