parent
c070ec8eae
commit
dde79520a1
@ -0,0 +1,503 @@ |
||||
/* 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 <https://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
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}; |
||||
|
||||
#[wasm_bindgen] |
||||
pub enum NumKind { |
||||
Fixed, |
||||
GuardedFixed, |
||||
NativeFloat64, |
||||
Rational, |
||||
} |
||||
|
||||
static mut KIND: NumKind = NumKind::Fixed; |
||||
|
||||
#[inline] |
||||
fn get_kind() -> &'static NumKind { |
||||
unsafe { |
||||
return &KIND; |
||||
} |
||||
} |
||||
|
||||
pub union DynNum { |
||||
fixed: ManuallyDrop<Fixed>, |
||||
gfixed: ManuallyDrop<GuardedFixed>, |
||||
float64: NativeFloat64, |
||||
rational: ManuallyDrop<Rational>, |
||||
} |
||||
|
||||
impl DynNum { |
||||
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) } |
||||
} |
||||
|
||||
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<Self, Self::FromStrRadixErr> { |
||||
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<usize> 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<Ordering> { 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<Self> for &DynNum { |
||||
type Output = DynNum; |
||||
fn add(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, add) } |
||||
} |
||||
|
||||
impl ops::Sub<Self> for &DynNum { |
||||
type Output = DynNum; |
||||
fn sub(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, sub) } |
||||
} |
||||
|
||||
impl ops::Mul<Self> for &DynNum { |
||||
type Output = DynNum; |
||||
fn mul(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, mul) } |
||||
} |
||||
|
||||
impl ops::Div<Self> for &DynNum { |
||||
type Output = DynNum; |
||||
fn div(self, rhs: Self) -> Self::Output { impl_1other_wrap!(self, rhs, div) } |
||||
} |
||||
|
||||
impl ops::Rem<Self> 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 { |
||||
|
||||
} |
||||
*/ |
Loading…
Reference in new issue