use crate::dimension::*;
use crate::*;
use crate::complex::c64;
use crate::tensor::element::*;
#[derive(Clone, Copy)]
pub struct UnitParameters {
pub(crate) scale: f64,
pub(crate) offset: f64,
pub(crate) symbol: &'static str,
pub(crate) name: &'static str,
}
pub trait Unit {
type Dimension;
fn parameters() -> UnitParameters;
fn to<S: Unit<Dimension = Self::Dimension>, E: TensorElement>(value: E) -> E
{
let base = Self::to_base(value.into());
S::from_base(base).into()
}
fn from<S: Unit<Dimension = Self::Dimension>, E: TensorElement>(value: E) -> E
{
let base = S::to_base(value.into());
Self::from_base(base).into()
}
fn to_base(value: c64) -> c64
{
let params = Self::parameters();
c64::from(( ((value.a * params.scale) + params.offset) as f64, ((value.b * params.scale) + params.offset) as f64))
}
fn from_base(value: c64) -> c64
{
let params = Self::parameters();
c64::from(( ((value.a / params.scale) - params.offset) as f64, ((value.b / params.scale) - params.offset) as f64))
}
fn symbol() -> &'static str {
Self::parameters().symbol
}
fn name() -> &'static str {
Self::parameters().name
}
fn ratio<T: Unit<Dimension = Self::Dimension>>() -> f64 {
let self_params = Self::parameters();
let other_params = T::parameters();
self_params.scale / other_params.scale
}
}
pub struct Unitless;
impl Unit for Unitless {
type Dimension = Dimensionless;
fn parameters() -> UnitParameters {
UnitParameters {
scale: 1.0,
offset: 0.0,
symbol: "",
name: "Unitless",
}
}
}
impl Default for Unitless {
fn default() -> Self {
Unitless
}
}
use std::marker::PhantomData;
pub struct UnitMul<L: Unit, R: Unit>(PhantomData<(L, R)>);
impl<L: Unit, R: Unit> Unit for UnitMul<L, R>
where
L::Dimension: MultiplyDimensions<R::Dimension>,
{
type Dimension = dim_mul!((<L as Unit>::Dimension), (<R as Unit>::Dimension));
fn parameters() -> UnitParameters {
let lhs_params = L::parameters();
let rhs_params = R::parameters();
UnitParameters {
scale: lhs_params.scale * rhs_params.scale,
offset: 0.0,
symbol: "", name: "", }
}
}
pub struct UnitInv<T: Unit>(PhantomData<T>);
impl<T: Unit> Unit for UnitInv<T>
where
T::Dimension: InvertDimension,
{
type Dimension = dim_inv!((<T as Unit>::Dimension));
fn parameters() -> UnitParameters {
let params = T::parameters();
UnitParameters {
scale: 1.0 / params.scale,
offset: 0.0,
symbol: "", name: "", }
}
}
#[macro_export]
macro_rules! unit_mul {
($lhs:ty, $rhs:ty) => {
UnitMul<$lhs, $rhs>
};
}
#[macro_export]
macro_rules! unit_inv {
($unit:ty) => {
UnitInv<$unit>
};
}
#[macro_export]
macro_rules! unit_div {
($lhs:ty, $rhs:ty) => {
UnitMul<$lhs, UnitInv<$rhs>>
};
}