#![deny(
rust_2018_idioms,
warnings,
clippy::pedantic,
missing_docs,
missing_debug_implementations,
broken_intra_doc_links,
unsafe_code
)]
#![allow(incomplete_features)]
#![feature(const_generics, const_evaluatable_checked)]
use std::{fmt, ops};
mod si;
pub use si::{units, values};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[allow(non_snake_case)]
pub struct Unit {
pub(crate) m: i8,
pub(crate) kg: i8,
pub(crate) s: i8,
pub(crate) A: i8,
pub(crate) K: i8,
pub(crate) mol: i8,
pub(crate) cd: i8,
}
impl Unit {
pub const fn inv(self) -> Self {
Self {
m: -self.m,
kg: -self.kg,
s: -self.s,
A: -self.A,
K: -self.K,
mol: -self.mol,
cd: -self.cd,
}
}
pub const fn mul(self, rhs: Self) -> Self {
Self {
m: self.m + rhs.m,
kg: self.kg + rhs.kg,
s: self.s + rhs.s,
A: self.A + rhs.A,
K: self.K + rhs.K,
mol: self.mol + rhs.mol,
cd: self.cd + rhs.cd,
}
}
pub const fn div(self, rhs: Self) -> Self {
Self {
m: self.m - rhs.m,
kg: self.kg - rhs.kg,
s: self.s - rhs.s,
A: self.A - rhs.A,
K: self.K - rhs.K,
mol: self.mol - rhs.mol,
cd: self.cd - rhs.cd,
}
}
}
impl fmt::Display for Unit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let units = [
("m", self.m),
("kg", self.kg),
("s", self.s),
("A", self.A),
("K", self.K),
("mol", self.mol),
("cd", self.cd),
];
let units = units.iter().filter(|unit| unit.1 != 0);
let len = units.clone().count();
for (idx, (name, unit)) in units.enumerate() {
if *unit == 1 {
write!(f, "{}", name)?;
} else {
write!(f, "{}^{}", name, unit)?;
}
if idx + 1 != len {
write!(f, " * ")?;
}
}
Ok(())
}
}
impl ops::Mul<Unit> for Unit {
type Output = Self;
fn mul(self, rhs: Unit) -> Self::Output {
self.mul(rhs)
}
}
impl ops::Div<Unit> for Unit {
type Output = Self;
fn div(self, rhs: Unit) -> Self::Output {
self.div(rhs)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(transparent)]
pub struct Quantity<const U: Unit> {
pub value: f64,
}
macro_rules! quantity_impl {
($num:ty, $t:ident) => {
impl<const U: Unit> $t<U> {
pub const fn new(value: $num) -> Self {
Self { value }
}
}
impl<const U: Unit> ::std::fmt::Display for $t<U> {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{} * {}", self.value, U)
}
}
impl<const U: Unit> ::std::ops::Add<$t<U>> for $t<U> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
value: self.value + rhs.value,
}
}
}
impl<const U: Unit> ::std::ops::AddAssign<$t<U>> for $t<U> {
fn add_assign(&mut self, rhs: Self) {
self.value += rhs.value;
}
}
impl<const U: Unit> ::std::ops::Sub<$t<U>> for $t<U> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
value: self.value - rhs.value,
}
}
}
impl<const U: Unit> ::std::ops::SubAssign<$t<U>> for $t<U> {
fn sub_assign(&mut self, rhs: Self) {
self.value -= rhs.value;
}
}
impl<const U: Unit> ::std::ops::Mul<$num> for $t<U> {
type Output = Self;
fn mul(self, rhs: $num) -> Self::Output {
Self {
value: self.value * rhs,
}
}
}
impl<const U: Unit> ::std::ops::Mul<$t<U>> for $num {
type Output = $t<U>;
fn mul(self, rhs: $t<U>) -> Self::Output {
$t {
value: self * rhs.value,
}
}
}
impl<const L: Unit, const R: Unit> ::std::ops::Mul<$t<R>> for $t<L>
where
$t<{ L.mul(R) }>: ,
{
type Output = $t<{ L.mul(R) }>;
fn mul(self, rhs: $t<R>) -> Self::Output {
$t {
value: self.value * rhs.value,
}
}
}
impl<const U: Unit> ::std::ops::MulAssign<$num> for $t<U> {
fn mul_assign(&mut self, rhs: $num) {
self.value *= rhs;
}
}
impl<const U: Unit> ::std::ops::Div<$num> for $t<U> {
type Output = Self;
fn div(self, rhs: $num) -> Self::Output {
Self {
value: self.value / rhs,
}
}
}
impl<const L: Unit, const R: Unit> ::std::ops::Div<$t<R>> for $t<L>
where
$t<{ L.div(R) }>: ,
{
type Output = $t<{ L.div(R) }>;
fn div(self, rhs: $t<R>) -> Self::Output {
$t {
value: self.value / rhs.value,
}
}
}
impl<const U: Unit> ::std::ops::Div<$t<U>> for $num
where
$t<{ U.inv() }>: ,
{
type Output = $t<{ U.inv() }>;
fn div(self, rhs: $t<U>) -> Self::Output {
$t {
value: self / rhs.value,
}
}
}
impl<const U: Unit> ::std::ops::DivAssign<$num> for $t<U> {
fn div_assign(&mut self, rhs: $num) {
self.value /= rhs;
}
}
};
}
quantity_impl!(f64, Quantity);