use crate::{
dimension::{CanDimDiv, CanDimInv, CanDimMul, DimType},
Quantity,
units::{
compound::*,
unit_anon::UnitAnon,
unit_rescale::{Rescale, UnitRescale},
},
Value,
};
mod exponential;
pub use exponential::*;
mod step;
pub use step::*;
pub mod transform;
pub use transform::*;
mod unit_binary;
pub use unit_binary::*;
mod unit_unary;
pub use unit_unary::*;
pub trait Unit: Copy + Default + core::fmt::Debug + core::fmt::Display + PartialEq {
type Dim: DimType;
fn scale(&self) -> f64;
fn scale_factor<U: Unit<Dim=Self::Dim>>(self, target: U) -> f64 {
let have = self.scale();
let want = target.scale();
have / want
}
fn scale_factor_v<U: Unit<Dim=Self::Dim>, V: Value>(self, target: U) -> Option<V> {
V::from_f64(self.scale_factor(target))
}
fn base() -> Self { Default::default() }
fn anonymous(&self) -> UnitAnon<Self::Dim> {
UnitAnon::new(self.scale())
}
fn rescale<S: Rescale>(self, factor: S) -> UnitRescale<Self, S> {
UnitRescale::new(self, factor)
}
fn dimension(&self) -> Self::Dim { DimType::dimension() }
fn quantity<V: Value>(self, value: V) -> Quantity<Self, V> {
Quantity::new(self, value)
}
fn one<V: Value>(self) -> Quantity<Self, V> {
self.quantity(num_traits::One::one())
}
fn zero<V: Value>(self) -> Quantity<Self, V> {
self.quantity(num_traits::Zero::zero())
}
fn convert_from<U, V>(self, qty: Quantity<U, V>) -> Quantity<Self, V> where
U: Unit<Dim=Self::Dim>,
V: Value,
{
qty.convert_to(self)
}
fn base_qty<V: Value>(value: V) -> Quantity<Self, V> {
Self::base().quantity(value)
}
fn base_from<U, V>(qty: Quantity<U, V>) -> Quantity<Self, V> where
U: Unit<Dim=Self::Dim>,
V: Value,
{
qty.convert_to(Self::base())
}
#[cfg(feature = "rand")]
fn random<V, R>(self, rng: &mut R) -> Quantity<Self, V> where
rand::distributions::Standard: rand::prelude::Distribution<V>,
R: rand::Rng,
V: Value,
{
self.random_in(rng, rand::distributions::Standard)
}
#[cfg(feature = "rand")]
fn random_in<V, R, D>(self, rng: &mut R, dist: D) -> Quantity<Self, V> where
D: rand::prelude::Distribution<V>,
R: rand::Rng,
V: Value,
{
self.quantity(dist.sample(rng))
}
#[cfg(feature = "simd")]
fn quantity_simd<V, const N: usize, S>(self, values: [V; N])
-> crate::simd::QtySimd<Self, V, N, S> where
core::simd::LaneCount<N>: core::simd::SupportedLaneCount,
V: crate::simd::QtySimdValue,
S: crate::simd::QtySimdScale,
{
crate::simd::QtySimd::from_scales(
values,
[crate::_conv_f64(self.scale()); N],
)
}
}
pub trait UnitMixed: Unit {
fn to_si(&self) -> Self;
fn is_si(&self) -> bool {
self.to_si().eq(self)
}
}
pub trait UnitCompound: Unit {}
pub trait UnitConcrete: Unit + UnitStep {
const BASE: Self;
fn symbol(&self) -> &'static str;
}
pub trait CanUnitInv: Unit {
type DimOut: DimType;
type Output: Unit<Dim=Self::DimOut>;
}
impl<U: Unit> CanUnitInv for U where
U::Dim: CanDimInv,
{
type DimOut = <U::Dim as CanDimInv>::Output;
type Output = PerUnit<U>;
}
pub trait CanUnitDiv<U>: Unit {
type DimOut: DimType;
type Output: Unit<Dim=Self::DimOut>;
}
impl<A: Unit, B: Unit> CanUnitDiv<B> for A where
A::Dim: CanDimDiv<B::Dim>,
{
type DimOut = <A::Dim as CanDimDiv<B::Dim>>::Output;
type Output = UnitDiv<A, B>;
}
pub trait CanUnitMul<U>: Unit {
type DimOut: DimType;
type Output: Unit<Dim=Self::DimOut>;
}
impl<A: Unit, B: Unit> CanUnitMul<B> for A where
A::Dim: CanDimMul<B::Dim>,
{
type DimOut = <A::Dim as CanDimMul<B::Dim>>::Output;
type Output = UnitMul<A, B>;
}