summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2018-05-22 13:36:12 +0100
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2018-05-22 13:36:12 +0100
commit1ca93a52487684c509326775d839182326d3ef8e (patch)
tree2e39120711d0f26e6247386008036dc5535b311c
parent8af2ea53f6ce45aa6cc75436557c1f03c0b28eb5 (diff)
downloadcanopied-1ca93a52487684c509326775d839182326d3ef8e.tar.bz2
Initial qvalues subcrate
-rw-r--r--qvalues/Cargo.toml6
-rw-r--r--qvalues/src/lib.rs264
2 files changed, 270 insertions, 0 deletions
diff --git a/qvalues/Cargo.toml b/qvalues/Cargo.toml
new file mode 100644
index 0000000..1cf08ec
--- /dev/null
+++ b/qvalues/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "qvalues"
+version = "0.1.0"
+authors = ["Daniel Silverstone <daniel.silverstone@codethink.co.uk>"]
+
+[dependencies]
diff --git a/qvalues/src/lib.rs b/qvalues/src/lib.rs
new file mode 100644
index 0000000..49d0770
--- /dev/null
+++ b/qvalues/src/lib.rs
@@ -0,0 +1,264 @@
+#[derive(Eq, PartialEq, PartialOrd, Copy, Clone)]
+pub enum BaseQuantity {
+ Voltage,
+ Current,
+ Temperature,
+ Distance,
+ Time,
+}
+
+impl BaseQuantity {
+ pub fn units(&self) -> &str {
+ match self {
+ BaseQuantity::Voltage => "v",
+ BaseQuantity::Current => "a",
+ BaseQuantity::Temperature => "c",
+ BaseQuantity::Distance => "m",
+ BaseQuantity::Time => "s",
+ }
+ }
+}
+
+// Note, this max value has to be sync'd with the BaseQuantity above
+#[derive(Eq, PartialEq, Clone, Copy)]
+pub struct Quantifier([i8; 5]);
+
+impl Quantifier {
+ pub fn new() -> Quantifier {
+ Quantifier([0; 5])
+ }
+
+ pub fn singleton(q: BaseQuantity) -> Quantifier {
+ let mut ret = Quantifier::new();
+ ret[q] = 1;
+ ret
+ }
+
+ pub fn is_scalar(&self) -> bool {
+ let mut scalar = true;
+ for v in self.0.iter() {
+ if *v != 0 {
+ scalar = false;
+ break;
+ }
+ }
+ scalar
+ }
+}
+
+impl std::ops::Index<BaseQuantity> for Quantifier {
+ type Output = i8;
+ fn index(&self, q: BaseQuantity) -> &i8 {
+ &self.0[q as usize]
+ }
+}
+
+impl std::ops::IndexMut<BaseQuantity> for Quantifier {
+ fn index_mut(&mut self, q: BaseQuantity) -> &mut i8 {
+ &mut self.0[q as usize]
+ }
+}
+
+impl std::ops::Mul for Quantifier {
+ type Output = Self;
+ fn mul(self, rhs: Self) -> Self {
+ let mut ret = Quantifier::new();
+ for ((zref, aval), bval) in ret.0.iter_mut().zip(self.0.iter()).zip(rhs.0.iter()) {
+ *zref = aval + bval;
+ }
+ ret
+ }
+}
+
+impl std::ops::Div for Quantifier {
+ type Output = Self;
+ fn div(self, rhs: Self) -> Self {
+ let mut ret = Quantifier::new();
+ for ((zref, aval), bval) in ret.0.iter_mut().zip(self.0.iter()).zip(rhs.0.iter()) {
+ *zref = aval - bval;
+ }
+ ret
+ }
+}
+
+#[derive(PartialEq, Clone, Copy)]
+pub struct QValue {
+ val: f64,
+ q: Quantifier,
+}
+
+impl QValue {
+ pub fn new(v: f64) -> QValue {
+ QValue {
+ val: v,
+ q: Quantifier::new(),
+ }
+ }
+
+ pub fn unit(q: BaseQuantity) -> QValue {
+ QValue {
+ val: 1.0,
+ q: Quantifier::singleton(q),
+ }
+ }
+
+ pub fn value(&self) -> f64 {
+ self.val
+ }
+ pub fn quantifier(&self) -> &Quantifier {
+ &self.q
+ }
+}
+
+impl std::ops::Add for QValue {
+ type Output = Option<QValue>;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ if self.q != rhs.q {
+ None
+ } else {
+ Some(QValue {
+ val: self.val + rhs.val,
+ q: self.q,
+ })
+ }
+ }
+}
+
+impl std::ops::Sub for QValue {
+ type Output = Option<QValue>;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ if self.q != rhs.q {
+ None
+ } else {
+ Some(QValue {
+ val: self.val - rhs.val,
+ q: self.q,
+ })
+ }
+ }
+}
+
+impl std::ops::Mul for QValue {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self {
+ QValue {
+ val: self.val * rhs.val,
+ q: self.q * rhs.q,
+ }
+ }
+}
+
+impl std::ops::Div for QValue {
+ type Output = Self;
+
+ fn div(self, rhs: Self) -> Self {
+ QValue {
+ val: self.val / rhs.val,
+ q: self.q / rhs.q,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use BaseQuantity;
+ use QValue;
+ use Quantifier;
+
+ #[test]
+ fn check_singletons() {
+ assert!(Quantifier::singleton(BaseQuantity::Voltage)[BaseQuantity::Voltage] == 1);
+ assert!(Quantifier::singleton(BaseQuantity::Current)[BaseQuantity::Current] == 1);
+ assert!(Quantifier::singleton(BaseQuantity::Temperature)[BaseQuantity::Temperature] == 1);
+ assert!(Quantifier::singleton(BaseQuantity::Distance)[BaseQuantity::Distance] == 1);
+ assert!(Quantifier::singleton(BaseQuantity::Time)[BaseQuantity::Time] == 1);
+
+ assert!(Quantifier::singleton(BaseQuantity::Voltage)[BaseQuantity::Voltage] == 1);
+ assert!(Quantifier::singleton(BaseQuantity::Voltage)[BaseQuantity::Current] == 0);
+ assert!(Quantifier::singleton(BaseQuantity::Voltage)[BaseQuantity::Temperature] == 0);
+ assert!(Quantifier::singleton(BaseQuantity::Voltage)[BaseQuantity::Distance] == 0);
+ assert!(Quantifier::singleton(BaseQuantity::Voltage)[BaseQuantity::Time] == 0);
+ }
+
+ #[test]
+ fn check_new_q_is_scalar() {
+ assert!(Quantifier::new().is_scalar());
+ }
+
+ #[test]
+ fn check_scalar_op_scalar_is_scalar() {
+ assert!((Quantifier::new() * Quantifier::new()).is_scalar());
+ assert!((Quantifier::new() / Quantifier::new()).is_scalar());
+ }
+
+ #[test]
+ fn check_volts_div_volts_is_scalar() {
+ assert!(
+ (Quantifier::singleton(BaseQuantity::Voltage)
+ / Quantifier::singleton(BaseQuantity::Voltage))
+ .is_scalar()
+ );
+ }
+
+ #[test]
+ fn check_qvalue_scalar() {
+ assert!(QValue::new(0.0).quantifier().is_scalar());
+ assert!(!QValue::unit(BaseQuantity::Voltage).quantifier().is_scalar());
+ }
+
+ #[test]
+ fn check_qvalue_unit() {
+ assert!(QValue::unit(BaseQuantity::Voltage).quantifier()[BaseQuantity::Voltage] == 1);
+ }
+
+ #[test]
+ fn check_qvalue_add() {
+ let volt = QValue::unit(BaseQuantity::Voltage);
+ let amp = QValue::unit(BaseQuantity::Current);
+ assert!((volt + volt).is_some());
+ assert!((volt + amp).is_none());
+ assert!((volt + volt).unwrap().value() == 2.0);
+ }
+
+ #[test]
+ fn check_qvalue_sub() {
+ let volt = QValue::unit(BaseQuantity::Voltage);
+ let amp = QValue::unit(BaseQuantity::Current);
+ assert!((volt - volt).is_some());
+ assert!((volt - amp).is_none());
+ assert!((volt - volt).unwrap().value() == 0.0);
+ }
+
+ #[test]
+ fn check_qvalue_mul() {
+ let volt = QValue::unit(BaseQuantity::Voltage);
+ let amp = QValue::unit(BaseQuantity::Current);
+ let watt = Quantifier::singleton(BaseQuantity::Voltage)
+ * Quantifier::singleton(BaseQuantity::Current);
+ assert!(*(volt * amp).quantifier() == watt);
+ }
+
+ #[test]
+ fn check_qvalue_div() {
+ let volt = QValue::unit(BaseQuantity::Voltage);
+ let amp = QValue::unit(BaseQuantity::Current);
+ assert!(*(volt * amp / volt).quantifier() == Quantifier::singleton(BaseQuantity::Current));
+ }
+
+ #[test]
+ fn verify_basequantity_units() {
+ let cases = [
+ (BaseQuantity::Voltage, "v"),
+ (BaseQuantity::Current, "a"),
+ (BaseQuantity::Temperature, "c"),
+ (BaseQuantity::Time, "s"),
+ (BaseQuantity::Distance, "m"),
+ ];
+ for (q, s) in cases.iter() {
+ assert!(q.units() == *s);
+ }
+ }
+}