Rearranged files

pull/2/head
Mark 2023-04-13 09:21:53 -07:00
parent e2d49c5fb6
commit 78b0262f61
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
4 changed files with 315 additions and 290 deletions

View File

@ -0,0 +1,160 @@
use std::hash::{Hash, Hasher};
use crate::quantity::Scalar;
use crate::quantity::Quantity;
use super::UnitBase;
use super::Prefix;
use super::Unit;
#[derive(Debug)]
#[derive(Copy, Clone)]
pub struct FreeUnit {
pub (in super) base: UnitBase,
pub (in super) prefix: Prefix
}
impl Hash for FreeUnit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.base.hash(state);
}
}
impl Eq for FreeUnit {}
impl PartialEq for FreeUnit {
fn eq(&self, other: &Self) -> bool {
self.base.eq(&other.base)
}
}
macro_rules! quick_base_factor {
(float, $u:expr, $s:expr, $( ($x:expr, $p:expr) ),* ) => {
Some(Quantity {
scalar: Scalar::new_float_from_string($s).unwrap(),
unit: Unit::from_array(&[
$(
(FreeUnit::from_base($x), Scalar::new_rational($p).unwrap()),
)*
(FreeUnit::from_base($u), Scalar::new_rational(-1f64).unwrap())
])
})
};
(rational, $u:expr, $s:expr, $( ($x:expr, $p:expr) ),* ) => {
Some(Quantity {
scalar: Scalar::new_float_from_string($s).unwrap(),
unit: Unit::from_array(&[
$(
(FreeUnit::from_base($x), Scalar::new_rational($p).unwrap()),
)*
(FreeUnit::from_base($u), Scalar::new_rational(-1f64).unwrap())
])
})
};
}
impl FreeUnit {
pub fn from_base(base: UnitBase) -> FreeUnit {
return FreeUnit { base, prefix: Prefix::None }
}
pub fn from_base_prefix(base: UnitBase, prefix: Prefix) -> FreeUnit { FreeUnit {base, prefix} }
pub fn set_prefix(&mut self, prefix: Prefix) { self.prefix = prefix; }
pub fn get_prefix(&self) -> Prefix { self.prefix }
pub fn same_with_prefix(&self, other: &FreeUnit) -> bool {
self.base.eq(&other.base) && self.prefix.eq(&other.prefix)
}
pub fn to_base_factor(&self) -> Quantity {
let q = match self.base {
// Returns the unit we need to multiply by to get a base
// unit, or `None` if this is already a base unit.
//
// Example:
// 1 foot = 0.3048 m,
// so 1 ft * (0.3084 m / ft) will give meters.
//
// The units here MUST be in terms of base units.
// If they aren't, things will break.
UnitBase::Foot => quick_base_factor!(float,
UnitBase::Foot,
"0.3048",
(UnitBase::Meter, 1f64)
),
UnitBase::Inch => quick_base_factor!(float,
UnitBase::Inch,
"0.0254",
(UnitBase::Meter, 1f64)
),
UnitBase::Mile => quick_base_factor!(rational,
UnitBase::Mile,
"1609",
(UnitBase::Meter, 1f64)
),
UnitBase::Minute => quick_base_factor!(rational,
UnitBase::Minute,
"60",
(UnitBase::Second, 1f64)
),
UnitBase::Hour => quick_base_factor!(rational,
UnitBase::Hour,
"3600",
(UnitBase::Second, 1f64)
),
UnitBase::Day => quick_base_factor!(rational,
UnitBase::Day,
"86400",
(UnitBase::Second, 1f64)
),
// Only base units should be missing a conversion factor.
_ => None
};
let mut q = q.unwrap_or(Quantity::new_rational_from_string("1").unwrap());
let mut p = self.prefix.to_ratio();
p.insert_unit(FreeUnit::from_base(self.base), Scalar::new_rational(1f64).unwrap());
p.insert_unit(FreeUnit::from_base_prefix(self.base, self.prefix), Scalar::new_rational(-1f64).unwrap());
q *= p;
return q;
}
}
impl ToString for FreeUnit {
fn to_string(&self) -> String {
let s = match self.base {
UnitBase::Second => "s",
UnitBase::Meter => "m",
UnitBase::Gram => "g",
UnitBase::Ampere => "a",
UnitBase::Kelvin => "k",
UnitBase::Mole => "mol",
UnitBase::Candela => "c",
UnitBase::Foot => "ft",
UnitBase::Inch => "in",
UnitBase::Mile => "mile",
UnitBase::Hour => "hour",
UnitBase::Minute => "min",
UnitBase::Day => "day",
};
let p = self.prefix.to_string();
format!("{p}{s}")
}
}

40
src/quantity/unit/mod.rs Normal file
View File

@ -0,0 +1,40 @@
use std::hash::Hash;
mod freeunit;
mod prefix;
mod unit;
pub use prefix::Prefix;
pub use unit::Unit;
pub use freeunit::FreeUnit;
#[derive(Hash)]
#[derive(Debug)]
#[derive(Copy, Clone)]
#[derive(Eq, PartialEq)]
pub enum UnitBase {
// Base Units
Second,
Meter,
Gram, // Technically kilogram, but that messes with our prefix system.
Ampere,
Kelvin,
Mole,
Candela,
// Length units
Inch,
Foot,
Mile,
// Time units
Minute,
Hour,
Day,
//Week,
//Month,
}

110
src/quantity/unit/prefix.rs Normal file
View File

@ -0,0 +1,110 @@
use crate::quantity::Quantity;
#[derive(Hash)]
#[derive(Debug)]
#[derive(Copy, Clone)]
#[derive(Eq, PartialEq)]
pub enum Prefix {
None,
Quetta,
Ronna,
Yotta,
Zetta,
Exa,
Peta,
Tera,
Giga,
Mega,
Kilo,
Hecto,
Deka,
Deci,
Centi,
Milli,
Micro,
Nano,
Pico,
Femto,
Atto,
Zepto,
Yocto,
Ronto,
Quecto
}
impl Prefix {
pub fn to_ratio(&self) -> Quantity {
let q = Quantity::new_rational_from_string(match self {
Prefix::Quetta => "1e30",
Prefix::Ronna => "1e27",
Prefix::Yotta => "1e24",
Prefix::Zetta => "1e21",
Prefix::Exa => "1e18",
Prefix::Peta => "1e15",
Prefix::Tera => "1e12",
Prefix::Giga => "1e9",
Prefix::Mega => "1e6",
Prefix::Kilo => "1e3",
Prefix::Hecto => "1e2",
Prefix::Deka => "1e1",
Prefix::Deci => "1e-1",
Prefix::Centi => "1e-2",
Prefix::Milli => "1e-3",
Prefix::Micro => "1e-6",
Prefix::Nano => "1e-9",
Prefix::Pico => "1e-12",
Prefix::Femto => "1e-15",
Prefix::Atto => "1e-18",
Prefix::Zepto => "1e-21",
Prefix::Yocto => "1e-24",
Prefix::Ronto => "1e-27",
Prefix::Quecto => "1e-30",
Prefix::None => { "1" }
}).unwrap();
return q;
}
}
impl ToString for Prefix {
fn to_string(&self) -> String {
String::from(match self {
Prefix::Quetta => "Q",
Prefix::Ronna => "R",
Prefix::Yotta => "Y",
Prefix::Zetta => "Z",
Prefix::Exa => "E",
Prefix::Peta => "P",
Prefix::Tera => "T",
Prefix::Giga => "G",
Prefix::Mega => "M",
Prefix::Kilo => "k",
Prefix::Hecto => "h",
Prefix::Deka => "da",
Prefix::Deci => "d",
Prefix::Centi => "c",
Prefix::Milli => "m",
Prefix::Micro => "u",
Prefix::Nano => "n",
Prefix::Pico => "p",
Prefix::Femto => "f",
Prefix::Atto => "a",
Prefix::Zepto => "z",
Prefix::Yocto => "y",
Prefix::Ronto => "r",
Prefix::Quecto => "q",
Prefix::None => ""
})
}
}

View File

@ -1,298 +1,14 @@
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::ops::{
Mul, Div,
MulAssign, DivAssign
};
use super::Scalar;
use super::Quantity;
#[derive(Hash)]
#[derive(Debug)]
#[derive(Copy, Clone)]
#[derive(Eq, PartialEq)]
pub enum UnitBase {
// Base Units
Second,
Meter,
Gram, // Technically kilogram, but that messes with prefix architecture.
Ampere,
Kelvin,
Mole,
Candela,
// Length units
Inch,
Foot,
Mile,
// Time units
Minute,
Hour,
Day,
//Week,
//Month,
}
#[derive(Hash)]
#[derive(Debug)]
#[derive(Copy, Clone)]
#[derive(Eq, PartialEq)]
pub enum Prefix {
None,
Quetta,
Ronna,
Yotta,
Zetta,
Exa,
Peta,
Tera,
Giga,
Mega,
Kilo,
Hecto,
Deka,
Deci,
Centi,
Milli,
Micro,
Nano,
Pico,
Femto,
Atto,
Zepto,
Yocto,
Ronto,
Quecto
}
impl Prefix {
pub fn to_ratio(&self) -> Quantity {
let q = Quantity::new_rational_from_string(match self {
Prefix::Quetta => "1e30",
Prefix::Ronna => "1e27",
Prefix::Yotta => "1e24",
Prefix::Zetta => "1e21",
Prefix::Exa => "1e18",
Prefix::Peta => "1e15",
Prefix::Tera => "1e12",
Prefix::Giga => "1e9",
Prefix::Mega => "1e6",
Prefix::Kilo => "1e3",
Prefix::Hecto => "1e2",
Prefix::Deka => "1e1",
Prefix::Deci => "1e-1",
Prefix::Centi => "1e-2",
Prefix::Milli => "1e-3",
Prefix::Micro => "1e-6",
Prefix::Nano => "1e-9",
Prefix::Pico => "1e-12",
Prefix::Femto => "1e-15",
Prefix::Atto => "1e-18",
Prefix::Zepto => "1e-21",
Prefix::Yocto => "1e-24",
Prefix::Ronto => "1e-27",
Prefix::Quecto => "1e-30",
Prefix::None => { "1" }
}).unwrap();
return q;
}
}
impl ToString for Prefix {
fn to_string(&self) -> String {
String::from(match self {
Prefix::Quetta => "Q",
Prefix::Ronna => "R",
Prefix::Yotta => "Y",
Prefix::Zetta => "Z",
Prefix::Exa => "E",
Prefix::Peta => "P",
Prefix::Tera => "T",
Prefix::Giga => "G",
Prefix::Mega => "M",
Prefix::Kilo => "k",
Prefix::Hecto => "h",
Prefix::Deka => "da",
Prefix::Deci => "d",
Prefix::Centi => "c",
Prefix::Milli => "m",
Prefix::Micro => "u",
Prefix::Nano => "n",
Prefix::Pico => "p",
Prefix::Femto => "f",
Prefix::Atto => "a",
Prefix::Zepto => "z",
Prefix::Yocto => "y",
Prefix::Ronto => "r",
Prefix::Quecto => "q",
Prefix::None => ""
})
}
}
#[derive(Debug)]
#[derive(Copy, Clone)]
pub struct FreeUnit {
base: UnitBase,
prefix: Prefix
}
impl Hash for FreeUnit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.base.hash(state);
}
}
impl Eq for FreeUnit {}
impl PartialEq for FreeUnit {
fn eq(&self, other: &Self) -> bool {
self.base.eq(&other.base)
}
}
macro_rules! quick_base_factor {
(float, $u:expr, $s:expr, $( ($x:expr, $p:expr) ),* ) => {
Some(Quantity {
scalar: Scalar::new_float_from_string($s).unwrap(),
unit: Unit::from_array(&[
$(
(FreeUnit::from_base($x), Scalar::new_rational($p).unwrap()),
)*
(FreeUnit::from_base($u), Scalar::new_rational(-1f64).unwrap())
])
})
};
(rational, $u:expr, $s:expr, $( ($x:expr, $p:expr) ),* ) => {
Some(Quantity {
scalar: Scalar::new_float_from_string($s).unwrap(),
unit: Unit::from_array(&[
$(
(FreeUnit::from_base($x), Scalar::new_rational($p).unwrap()),
)*
(FreeUnit::from_base($u), Scalar::new_rational(-1f64).unwrap())
])
})
};
}
impl FreeUnit {
pub fn from_base(base: UnitBase) -> FreeUnit {
return FreeUnit { base, prefix: Prefix::None }
}
pub fn from_base_prefix(base: UnitBase, prefix: Prefix) -> FreeUnit { FreeUnit {base, prefix} }
pub fn set_prefix(&mut self, prefix: Prefix) { self.prefix = prefix; }
pub fn get_prefix(&self) -> Prefix { self.prefix }
pub fn same_with_prefix(&self, other: &FreeUnit) -> bool {
self.base.eq(&other.base) && self.prefix.eq(&other.prefix)
}
pub fn to_base_factor(&self) -> Quantity {
let q = match self.base {
// Returns the unit we need to multiply by to get a base
// unit, or `None` if this is already a base unit.
//
// Example:
// 1 foot = 0.3048 m,
// so 1 ft * (0.3084 m / ft) will give meters.
//
// The units here MUST be in terms of base units.
// If they aren't, things will break.
UnitBase::Foot => quick_base_factor!(float,
UnitBase::Foot,
"0.3048",
(UnitBase::Meter, 1f64)
),
UnitBase::Inch => quick_base_factor!(float,
UnitBase::Inch,
"0.0254",
(UnitBase::Meter, 1f64)
),
UnitBase::Mile => quick_base_factor!(rational,
UnitBase::Mile,
"1609",
(UnitBase::Meter, 1f64)
),
UnitBase::Minute => quick_base_factor!(rational,
UnitBase::Minute,
"60",
(UnitBase::Second, 1f64)
),
UnitBase::Hour => quick_base_factor!(rational,
UnitBase::Hour,
"3600",
(UnitBase::Second, 1f64)
),
UnitBase::Day => quick_base_factor!(rational,
UnitBase::Day,
"86400",
(UnitBase::Second, 1f64)
),
// Only base units should be missing a conversion factor.
_ => None
};
let mut q = q.unwrap_or(Quantity::new_rational_from_string("1").unwrap());
let mut p = self.prefix.to_ratio();
p.insert_unit(FreeUnit::from_base(self.base), Scalar::new_rational(1f64).unwrap());
p.insert_unit(FreeUnit::from_base_prefix(self.base, self.prefix), Scalar::new_rational(-1f64).unwrap());
q *= p;
return q;
}
}
impl ToString for FreeUnit {
fn to_string(&self) -> String {
let s = match self.base {
UnitBase::Second => "s",
UnitBase::Meter => "m",
UnitBase::Gram => "g",
UnitBase::Ampere => "a",
UnitBase::Kelvin => "k",
UnitBase::Mole => "mol",
UnitBase::Candela => "c",
UnitBase::Foot => "ft",
UnitBase::Inch => "in",
UnitBase::Mile => "mile",
UnitBase::Hour => "hour",
UnitBase::Minute => "min",
UnitBase::Day => "day",
};
let p = self.prefix.to_string();
format!("{p}{s}")
}
}
use crate::quantity::Scalar;
use crate::quantity::Quantity;
use super::UnitBase;
use super::Prefix;
use super::FreeUnit;
#[derive(Debug)]
#[derive(Clone)]
@ -351,7 +67,6 @@ impl ToString for Unit {
}
}
impl Unit {
pub fn new() -> Unit {
return Unit {