diff --git a/src/numbers/dynnum.rs b/src/numbers/dynnum.rs
new file mode 100644
index 0000000..eab11c6
--- /dev/null
+++ b/src/numbers/dynnum.rs
@@ -0,0 +1,513 @@
+/* OpenTally: Open-source election vote counting
+ * Copyright © 2021 Lee Yingtong Li (RunasSudo)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+use super::{Assign, Fixed, GuardedFixed, NativeFloat64, Number, Rational};
+
+use num_traits::{Num, One, Zero};
+//use wasm_bindgen::prelude::wasm_bindgen;
+
+use std::cmp::{Ord, Ordering};
+use std::fmt;
+use std::mem::ManuallyDrop;
+use std::ops::{self, Deref, DerefMut};
+
+/// Represents the underlying implementation for [DynNum]s
+//#[wasm_bindgen]
+pub enum NumKind {
+ /// See [crate::numbers::fixed]
+ Fixed,
+ /// See [crate::numbers::gfixed]
+ GuardedFixed,
+ /// See [crate::numbers::native]
+ NativeFloat64,
+ /// See [crate::numbers::rational_rug] or [crate::numbers::rational_num]
+ Rational,
+}
+
+/// Determines which underlying implementation to use
+static mut KIND: NumKind = NumKind::Fixed;
+
+/// Returns which underlying implementation is in use
+#[inline]
+fn get_kind() -> &'static NumKind {
+ unsafe {
+ return &KIND;
+ }
+}
+
+/// A wrapper for different numeric types using dynamic dispatch
+pub union DynNum {
+ fixed: ManuallyDrop,
+ gfixed: ManuallyDrop,
+ float64: NativeFloat64,
+ rational: ManuallyDrop,
+}
+
+impl DynNum {
+ /// Set which underlying implementation to use
+ pub fn set_kind(kind: NumKind) {
+ unsafe {
+ KIND = kind;
+ }
+ }
+}
+
+macro_rules! impl_1arg_nowrap {
+ ($self:expr, $arg:expr, $func:ident) => {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ $self.fixed.$func($arg)
+ }
+ NumKind::GuardedFixed => {
+ $self.gfixed.$func($arg)
+ }
+ NumKind::NativeFloat64 => {
+ $self.float64.$func($arg)
+ }
+ NumKind::Rational => {
+ $self.rational.$func($arg)
+ }
+ }
+ }
+ }
+}
+
+macro_rules! impl_assoc_nowrap {
+ ($func:ident) => {
+ match get_kind() {
+ NumKind::Fixed => {
+ Fixed::$func()
+ }
+ NumKind::GuardedFixed => {
+ GuardedFixed::$func()
+ }
+ NumKind::NativeFloat64 => {
+ NativeFloat64::$func()
+ }
+ NumKind::Rational => {
+ Rational::$func()
+ }
+ }
+ }
+}
+
+impl Number for DynNum {
+ fn new() -> Self {
+ match get_kind() {
+ NumKind::Fixed => {
+ DynNum { fixed: ManuallyDrop::new(Fixed::new()) }
+ }
+ NumKind::GuardedFixed => {
+ DynNum { gfixed: ManuallyDrop::new(GuardedFixed::new()) }
+ }
+ NumKind::NativeFloat64 => {
+ DynNum { float64: NativeFloat64::new() }
+ }
+ NumKind::Rational => {
+ DynNum { rational: ManuallyDrop::new(Rational::new()) }
+ }
+ }
+ }
+
+ fn describe() -> String { impl_assoc_nowrap!(describe) }
+ fn pow_assign(&mut self, exponent: i32) { impl_1arg_nowrap!(self, exponent, pow_assign) }
+ fn floor_mut(&mut self, dps: usize) { impl_1arg_nowrap!(self, dps, floor_mut) }
+ fn ceil_mut(&mut self, dps: usize) { impl_1arg_nowrap!(self, dps, ceil_mut) }
+ fn round_mut(&mut self, dps: usize) { impl_1arg_nowrap!(self, dps, round_mut) }
+}
+
+impl Drop for DynNum {
+ fn drop(&mut self) {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ ManuallyDrop::drop(&mut self.fixed);
+ }
+ NumKind::GuardedFixed => {
+ ManuallyDrop::drop(&mut self.gfixed);
+ }
+ NumKind::NativeFloat64 => {}
+ NumKind::Rational => {
+ ManuallyDrop::drop(&mut self.rational);
+ }
+ }
+ }
+ }
+}
+
+macro_rules! impl_0arg_wrap {
+ ($self:expr, $func:ident) => {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ DynNum { fixed: ManuallyDrop::new($self.fixed.deref().$func()) }
+ }
+ NumKind::GuardedFixed => {
+ DynNum { gfixed: ManuallyDrop::new($self.gfixed.deref().$func()) }
+ }
+ NumKind::NativeFloat64 => {
+ DynNum { float64: $self.float64.$func() }
+ }
+ NumKind::Rational => {
+ DynNum { rational: ManuallyDrop::new($self.rational.deref().$func()) }
+ }
+ }
+ }
+ }
+}
+
+impl Clone for DynNum {
+ fn clone(&self) -> Self { impl_0arg_wrap!(self, clone) }
+}
+
+impl Num for DynNum {
+ type FromStrRadixErr = Self; // TODO
+
+ fn from_str_radix(str: &str, radix: u32) -> Result {
+ match get_kind() {
+ NumKind::Fixed => {
+ Ok(DynNum { fixed: ManuallyDrop::new(Fixed::from_str_radix(str, radix).unwrap()) })
+ }
+ NumKind::GuardedFixed => {
+ Ok(DynNum { gfixed: ManuallyDrop::new(GuardedFixed::from_str_radix(str, radix).unwrap()) })
+ }
+ NumKind::NativeFloat64 => {
+ Ok(DynNum { float64: NativeFloat64::from_str_radix(str, radix).unwrap() })
+ }
+ NumKind::Rational => {
+ Ok(DynNum { rational: ManuallyDrop::new(Rational::from_str_radix(str, radix).unwrap()) })
+ }
+ }
+ }
+}
+
+macro_rules! impl_1other_nowrap {
+ ($self:expr, $rhs:expr, $func:ident) => {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ $self.fixed.deref().$func($rhs.fixed.deref())
+ }
+ NumKind::GuardedFixed => {
+ $self.gfixed.deref().$func($rhs.gfixed.deref())
+ }
+ NumKind::NativeFloat64 => {
+ $self.float64.$func(&$rhs.float64)
+ }
+ NumKind::Rational => {
+ $self.rational.deref().$func($rhs.rational.deref())
+ }
+ }
+ }
+ }
+}
+
+macro_rules! impl_1other_nowrap_mut {
+ ($self:expr, $rhs:expr, $func:ident) => {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ $self.fixed.deref_mut().$func($rhs.fixed.deref())
+ }
+ NumKind::GuardedFixed => {
+ $self.gfixed.deref_mut().$func($rhs.gfixed.deref())
+ }
+ NumKind::NativeFloat64 => {
+ $self.float64.$func(&$rhs.float64)
+ }
+ NumKind::Rational => {
+ $self.rational.deref_mut().$func($rhs.rational.deref())
+ }
+ }
+ }
+ }
+}
+
+impl Assign for DynNum {
+ fn assign(&mut self, src: Self) { impl_1other_nowrap_mut!(self, src, assign) }
+}
+
+impl Assign<&Self> for DynNum {
+ fn assign(&mut self, src: &Self) { impl_1other_nowrap_mut!(self, src, assign) }
+}
+
+impl From for DynNum {
+ fn from(n: usize) -> Self {
+ match get_kind() {
+ NumKind::Fixed => {
+ DynNum { fixed: ManuallyDrop::new(Fixed::from(n)) }
+ }
+ NumKind::GuardedFixed => {
+ DynNum { gfixed: ManuallyDrop::new(GuardedFixed::from(n)) }
+ }
+ NumKind::NativeFloat64 => {
+ DynNum { float64: NativeFloat64::from(n) }
+ }
+ NumKind::Rational => {
+ DynNum { rational: ManuallyDrop::new(Rational::from(n)) }
+ }
+ }
+ }
+}
+
+impl fmt::Display for DynNum {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl_1arg_nowrap!(self, f, fmt) }
+}
+
+impl fmt::Debug for DynNum {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl_1arg_nowrap!(self, f, fmt) }
+}
+
+impl PartialEq for DynNum {
+ fn eq(&self, other: &Self) -> bool { impl_1other_nowrap!(self, other, eq) }
+}
+
+impl Eq for DynNum {}
+
+impl PartialOrd for DynNum {
+ fn partial_cmp(&self, other: &Self) -> Option { impl_1other_nowrap!(self, other, partial_cmp) }
+}
+
+impl Ord for DynNum {
+ fn cmp(&self, other: &Self) -> Ordering { impl_1other_nowrap!(self, other, cmp) }
+}
+
+macro_rules! impl_assoc_wrap {
+ ($func:ident) => {
+ match get_kind() {
+ NumKind::Fixed => {
+ DynNum { fixed: ManuallyDrop::new(Fixed::$func()) }
+ }
+ NumKind::GuardedFixed => {
+ DynNum { gfixed: ManuallyDrop::new(GuardedFixed::$func()) }
+ }
+ NumKind::NativeFloat64 => {
+ DynNum { float64: NativeFloat64::$func() }
+ }
+ NumKind::Rational => {
+ DynNum { rational: ManuallyDrop::new(Rational::$func()) }
+ }
+ }
+ }
+}
+
+impl One for DynNum {
+ fn one() -> Self { impl_assoc_wrap!(one) }
+}
+
+macro_rules! impl_0arg_nowrap {
+ ($self:expr, $func:ident) => {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ $self.fixed.deref().$func()
+ }
+ NumKind::GuardedFixed => {
+ $self.gfixed.deref().$func()
+ }
+ NumKind::NativeFloat64 => {
+ $self.float64.$func()
+ }
+ NumKind::Rational => {
+ $self.rational.deref().$func()
+ }
+ }
+ }
+ }
+}
+
+impl Zero for DynNum {
+ fn zero() -> Self { impl_assoc_wrap!(zero) }
+
+ fn is_zero(&self) -> bool { impl_0arg_nowrap!(self, is_zero) }
+}
+
+impl ops::Neg for DynNum {
+ type Output = Self;
+ fn neg(self) -> Self::Output { impl_0arg_wrap!(self, neg) }
+}
+
+macro_rules! impl_1other_wrap {
+ ($self:expr, $rhs:expr, $func:ident) => {
+ // Safety: Access only correct union field
+ unsafe {
+ match get_kind() {
+ NumKind::Fixed => {
+ DynNum { fixed: ManuallyDrop::new($self.fixed.deref().$func($rhs.fixed.deref())) }
+ }
+ NumKind::GuardedFixed => {
+ DynNum { gfixed: ManuallyDrop::new($self.gfixed.deref().$func($rhs.gfixed.deref())) }
+ }
+ NumKind::NativeFloat64 => {
+ DynNum { float64: $self.float64.$func($rhs.float64) }
+ }
+ NumKind::Rational => {
+ DynNum { rational: ManuallyDrop::new($self.rational.deref().$func($rhs.rational.deref())) }
+ }
+ }
+ }
+ }
+}
+
+impl ops::Add for DynNum {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, add) }
+}
+
+impl ops::Sub for DynNum {
+ type Output = Self;
+ fn sub(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, sub) }
+}
+
+impl ops::Mul for DynNum {
+ type Output = Self;
+ fn mul(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, mul) }
+}
+
+impl ops::Div for DynNum {
+ type Output = Self;
+ fn div(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, div) }
+}
+
+impl ops::Rem for DynNum {
+ type Output = Self;
+ fn rem(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, rem) }
+}
+
+impl ops::Add<&Self> for DynNum {
+ type Output = Self;
+ fn add(self, rhs: &Self) -> Self::Output { impl_1other_wrap!(self, rhs, add) }
+}
+
+impl ops::Sub<&Self> for DynNum {
+ type Output = Self;
+ fn sub(self, rhs: &Self) -> Self::Output { impl_1other_wrap!(self, rhs, sub) }
+}
+
+impl ops::Mul<&Self> for DynNum {
+ type Output = Self;
+ fn mul(self, rhs: &Self) -> Self::Output { impl_1other_wrap!(self, rhs, mul) }
+}
+
+impl ops::Div<&Self> for DynNum {
+ type Output = Self;
+ fn div(self, rhs: &Self) -> Self::Output { impl_1other_wrap!(self, rhs, div) }
+}
+
+impl ops::Rem<&Self> for DynNum {
+ type Output = Self;
+ fn rem(self, rhs: &Self) -> Self::Output { impl_1other_wrap!(self, rhs, rem) }
+}
+
+impl ops::AddAssign for DynNum {
+ fn add_assign(&mut self, rhs: Self) { impl_1other_nowrap_mut!(self, rhs, add_assign) }
+}
+
+impl ops::SubAssign for DynNum {
+ fn sub_assign(&mut self, rhs: Self) { impl_1other_nowrap_mut!(self, rhs, sub_assign) }
+}
+
+impl ops::MulAssign for DynNum {
+ fn mul_assign(&mut self, rhs: Self) { impl_1other_nowrap_mut!(self, rhs, mul_assign) }
+}
+
+impl ops::DivAssign for DynNum {
+ fn div_assign(&mut self, rhs: Self) { impl_1other_nowrap_mut!(self, rhs, div_assign) }
+}
+
+impl ops::RemAssign for DynNum {
+ fn rem_assign(&mut self, rhs: Self) { impl_1other_nowrap_mut!(self, rhs, rem_assign) }
+}
+
+impl ops::AddAssign<&Self> for DynNum {
+ fn add_assign(&mut self, rhs: &Self) { impl_1other_nowrap_mut!(self, rhs, add_assign) }
+}
+
+impl ops::SubAssign<&Self> for DynNum {
+ fn sub_assign(&mut self, rhs: &Self) { impl_1other_nowrap_mut!(self, rhs, sub_assign) }
+}
+
+impl ops::MulAssign<&Self> for DynNum {
+ fn mul_assign(&mut self, rhs: &Self) { impl_1other_nowrap_mut!(self, rhs, mul_assign) }
+}
+
+impl ops::DivAssign<&Self> for DynNum {
+ fn div_assign(&mut self, rhs: &Self) { impl_1other_nowrap_mut!(self, rhs, div_assign) }
+}
+
+impl ops::RemAssign<&Self> for DynNum {
+ fn rem_assign(&mut self, rhs: &Self) { impl_1other_nowrap_mut!(self, rhs, rem_assign) }
+}
+
+impl ops::Neg for &DynNum {
+ type Output = DynNum;
+ fn neg(self) -> Self::Output { impl_0arg_wrap!(self, neg) }
+}
+
+impl ops::Add for &DynNum {
+ type Output = DynNum;
+ fn add(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, add) }
+}
+
+impl ops::Sub for &DynNum {
+ type Output = DynNum;
+ fn sub(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, sub) }
+}
+
+impl ops::Mul for &DynNum {
+ type Output = DynNum;
+ fn mul(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, mul) }
+}
+
+impl ops::Div for &DynNum {
+ type Output = DynNum;
+ fn div(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, div) }
+}
+
+impl ops::Rem for &DynNum {
+ type Output = DynNum;
+ fn rem(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, rem) }
+}
+
+/*
+impl ops::Add<&&Rational> for &Rational {
+
+}
+
+impl ops::Sub<&&Rational> for &Rational {
+
+}
+
+impl ops::Mul<&&Rational> for &Rational {
+
+}
+
+impl ops::Div<&&Rational> for &Rational {
+
+}
+
+impl ops::Rem<&&Rational> for &Rational {
+
+}
+*/
diff --git a/src/numbers/gfixed.rs b/src/numbers/gfixed.rs
index e37b928..18e8f8b 100644
--- a/src/numbers/gfixed.rs
+++ b/src/numbers/gfixed.rs
@@ -187,7 +187,7 @@ impl Num for GuardedFixed {
}
impl PartialEq for GuardedFixed {
- fn eq(&self, other: &GuardedFixed) -> bool {
+ fn eq(&self, other: &Self) -> bool {
if &(&self.0 - &other.0).abs() < get_factor_cmp() {
return true;
} else {
@@ -197,13 +197,13 @@ impl PartialEq for GuardedFixed {
}
impl PartialOrd for GuardedFixed {
- fn partial_cmp(&self, other: &GuardedFixed) -> Option {
+ fn partial_cmp(&self, other: &Self) -> Option {
return Some(self.cmp(other));
}
}
impl Ord for GuardedFixed {
- fn cmp(&self, other: &GuardedFixed) -> Ordering {
+ fn cmp(&self, other: &Self) -> Ordering {
if self.eq(other) {
return Ordering::Equal;
} else {
diff --git a/src/numbers/mod.rs b/src/numbers/mod.rs
index 1b45933..acd2d68 100644
--- a/src/numbers/mod.rs
+++ b/src/numbers/mod.rs
@@ -30,6 +30,9 @@ mod rational_rug;
//#[cfg(target_arch = "wasm32")]
mod rational_num;
+//#[cfg(target_arch = "wasm32")]
+mod dynnum;
+
use num_traits::{NumAssignRef, NumRef};
#[cfg(not(target_arch = "wasm32"))]
@@ -153,6 +156,8 @@ impl DeserializeWith, Option for Rational {
}
impl ops::DivAssign<&Self> for Rational {
- fn div_assign(&mut self, rhs: &Self) { self.0 /= &rhs.0 }
+ fn div_assign(&mut self, rhs: &Self) { self.0 /= &rhs.0; }
}
impl ops::RemAssign<&Self> for Rational {
diff --git a/src/stv/wasm.rs b/src/stv/wasm.rs
index 2f528e0..d910037 100644
--- a/src/stv/wasm.rs
+++ b/src/stv/wasm.rs
@@ -20,6 +20,7 @@
use crate::constraints::Constraints;
use crate::election::{CandidateState, CountState, Election, StageKind};
+//use crate::numbers::{DynNum, Fixed, GuardedFixed, NativeFloat64, Number, NumKind, Rational};
use crate::numbers::{Fixed, GuardedFixed, NativeFloat64, Number, Rational};
use crate::parser::blt;
use crate::stv;
@@ -49,6 +50,12 @@ macro_rules! wasm_error {
// Init
+/// Wrapper for [DynNum::set_kind]
+//#[wasm_bindgen]
+//pub fn dynnum_set_kind(kind: NumKind) {
+// DynNum::set_kind(kind);
+//}
+
/// Wrapper for [Fixed::set_dps]
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub fn fixed_set_dps(dps: usize) {
@@ -209,6 +216,7 @@ macro_rules! impl_type {
}}
}
+//impl_type!(DynNum);
impl_type!(Fixed);
impl_type!(GuardedFixed);
impl_type!(NativeFloat64);