From 175261b5c0f7daf128176e0b75eb6cc0d80f00e2 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 10 Apr 2023 21:03:16 -0700 Subject: [PATCH] Compound unit foundation --- src/parser/mod.rs | 19 +++++++------- src/quantity/mod.rs | 5 ++++ src/quantity/quantity.rs | 46 +++++++++++++++++++++++++++++--- src/quantity/unit.rs | 57 ++++++++++++++++++++++++++-------------- 4 files changed, 94 insertions(+), 33 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 1622165..0ba96b4 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -93,31 +93,30 @@ impl PreToken { let c = match &s[..] { // Mathematical constants // 100 digits of each. - "π"|"pi" => { Some(Token::Constant(Quantity::new_float_from_string( + "π"|"pi" => { Some((Quantity::new_float_from_string( "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067" ).unwrap(), String::from("π")))}, - "e" => { Some(Token::Constant(Quantity::new_float_from_string( + "e" => { Some((Quantity::new_float_from_string( "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427" ).unwrap(), String::from("e"))) }, - "phi"|"φ" => { Some(Token::Constant(Quantity::new_float_from_string( + "phi"|"φ" => { Some((Quantity::new_float_from_string( "1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137" ).unwrap(), String::from("φ"))) }, _ => { None } }; - if c.is_some() { return Ok(c.unwrap()); } - - let c = Unit::from_string(&s); - if c.is_some() { - let mut q = Quantity::new_rational(1f64).unwrap(); - q.set_unit(c.unwrap()); - return Ok(Token::Number(q)); + let (a, b) = c.unwrap(); + return Ok(Token::Constant(a, b)); } + let c = Quantity::from_unit_string(&s); + + if c.is_some() { return Ok(Token::Number(c.unwrap())); } + return Err((l, ParserError::Undefined(s))); } diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs index f1c149f..c962230 100644 --- a/src/quantity/mod.rs +++ b/src/quantity/mod.rs @@ -22,6 +22,11 @@ pub(in crate::quantity) use crate::quantity::scalar::Scalar; mod unit; pub use crate::quantity::unit::Unit; pub use crate::quantity::unit::BaseUnit; +pub(in crate::quantity) use crate::quantity::unit::CompoundUnit; mod quantity; pub use crate::quantity::quantity::Quantity; + + + + diff --git a/src/quantity/quantity.rs b/src/quantity/quantity.rs index 7bf2779..233afff 100644 --- a/src/quantity/quantity.rs +++ b/src/quantity/quantity.rs @@ -7,9 +7,9 @@ use std::ops::{ }; use std::cmp::Ordering; - use crate::quantity::Unit; use crate::quantity::BaseUnit; +use crate::quantity::CompoundUnit; use crate::quantity::Scalar; @@ -44,8 +44,6 @@ impl Quantity { return format!("{n} {u}"); } - - pub fn new_float(f: f64) -> Option { let v = Scalar::new_float(f); if v.is_none() { return None; } @@ -88,6 +86,48 @@ impl Quantity { pub fn insert_unit(&mut self, ui: BaseUnit, pi: f64) { self.u.insert(ui, pi) } pub fn set_unit(&mut self, u: Unit) { self.u = u; } + + pub fn from_unit_string(s: &str) -> Option { + // Base Units + let b = match s { + "m" => Some(BaseUnit::Meter), + "s" => Some(BaseUnit::Second), + "kg" => Some(BaseUnit::Kilogram), + "a" => Some(BaseUnit::Ampere), + "k" => Some(BaseUnit::Kelvin), + "mol" => Some(BaseUnit::Mole), + "c" => Some(BaseUnit::Candela), + _ => { None } + }; + + if b.is_some() { + let mut u = Unit::new(); + u.insert(b.unwrap(), 1f64); + + let mut q = Quantity::new_rational(1f64).unwrap(); + q.set_unit(u); + + return Some(q); + }; + + // Compound units + let b = match s { + "ft" => Some(CompoundUnit::FOOT), + _ => { None } + }; + + if b.is_some() { + let b = b.unwrap(); + let q = Quantity{ + v: b.coef(), + u: b.unit() + }; + return Some(q); + }; + + return None; + } + } diff --git a/src/quantity/unit.rs b/src/quantity/unit.rs index f45c7bd..493b68f 100644 --- a/src/quantity/unit.rs +++ b/src/quantity/unit.rs @@ -1,11 +1,11 @@ -use std::{collections::HashMap, hash::Hash}; - - +use std::collections::HashMap; use std::ops::{ Mul, Div, MulAssign, DivAssign }; +use crate::quantity::Scalar; + #[derive(Debug)] #[derive(Hash)] #[derive(Eq, PartialEq)] @@ -20,6 +20,40 @@ pub enum BaseUnit { Candela } +pub struct CompoundUnit { + coef_str: &'static str, + rational: bool, + units: &'static[(BaseUnit, f64)], + pub str: &'static str +} + +impl CompoundUnit { + pub const FOOT: CompoundUnit = CompoundUnit { + coef_str: "0.3048", + rational: false, + units: &[(BaseUnit::Meter, 1f64)], + str: "ft" + }; + + pub fn unit(&self) -> Unit { + let mut n = Unit::new(); + for (u, p) in self.units.iter() { + n.insert(*u, *p); + } + return n; + } + + pub fn coef(&self) -> Scalar { + if self.rational { + Scalar::new_rational_from_string(self.coef_str).unwrap() + } else { + Scalar::new_float_from_string(self.coef_str).unwrap() + } + } +} + + + #[derive(Debug)] #[derive(Clone)] pub struct Unit { @@ -117,23 +151,6 @@ impl Unit { }; return u; } - - pub fn from_string(s: &str) -> Option { - let b = match s { - "m" => BaseUnit::Meter, - "s" => BaseUnit::Second, - "kg" => BaseUnit::Kilogram, - "a" => BaseUnit::Ampere, - "k" => BaseUnit::Kelvin, - "mol" => BaseUnit::Mole, - "c" => BaseUnit::Candela, - _ => { return None; } - }; - - let mut u = Unit::new(); - u.insert(b, 1f64); - return Some(u); - } }