#[macro_export]
macro_rules! system {
(
$(#[$quantities_attr:meta])* quantities: $quantities:ident {
$($(#[$name_attr:meta])* $name:ident: $unit:ident, $symbol:ident;)+
}
$(#[$units_attr:meta])* units: $units:ident {
$($module:ident::$quantity:ident,)+
}
) => {
$(#[macro_use]
pub mod $module;)+
system! {
$(#[$quantities_attr])*
quantities: $quantities {
$($(#[$name_attr])* $name: $unit, $symbol;)+
}
$(#[$units_attr])*
units: $units {
$(mod $module::$quantity,)+
}
}
};
(
$(#[$quantities_attr:meta])* quantities: $quantities:ident {
$($(#[$name_attr:meta])* $name:ident: $unit:ident, $symbol:ident;)+
}
$(#[$units_attr:meta])* units: $units:ident {
$(mod $module:ident::$quantity:ident,)+
}
) => {
pub trait Dimension:
Send
+ Sync
+ Unpin
+ $crate::lib::panic::RefUnwindSafe
+ $crate::lib::panic::UnwindSafe
{
$($(#[$name_attr])*
type $symbol: $crate::typenum::Integer;)+
type Kind: ?Sized;
}
pub trait Units<V>:
Send
+ Sync
+ Unpin
+ $crate::lib::panic::RefUnwindSafe
+ $crate::lib::panic::UnwindSafe
where
V: $crate::Conversion<V>,
{
$($(#[$name_attr])*
#[allow(non_camel_case_types)]
type $name: Unit + $crate::Conversion<V, T = V::T>;)+
}
pub trait Unit: Copy {
fn abbreviation() -> &'static str;
fn singular() -> &'static str;
fn plural() -> &'static str;
}
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust,compile_fail")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust,compile_fail")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust,compile_fail")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[repr(transparent)]
pub struct Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
pub dimension: $crate::lib::marker::PhantomData<D>,
pub units: $crate::lib::marker::PhantomData<U>,
pub value: V,
}
type DN<N> = dyn Dimension<$($symbol = system!(@replace $symbol N),)+
Kind = dyn $crate::Kind>;
#[allow(dead_code)]
pub type DimensionOne = DN<$crate::typenum::Z0>;
$(#[$quantities_attr])*
pub type $quantities<$($symbol,)+ K = dyn $crate::Kind> =
dyn Dimension<$($symbol = $symbol,)+ Kind = K>;
$(#[$units_attr])*
#[allow(unused_qualifications)]
pub type $units<V> = dyn Units<V, $($name = $name::$unit),+>;
#[inline(always)]
fn from_base<D, U, V, N>(v: &V) -> V
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::Conversion<V> + $crate::lib::ops::Mul<V, Output = V>,
N: $crate::Conversion<V, T = V::T>,
{
use $crate::typenum::Integer;
use $crate::Conversion;
use $crate::ConversionFactor;
(v.into_conversion() $(* U::$name::coefficient().powi(D::$symbol::to_i32()))+
/ N::coefficient() - N::constant($crate::ConstantOp::Sub))
.value()
}
#[inline(always)]
fn to_base<D, U, V, N>(v: &V) -> V
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::Conversion<V> + $crate::lib::ops::Mul<V, Output = V>,
N: $crate::Conversion<V, T = V::T>,
{
use $crate::typenum::Integer;
use $crate::Conversion;
use $crate::ConversionFactor;
((v.into_conversion() + N::constant($crate::ConstantOp::Add)) * N::coefficient()
/ (V::coefficient() $(* U::$name::coefficient().powi(D::$symbol::to_i32()))+))
.value()
}
autoconvert_test! {
#[allow(dead_code)]
#[inline(always)]
fn change_base<D, Ul, Ur, V>(v: &V) -> V
where
D: Dimension + ?Sized,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::Conversion<V> + $crate::lib::ops::Mul<V, Output = V>,
{
use $crate::typenum::Integer;
use $crate::Conversion;
use $crate::ConversionFactor;
(v.into_conversion() $(* Ur::$name::coefficient().powi(D::$symbol::to_i32())
/ Ul::$name::coefficient().powi(D::$symbol::to_i32()))+)
.value()
}}
#[doc(hidden)]
macro_rules! impl_ops {
(
$AddSubTrait:ident, $addsub_fun:ident, $addsub_op:tt,
$AddSubAssignTrait:ident, $addsubassign_fun:ident, $addsubassign_op:tt,
$AddSubAlias:ident,
$MulDivTrait:ident, $muldiv_fun:ident, $muldiv_op:tt,
$MulDivAssignTrait:ident, $muldivassign_fun:ident, $muldivassign_op:tt,
$Mod:ident
) => {
autoconvert! {
impl<D, Ul, Ur, V> $crate::lib::ops::$AddSubTrait<Quantity<D, Ur, V>>
for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubTrait,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = Quantity<D, Ul, V>;
#[inline(always)]
fn $addsub_fun(self, rhs: Quantity<D, Ur, V>) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value $addsub_op change_base::<D, Ul, Ur, V>(&rhs.value),
}
}
}}
not_autoconvert! {
impl<D, U, V> $crate::lib::ops::$AddSubTrait for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = Self;
#[inline(always)]
fn $addsub_fun(self, rhs: Self) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value $addsub_op rhs.value,
}
}
}}
autoconvert! {
impl<D, Ul, Ur, V> $crate::lib::ops::$AddSubAssignTrait<Quantity<D, Ur, V>>
for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubAssignTrait,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>
+ $crate::lib::ops::$AddSubAssignTrait<V>,
{
#[inline(always)]
fn $addsubassign_fun(&mut self, rhs: Quantity<D, Ur, V>) {
self.value $addsubassign_op change_base::<D, Ul, Ur, V>(&rhs.value);
}
}}
not_autoconvert! {
impl<D, U, V> $crate::lib::ops::$AddSubAssignTrait for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubAssignTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>
+ $crate::lib::ops::$AddSubAssignTrait<V>,
{
#[inline(always)]
fn $addsubassign_fun(&mut self, rhs: Self) {
self.value $addsubassign_op rhs.value;
}
}}
autoconvert! {
impl<Dl, Dr, Ul, Ur, V> $crate::lib::ops::$MulDivTrait<Quantity<Dr, Ur, V>>
for Quantity<Dl, Ul, V>
where
Dl: Dimension + ?Sized,
$(Dl::$symbol: $crate::lib::ops::$AddSubTrait<Dr::$symbol>,
<Dl::$symbol as $crate::lib::ops::$AddSubTrait<Dr::$symbol>>::Output: $crate::typenum::Integer,)+
Dl::Kind: $crate::marker::$MulDivTrait,
Dr: Dimension + ?Sized,
Dr::Kind: $crate::marker::$MulDivTrait,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::$MulDivTrait<V>,
{
type Output = Quantity<
$quantities<$($crate::typenum::$AddSubAlias<Dl::$symbol, Dr::$symbol>,)+>,
Ul, V>;
#[inline(always)]
fn $muldiv_fun(self, rhs: Quantity<Dr, Ur, V>) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value $muldiv_op change_base::<Dr, Ul, Ur, V>(&rhs.value),
}
}
}}
not_autoconvert! {
impl<Dl, Dr, U, V> $crate::lib::ops::$MulDivTrait<Quantity<Dr, U, V>>
for Quantity<Dl, U, V>
where
Dl: Dimension + ?Sized,
$(Dl::$symbol: $crate::lib::ops::$AddSubTrait<Dr::$symbol>,
<Dl::$symbol as $crate::lib::ops::$AddSubTrait<Dr::$symbol>>::Output: $crate::typenum::Integer,)+
Dl::Kind: $crate::marker::$MulDivTrait,
Dr: Dimension + ?Sized,
Dr::Kind: $crate::marker::$MulDivTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::$MulDivTrait<V>,
{
type Output = Quantity<
$quantities<$($crate::typenum::$AddSubAlias<Dl::$symbol, Dr::$symbol>,)+>,
U, V>;
#[inline(always)]
fn $muldiv_fun(self, rhs: Quantity<Dr, U, V>) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value $muldiv_op rhs.value,
}
}
}}
impl<D, U, V> $crate::lib::ops::$MulDivTrait<V> for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$MulDivTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = Quantity<D, U, V>;
#[inline(always)]
fn $muldiv_fun(self, rhs: V) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value $muldiv_op rhs,
}
}
}
impl<D, U, V> $crate::lib::ops::$MulDivAssignTrait<V> for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$MulDivAssignTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>
+ $crate::lib::ops::$MulDivAssignTrait<V>,
{
#[inline(always)]
fn $muldivassign_fun(&mut self, rhs: V) {
self.value $muldivassign_op rhs;
}
}
#[doc(hidden)]
mod $Mod {
storage_types! {
use super::super::*;
impl<D, U> $crate::lib::ops::$MulDivTrait<Quantity<D, U, V>> for V
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$MulDivTrait,
U: Units<V> + ?Sized,
$($crate::typenum::Z0: $crate::lib::ops::$AddSubTrait<D::$symbol>,
<$crate::typenum::Z0 as $crate::lib::ops::$AddSubTrait<D::$symbol>>::Output: $crate::typenum::Integer,)+
{
type Output = Quantity<
$quantities<
$($crate::typenum::$AddSubAlias<
$crate::typenum::Z0,
D::$symbol>,)+
D::Kind>,
U, V>;
#[inline(always)]
fn $muldiv_fun(self, rhs: Quantity<D, U, V>) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self $muldiv_op rhs.value,
}
}
}
}
}
};
}
impl_ops!(Add, add, +, AddAssign, add_assign, +=, Sum,
Mul, mul, *, MulAssign, mul_assign, *=, add_mul);
impl_ops!(Sub, sub, -, SubAssign, sub_assign, -=, Diff,
Div, div, /, DivAssign, div_assign, /=, sub_div);
impl<D, U, V> Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline(always)]
pub fn is_nan(self) -> bool
where
V: $crate::num::Float,
{
self.value.is_nan()
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline(always)]
pub fn is_infinite(self) -> bool
where
V: $crate::num::Float,
{
self.value.is_infinite()
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline(always)]
pub fn is_finite(self) -> bool
where
V: $crate::num::Float,
{
self.value.is_finite()
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline(always)]
pub fn is_normal(self) -> bool
where
V: $crate::num::Float,
{
self.value.is_normal()
}
#[inline(always)]
pub fn classify(self) -> $crate::lib::num::FpCategory
where
V: $crate::num::Float,
{
self.value.classify()
}
std! {
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust,compile_fail")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[inline(always)]
pub fn cbrt(
self
) -> Quantity<
$quantities<$($crate::typenum::PartialQuot<D::$symbol, $crate::typenum::P3>),+>,
U, V>
where
$(D::$symbol: $crate::lib::ops::PartialDiv<$crate::typenum::P3>,
<D::$symbol as $crate::lib::ops::PartialDiv<$crate::typenum::P3>>::Output: $crate::typenum::Integer,)+
D::Kind: $crate::marker::Div,
V: $crate::num::Float,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.cbrt(),
}
}
autoconvert! {
#[inline(always)]
pub fn hypot<Ur>(self, other: Quantity<D, Ur, V>) -> Self
where
V: $crate::num::Float,
Ur: Units<V> + ?Sized,
{
Self {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.hypot(change_base::<D, U, Ur, V>(&other.value)),
}
}}
not_autoconvert! {
#[inline(always)]
pub fn hypot(self, other: Self) -> Self
where
V: $crate::num::Float,
{
Self {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.hypot(other.value),
}
}}}
#[inline(always)]
pub fn abs(self) -> Self
where
V: $crate::num::Signed,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.abs(),
}
}
#[inline(always)]
pub fn signum(self) -> Self
where
V: $crate::num::Signed,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.signum(),
}
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline(always)]
pub fn is_sign_positive(self) -> bool
where
V: $crate::num::Float,
{
self.value.is_sign_positive()
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
#[inline(always)]
pub fn is_sign_negative(self) -> bool
where
V: $crate::num::Float,
{
self.value.is_sign_negative()
}
std! {
#[inline(always)]
pub fn mul_add<Da, Ua, Ub>(
self,
a: Quantity<Da, Ua, V>,
b: Quantity<$quantities<$($crate::typenum::Sum<D::$symbol, Da::$symbol>),+>, Ub, V>,
) -> Quantity<$quantities<$($crate::typenum::Sum<D::$symbol, Da::$symbol>),+>, U, V>
where
$(D::$symbol: $crate::lib::ops::Add<Da::$symbol>,
<D::$symbol as $crate::lib::ops::Add<Da::$symbol>>::Output: $crate::typenum::Integer,)+
D::Kind: $crate::marker::Mul,
V: $crate::num::Float,
Da: Dimension + ?Sized,
Da::Kind: $crate::marker::Mul,
Ua: Units<V> + ?Sized,
Ub: Units<V> + ?Sized,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.mul_add(a.value, b.value),
}
}}
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[inline(always)]
pub fn recip(
self
) -> Quantity<$quantities<$($crate::typenum::Negate<D::$symbol>),+>, U, V>
where
$(D::$symbol: $crate::lib::ops::Neg,
<D::$symbol as $crate::lib::ops::Neg>::Output: $crate::typenum::Integer,)+
D::Kind: $crate::marker::Div,
V: $crate::num::Float,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.recip(),
}
}
std! {
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[inline(always)]
pub fn powi<E>(
self, _e: E
) -> Quantity<$quantities<$($crate::typenum::Prod<D::$symbol, E>),+>, U, V>
where
$(D::$symbol: $crate::lib::ops::Mul<E>,
<D::$symbol as $crate::lib::ops::Mul<E>>::Output: $crate::typenum::Integer,)+
D::Kind: $crate::marker::Mul,
E: $crate::typenum::Integer,
V: $crate::num::Float,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.powi(E::to_i32()),
}
}
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust,compile_fail")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[inline(always)]
pub fn sqrt(
self
) -> Quantity<
$quantities<$($crate::typenum::PartialQuot<D::$symbol, $crate::typenum::P2>),+>,
U, V>
where
$(D::$symbol: $crate::typenum::PartialDiv<$crate::typenum::P2>,
<D::$symbol as $crate::typenum::PartialDiv<$crate::typenum::P2>>::Output: $crate::typenum::Integer,)+
D::Kind: $crate::marker::Div,
V: $crate::num::Float,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.sqrt(),
}
}}
#[inline(always)]
pub fn max(self, other: Self) -> Self
where
V: $crate::num::Float,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.max(other.value),
}
}
#[inline(always)]
pub fn min(self, other: Self) -> Self
where
V: $crate::num::Float,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.min(other.value),
}
}
}
impl<D, U, V> $crate::lib::clone::Clone for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::clone::Clone,
{
#[inline(always)]
fn clone(&self) -> Self {
match *self {
Quantity { ref value, .. } => {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: $crate::lib::clone::Clone::clone(&(*value)),
}
}
}
}
}
impl<D, U, V> $crate::lib::marker::Copy for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::marker::Copy,
{
}
#[allow(non_camel_case_types)]
impl<D, U, V> $crate::lib::fmt::Debug for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::fmt::Debug,
{
fn fmt<'a>(&self, f: &mut $crate::lib::fmt::Formatter<'a>) -> $crate::lib::fmt::Result {
self.value.fmt(f)
$(.and_then(|_| {
let d = <D::$symbol as $crate::typenum::Integer>::to_i32();
if 0 != d {
write!(f, " {}^{}", U::$name::abbreviation(), d)
}
else {
Ok(())
}
}))+
}
}
impl<D, U, V> $crate::lib::default::Default for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::default::Default,
{
fn default() -> Self {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: V::default(),
}
}
}
impl<D, U, V> $crate::lib::cmp::Eq for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::cmp::Eq,
{
}
impl<D, U, V> $crate::lib::hash::Hash for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::hash::Hash,
{
fn hash<H: $crate::lib::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl<D, U, V> $crate::lib::ops::Neg for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Neg,
U: Units<V> + ?Sized,
V: $crate::num::Signed + $crate::Conversion<V>,
{
type Output = Quantity<D, U, V>;
#[inline(always)]
fn neg(self) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: -self.value,
}
}
}
impl<D, U, V> $crate::lib::cmp::Ord for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::cmp::Ord,
{
#[inline(always)]
fn cmp(&self, other: &Self) -> $crate::lib::cmp::Ordering {
self.value.cmp(&other.value)
}
#[inline(always)]
fn max(self, other: Self) -> Self {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.max(other.value),
}
}
#[inline(always)]
fn min(self, other: Self) -> Self {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value.min(other.value),
}
}
}
autoconvert! {
impl<D, Ul, Ur, V> $crate::lib::cmp::PartialEq<Quantity<D, Ur, V>> for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
#[inline(always)]
fn eq(&self, other: &Quantity<D, Ur, V>) -> bool {
self.value == change_base::<D, Ul, Ur, V>(&other.value)
}
}}
not_autoconvert! {
impl<D, U, V> $crate::lib::cmp::PartialEq for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}}
autoconvert! {
impl<D, Ul, Ur, V> $crate::lib::cmp::PartialOrd<Quantity<D, Ur, V>> for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::cmp::PartialOrd,
{
#[inline(always)]
fn partial_cmp(
&self, other: &Quantity<D, Ur, V>
) -> Option<$crate::lib::cmp::Ordering>
{
self.value.partial_cmp(&change_base::<D, Ul, Ur, V>(&other.value))
}
#[inline(always)]
fn lt(&self, other: &Quantity<D, Ur, V>) -> bool {
self.value.lt(&change_base::<D, Ul, Ur, V>(&other.value))
}
#[inline(always)]
fn le(&self, other: &Quantity<D, Ur, V>) -> bool {
self.value.le(&change_base::<D, Ul, Ur, V>(&other.value))
}
#[inline(always)]
fn gt(&self, other: &Quantity<D, Ur, V>) -> bool {
self.value.gt(&change_base::<D, Ul, Ur, V>(&other.value))
}
#[inline(always)]
fn ge(&self, other: &Quantity<D, Ur, V>) -> bool {
self.value.ge(&change_base::<D, Ul, Ur, V>(&other.value))
}
}}
not_autoconvert! {
impl<D, U, V> $crate::lib::cmp::PartialOrd for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::cmp::PartialOrd,
{
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<$crate::lib::cmp::Ordering> {
self.value.partial_cmp(&other.value)
}
#[inline(always)]
fn lt(&self, other: &Self) -> bool {
self.value.lt(&other.value)
}
#[inline(always)]
fn le(&self, other: &Self) -> bool {
self.value.le(&other.value)
}
#[inline(always)]
fn gt(&self, other: &Self) -> bool {
self.value.gt(&other.value)
}
#[inline(always)]
fn ge(&self, other: &Self) -> bool {
self.value.ge(&other.value)
}
}}
autoconvert! {
impl<D, Ul, Ur, V> $crate::lib::ops::Rem<Quantity<D, Ur, V>> for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Rem,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = Quantity<D, Ul, V>;
#[inline(always)]
fn rem(self, rhs: Quantity<D, Ur, V>) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value % change_base::<D, Ul, Ur, V>(&rhs.value)
}
}
}}
not_autoconvert! {
impl<D, U, V> $crate::lib::ops::Rem for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Rem,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = Self;
#[inline(always)]
fn rem(self, rhs: Self) -> Self::Output {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value % rhs.value
}
}
}}
autoconvert! {
impl<D, Ul, Ur, V> $crate::lib::ops::RemAssign<Quantity<D, Ur, V>> for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::RemAssign,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::RemAssign,
{
#[inline(always)]
fn rem_assign(&mut self, rhs: Quantity<D, Ur, V>) {
self.value %= change_base::<D, Ul, Ur, V>(&rhs.value)
}
}}
not_autoconvert! {
impl<D, U, V> $crate::lib::ops::RemAssign for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::RemAssign,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::RemAssign,
{
#[inline(always)]
fn rem_assign(&mut self, rhs: Self) {
self.value %= rhs.value
}
}}
impl<D, U, V> $crate::num::Saturating for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Saturating,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::num::Saturating,
{
fn saturating_add(self, v: Self) -> Self {
Quantity { value: self.value.saturating_add(v.value), ..self }
}
fn saturating_sub(self, v: Self) -> Self {
Quantity { value: self.value.saturating_sub(v.value), ..self }
}
}
impl<D, U, V> $crate::lib::iter::Sum for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Add,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::iter::Sum,
{
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = Self>,
{
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: iter.map(|v| { v.value }).sum(),
}
}
}
test! {
impl<D, U, V> $crate::tests::Test for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::tests::Test,
{
fn assert_eq(lhs: &Self, rhs: &Self) {
$crate::tests::Test::assert_eq(&lhs.value, &rhs.value);
}
fn assert_approx_eq(lhs: &Self, rhs: &Self) {
$crate::tests::Test::assert_approx_eq(&lhs.value, &rhs.value);
}
fn eq(lhs: &Self, rhs: &Self) -> bool {
$crate::tests::Test::eq(&lhs.value, &rhs.value)
}
fn approx_eq(lhs: &Self, rhs: &Self) -> bool {
$crate::tests::Test::approx_eq(&lhs.value, &rhs.value)
}
}}
impl<D, U, V> $crate::num::Zero for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Add,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
fn zero() -> Self {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: V::zero(),
}
}
fn is_zero(&self) -> bool {
self.value.is_zero()
}
}
serde! {
impl<D, U, V> $crate::serde::Serialize for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: $crate::serde::Serializer
{
self.value.serialize(serializer)
}
}
impl<'de, D, U, V> $crate::serde::Deserialize<'de> for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::serde::Deserialize<'de>,
{
fn deserialize<De>(deserializer: De) -> Result<Self, De::Error>
where
De: $crate::serde::Deserializer<'de>,
{
let value: V = $crate::serde::Deserialize::deserialize(deserializer)?;
Ok(Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value,
})
}
}}
pub mod fmt {
use $crate::lib::fmt;
use super::{Dimension, Quantity, Unit, Units, from_base};
use $crate::num::Num;
use $crate::Conversion;
use $crate::fmt::DisplayStyle;
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
#[allow(missing_debug_implementations)]
pub struct Arguments<D, N>
where
D: Dimension + ?Sized,
N: Unit,
{
pub(super) dimension: $crate::lib::marker::PhantomData<D>,
pub(super) unit: N,
pub(super) style: DisplayStyle,
}
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
pub struct QuantityArguments<D, U, V, N>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: Num + Conversion<V>,
N: Unit,
{
pub(super) arguments: Arguments<D, N>,
pub(super) quantity: Quantity<D, U, V>,
}
impl<D, N> $crate::lib::clone::Clone for Arguments<D, N>
where
D: Dimension + ?Sized,
N: Unit,
{
fn clone(&self) -> Self {
Self {
dimension: $crate::lib::marker::PhantomData,
unit: self.unit.clone(),
style: self.style.clone(),
}
}
}
impl<D, N> $crate::lib::marker::Copy for Arguments<D, N>
where
D: Dimension + ?Sized,
N: Unit,
{
}
impl<D, U, V, N> $crate::lib::clone::Clone for QuantityArguments<D, U, V, N>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::clone::Clone,
N: Unit,
{
fn clone(&self) -> Self {
Self {
arguments: self.arguments.clone(),
quantity: self.quantity.clone(),
}
}
}
impl<D, U, V, N> $crate::lib::marker::Copy for QuantityArguments<D, U, V, N>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::marker::Copy,
N: Unit,
{
}
macro_rules! format_arguments {
($style:ident) => {
impl<D, U, V, N> fmt::$style for QuantityArguments<D, U, V, N>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: Num + Conversion<V> + fmt::$style,
N: Unit + Conversion<V, T = V::T>,
{
fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result {
let value = from_base::<D, U, V, N>(&self.quantity.value);
value.fmt(f)?;
write!(f, " {}",
match self.arguments.style {
DisplayStyle::Abbreviation => N::abbreviation(),
DisplayStyle::Description => {
if value.is_one() { N::singular() } else { N::plural() }
},
})
}
}
};
}
format_arguments!(Binary);
format_arguments!(Debug);
format_arguments!(Display);
format_arguments!(LowerExp);
format_arguments!(LowerHex);
format_arguments!(Octal);
format_arguments!(UpperExp);
format_arguments!(UpperHex);
}
#[macro_export]
macro_rules! $quantities {
($path:path) => {
use $path as __system;
$(
#[allow(dead_code)]
#[allow(unused_qualifications)]
pub type $quantity<V> = __system::$module::$quantity<__system::$units<V>, V>;)+
};
($path:path, $V:ty) => {
use $path as __system;
$(
#[allow(dead_code)]
#[allow(unused_qualifications)]
pub type $quantity = __system::$module::$quantity<__system::$units<$V>, $V>;)+
};
($path:path, $V:ty, $U:tt) => {
system!(@quantities $path, $V; $($name),+; $U; $($module::$quantity),+);
};
}
};
(
@quantities $path:path,
$V:ty;
$($name:ident),+;
($($U:ident),+);
$($module:ident::$quantity:ident),+
) => {
use $path as __system;
type Units = dyn __system::Units<$V, $($name = __system::$name::$U,)+>;
$(
#[allow(dead_code)]
#[allow(unused_qualifications)]
pub type $quantity = __system::$module::$quantity<Units, $V>;)+
};
(@replace $_t:tt $sub:ty) => { $sub };
}