#[macro_export]
macro_rules! quantity {
(
$(#[$quantity_attr:meta])* quantity: $quantity:ident; $description:expr;
$(#[$dim_attr:meta])* dimension: $system:ident<$($dimension:ident),+>;
$(kind: $kind:ty;)?
units {
$($(#[$unit_attr:meta])* @$unit:ident: $($conversion:expr),+; $abbreviation:expr,
$singular:expr, $plural:expr;)+
}
) => {
mod __system {
pub use super::super::*;
}
$(#[$dim_attr])*
pub type Dimension = __system::$system<$($crate::typenum::$dimension),+,
quantity!(@kind $($kind)?)>;
$(#[$quantity_attr])*
pub type $quantity<U, V> = __system::Quantity<Dimension, U, V>;
pub trait Unit: __system::Unit {}
pub trait Conversion<V>: Unit + $crate::Conversion<V, T = <V as $crate::Conversion<V>>::T>
where
V: $crate::Conversion<V>,
{
}
unit! {
@units $($(#[$unit_attr])* @$unit: $($conversion),+;
$abbreviation, $singular, $plural;)+
}
#[allow(dead_code)]
#[inline(always)]
pub fn description() -> &'static str {
$description
}
#[allow(non_camel_case_types)]
#[allow(clippy::manual_non_exhaustive)]
#[derive(Debug, Clone, Copy)]
pub enum Units {
$(#[doc=$plural]
$unit($unit),)+
#[doc(hidden)]
__nonexhaustive,
}
impl Units {
#[allow(dead_code)]
pub fn abbreviation(&self) -> &'static str {
match self {
$(Units::$unit(_) => <$unit as __system::Unit>::abbreviation(),)+
Units::__nonexhaustive => "unknown",
}
}
#[allow(dead_code)]
pub fn singular(&self) -> &'static str {
match self {
$(Units::$unit(_) => <$unit as __system::Unit>::singular(),)+
Units::__nonexhaustive => "unknown",
}
}
#[allow(dead_code)]
pub fn plural(&self) -> &'static str {
match self {
$(Units::$unit(_) => <$unit as __system::Unit>::plural(),)+
Units::__nonexhaustive => "unknown",
}
}
}
static ALL_UNITS: &[Units] = &[
$(Units::$unit($unit),)+
];
#[allow(dead_code)]
pub fn units() -> impl Iterator<Item = Units> {
ALL_UNITS.iter().copied()
}
impl<U, V> $quantity<U, V>
where
U: __system::Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
#[inline(always)]
pub fn new<N>(v: V) -> Self
where
N: Unit + $crate::Conversion<V, T = V::T>,
{
$quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: __system::to_base::<Dimension, U, V, N>(&v),
}
}
#[inline(always)]
pub fn get<N>(&self) -> V
where
N: Unit + $crate::Conversion<V, T = V::T>,
{
__system::from_base::<Dimension, U, V, N>(&self.value)
}
#[inline(always)]
pub fn floor<N>(self) -> Self
where
V: $crate::num::Float,
N: Unit + $crate::Conversion<V, T = V::T>,
{
Self::new::<N>(self.get::<N>().floor())
}
#[inline(always)]
pub fn ceil<N>(self) -> Self
where
V: $crate::num::Float,
N: Unit + $crate::Conversion<V, T = V::T>,
{
Self::new::<N>(self.get::<N>().ceil())
}
#[inline(always)]
pub fn round<N>(self) -> Self
where
V: $crate::num::Float,
N: Unit + $crate::Conversion<V, T = V::T>,
{
Self::new::<N>(self.get::<N>().round())
}
#[inline(always)]
pub fn trunc<N>(self) -> Self
where
V: $crate::num::Float,
N: Unit + $crate::Conversion<V, T = V::T>,
{
Self::new::<N>(self.get::<N>().trunc())
}
#[inline(always)]
pub fn fract<N>(self) -> Self
where
V: $crate::num::Float,
N: Unit + $crate::Conversion<V, T = V::T>,
{
Self::new::<N>(self.get::<N>().fract())
}
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
pub fn format_args<N>(
unit: N,
style: $crate::fmt::DisplayStyle
) -> __system::fmt::Arguments<Dimension, N>
where
N: Unit
{
__system::fmt::Arguments {
dimension: $crate::lib::marker::PhantomData,
unit,
style,
}
}
#[cfg_attr(all(feature = "si", feature = "f32"), doc = " ```rust")]
#[cfg_attr(not(all(feature = "si", feature = "f32")), doc = " ```rust,ignore")]
pub fn into_format_args<N>(
self,
unit: N,
style: $crate::fmt::DisplayStyle
) -> __system::fmt::QuantityArguments<Dimension, U, V, N>
where
N: Unit
{
__system::fmt::QuantityArguments {
arguments: __system::fmt::Arguments {
dimension: $crate::lib::marker::PhantomData,
unit,
style,
},
quantity: self,
}
}
}
impl<N> __system::fmt::Arguments<Dimension, N>
where
N: __system::Unit + Unit,
{
pub fn with<U, V>(
self,
quantity: $quantity<U, V>
) -> __system::fmt::QuantityArguments<Dimension, U, V, N>
where
U: __system::Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
__system::fmt::QuantityArguments {
arguments: self,
quantity,
}
}
}
mod str {
storage_types! {
use $crate::lib::str::FromStr;
use $crate::str::ParseQuantityError::*;
impl<U> FromStr for super::super::$quantity<U, V>
where
U: super::super::__system::Units<V> + ?Sized,
{
type Err = $crate::str::ParseQuantityError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.splitn(2, ' ');
let value = parts.next().unwrap();
let unit = parts.next().ok_or(NoSeparator)?;
let value = value.parse::<V>().map_err(|_| ValueParseError)?;
#[allow(unreachable_patterns)]
match unit.trim() {
$($abbreviation | $singular | $plural => Ok(Self::new::<super::super::$unit>(value)),)+
_ => Err(UnknownUnit),
}
}
}
}
}
};
(@kind $kind:ty) => { $kind };
(@kind) => { dyn $crate::Kind };
}