Implement rational numbers in WebAssembly using num-bigint
This commit is contained in:
parent
2793088e12
commit
2428fcb4ed
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -239,6 +239,39 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -257,7 +290,10 @@ dependencies = [
|
|||||||
"csv",
|
"csv",
|
||||||
"flate2",
|
"flate2",
|
||||||
"git-version",
|
"git-version",
|
||||||
|
"num-bigint",
|
||||||
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"paste",
|
||||||
"rug",
|
"rug",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@ -268,6 +304,12 @@ version = "3.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d"
|
checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -13,7 +13,11 @@ num-traits = "0.2"
|
|||||||
wasm-bindgen = "0.2.74"
|
wasm-bindgen = "0.2.74"
|
||||||
|
|
||||||
# Only for WebAssembly - include here for syntax highlighting
|
# Only for WebAssembly - include here for syntax highlighting
|
||||||
|
#[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.6"
|
||||||
|
num-bigint = "0.4.0"
|
||||||
|
num-rational = "0.4.0"
|
||||||
|
paste = "1.0.5"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
csv = "1.1.6"
|
csv = "1.1.6"
|
||||||
|
@ -23,24 +23,24 @@
|
|||||||
document.getElementById('output').append("\n");
|
document.getElementById('output').append("\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
var { CountStateFloat64, STVOptions, count_init_float64, count_one_stage_float64, election_from_blt_float64, make_and_print_result_float64 } = wasm_bindgen;
|
var wasm = wasm_bindgen;
|
||||||
async function run() {
|
async function run() {
|
||||||
await wasm_bindgen("opentally_bg.wasm");
|
await wasm_bindgen("opentally_bg.wasm");
|
||||||
|
|
||||||
let stv_opts = STVOptions.new(2, "one_round");
|
let stv_opts = wasm.STVOptions.new(2, "one_round");
|
||||||
|
|
||||||
let election = election_from_blt_float64(election_data);
|
let election = wasm.election_from_blt_Rational(election_data);
|
||||||
let state = CountStateFloat64.new(election);
|
let state = wasm.CountStateRational.new(election);
|
||||||
|
|
||||||
count_init_float64(state, stv_opts);
|
wasm.count_init_Rational(state, stv_opts);
|
||||||
make_and_print_result_float64(1, state);
|
wasm.make_and_print_result_Rational(1, state);
|
||||||
|
|
||||||
for (let stage_num = 2;; stage_num++) {
|
for (let stage_num = 2;; stage_num++) {
|
||||||
let is_done = count_one_stage_float64(state, stv_opts);
|
let is_done = wasm.count_one_stage_Rational(state, stv_opts);
|
||||||
if (is_done) {
|
if (is_done) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
make_and_print_result_float64(stage_num, state);
|
wasm.make_and_print_result_Rational(stage_num, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
|
@ -18,7 +18,10 @@
|
|||||||
mod native;
|
mod native;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
mod rational;
|
mod rational_rug;
|
||||||
|
|
||||||
|
//#[cfg(target_arch = "wasm32")]
|
||||||
|
mod rational_num;
|
||||||
|
|
||||||
use num_traits::{NumAssignRef, NumRef};
|
use num_traits::{NumAssignRef, NumRef};
|
||||||
|
|
||||||
@ -49,4 +52,7 @@ pub trait Number: NumRef + NumAssignRef + ops::Neg<Output=Self> + Ord + Assign +
|
|||||||
pub use self::native::NativeFloat64;
|
pub use self::native::NativeFloat64;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use self::rational::Rational;
|
pub use self::rational_rug::Rational;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub use self::rational_num::Rational;
|
||||||
|
303
src/numbers/rational_num.rs
Normal file
303
src/numbers/rational_num.rs
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/* 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, Number};
|
||||||
|
|
||||||
|
use num_bigint::{BigInt, ParseBigIntError};
|
||||||
|
use num_rational::BigRational; // TODO: Can we do Ratio<IBig> and combine with ibig?
|
||||||
|
use num_traits::{Num, One, Signed, Zero};
|
||||||
|
|
||||||
|
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
pub struct Rational(BigRational);
|
||||||
|
|
||||||
|
impl Number for Rational {
|
||||||
|
fn new() -> Self { Self(BigRational::zero()) }
|
||||||
|
|
||||||
|
fn from(n: usize) -> Self { Self(BigRational::from_integer(BigInt::from(n))) }
|
||||||
|
|
||||||
|
fn floor_mut(&mut self, dps: usize) {
|
||||||
|
if dps == 0 {
|
||||||
|
self.0 = self.0.floor();
|
||||||
|
} else {
|
||||||
|
let factor = BigRational::from_integer(BigInt::from(10)).pow(dps as i32);
|
||||||
|
self.0 *= &factor;
|
||||||
|
self.0 = self.0.floor();
|
||||||
|
self.0 /= factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Num for Rational {
|
||||||
|
//type FromStrRadixErr = ParseRatioError;
|
||||||
|
type FromStrRadixErr = ParseBigIntError;
|
||||||
|
|
||||||
|
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||||
|
//match BigRational::from_str_radix(str, radix) {
|
||||||
|
match BigInt::from_str_radix(str, radix) {
|
||||||
|
Ok(value) => Ok(Self(BigRational::from_integer(value))),
|
||||||
|
Err(err) => Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assign for Rational {
|
||||||
|
fn assign(&mut self, src: Self) { self.0 = src.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assign<&Rational> for Rational {
|
||||||
|
fn assign(&mut self, src: &Rational) { self.0 = src.0.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Rational {
|
||||||
|
fn clone(&self) -> Self { Self(self.0.clone()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Rational {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if let Some(precision) = f.precision() {
|
||||||
|
if precision == 0 {
|
||||||
|
let result = self.0.round().to_integer().to_string();
|
||||||
|
return f.write_str(&result);
|
||||||
|
} else {
|
||||||
|
let base = BigInt::from(10).pow(precision as u32);
|
||||||
|
let mut result = (&self.0 * base).abs().round().to_integer().to_string();
|
||||||
|
|
||||||
|
let should_add_minus = (self.0 < BigRational::zero()) && result != "0";
|
||||||
|
|
||||||
|
// Add leading 0s
|
||||||
|
result = format!("{0:0>1$}", result, precision + 1);
|
||||||
|
|
||||||
|
// Add the decimal point
|
||||||
|
result.insert(result.len() - precision, '.');
|
||||||
|
|
||||||
|
// Add the sign
|
||||||
|
if should_add_minus {
|
||||||
|
result.insert(0, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.write_str(&result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return self.0.fmt(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl One for Rational {
|
||||||
|
fn one() -> Self { Self(BigRational::one()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zero for Rational {
|
||||||
|
fn zero() -> Self { Self::new() }
|
||||||
|
fn is_zero(&self) -> bool { self.0.is_zero() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Rational {}
|
||||||
|
impl PartialEq for Rational {
|
||||||
|
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Rational {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering { self.0.partial_cmp(&other.0).unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Rational {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.0.partial_cmp(&other.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Neg for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn neg(self) -> Self::Output { Self(-self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn add(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn sub(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn mul(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn div(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
|
||||||
|
fn rem(self, _rhs: Self) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add<&Rational> for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn add(self, rhs: &Rational) -> Self::Output { Self(self.0 + &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<&Rational> for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn sub(self, _rhs: &Rational) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<&Rational> for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn mul(self, rhs: &Rational) -> Self::Output { Rational(self.0 * &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div<&Rational> for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn div(self, rhs: &Rational) -> Self::Output { Rational(self.0 / &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem<&Rational> for Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn rem(self, _rhs: &Rational) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::AddAssign for Rational {
|
||||||
|
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::SubAssign for Rational {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::MulAssign for Rational {
|
||||||
|
fn mul_assign(&mut self, _rhs: Self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::DivAssign for Rational {
|
||||||
|
fn div_assign(&mut self, rhs: Self) {
|
||||||
|
self.0 /= &rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::RemAssign for Rational {
|
||||||
|
fn rem_assign(&mut self, _rhs: Self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::AddAssign<&Rational> for Rational {
|
||||||
|
fn add_assign(&mut self, rhs: &Rational) { self.0 += &rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::SubAssign<&Rational> for Rational {
|
||||||
|
fn sub_assign(&mut self, rhs: &Rational) { self.0 -= &rhs.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::MulAssign<&Rational> for Rational {
|
||||||
|
fn mul_assign(&mut self, _rhs: &Rational) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::DivAssign<&Rational> for Rational {
|
||||||
|
fn div_assign(&mut self, _rhs: &Rational) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::RemAssign<&Rational> for Rational {
|
||||||
|
fn rem_assign(&mut self, _rhs: &Rational) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Neg for &Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn neg(self) -> Self::Output { Rational(-&self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add<&Rational> for &Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn add(self, _rhs: &Rational) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<&Rational> for &Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn sub(self, rhs: &Rational) -> Self::Output { Rational(&self.0 - &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<&Rational> for &Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn mul(self, _rhs: &Rational) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div<&Rational> for &Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn div(self, rhs: &Rational) -> Self::Output { Rational(&self.0 / &rhs.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem<&Rational> for &Rational {
|
||||||
|
type Output = Rational;
|
||||||
|
fn rem(self, _rhs: &Rational) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
impl ops::Add<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Div<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Rem<&&NativeFloat> for &NativeFloat {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
103
src/stv/wasm.rs
103
src/stv/wasm.rs
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::election::{Candidate, CandidateState, CountCard, CountState, CountStateOrRef, Election, StageResult};
|
use crate::election::{Candidate, CandidateState, CountCard, CountState, CountStateOrRef, Election, StageResult};
|
||||||
use crate::numbers::{NativeFloat64, Number};
|
use crate::numbers::{NativeFloat64, Number, Rational};
|
||||||
use crate::stv;
|
use crate::stv;
|
||||||
|
|
||||||
extern crate console_error_panic_hook;
|
extern crate console_error_panic_hook;
|
||||||
@ -37,29 +37,82 @@ macro_rules! cprintln {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper macros for making functions
|
||||||
|
|
||||||
|
macro_rules! impl_type {
|
||||||
|
($type:ident) => { paste::item! {
|
||||||
// Exported functions
|
// Exported functions
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn election_from_blt_float64(text: String) -> ElectionFloat64 {
|
#[allow(non_snake_case)]
|
||||||
|
pub fn [<election_from_blt_$type>](text: String) -> [<Election$type>] {
|
||||||
// Install panic! hook
|
// Install panic! hook
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
let election: Election<NativeFloat64> = Election::from_blt(text.lines().map(|s| s.to_string()).into_iter());
|
let election: Election<$type> = Election::from_blt(text.lines().map(|s| s.to_string()).into_iter());
|
||||||
return ElectionFloat64(election);
|
return [<Election$type>](election);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn count_init_float64(state: &mut CountStateFloat64, opts: &STVOptions) {
|
#[allow(non_snake_case)]
|
||||||
|
pub fn [<count_init_$type>](state: &mut [<CountState$type>], opts: &STVOptions) {
|
||||||
stv::count_init(&mut state.0, &opts.0);
|
stv::count_init(&mut state.0, &opts.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn count_one_stage_float64(state: &mut CountStateFloat64, opts: &STVOptions) -> bool {
|
#[allow(non_snake_case)]
|
||||||
|
pub fn [<count_one_stage_$type>](state: &mut [<CountState$type>], opts: &STVOptions) -> bool {
|
||||||
return stv::count_one_stage(&mut state.0, &opts.0);
|
return stv::count_one_stage(&mut state.0, &opts.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reporting
|
// Reporting
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn [<make_and_print_result_$type>](stage_num: usize, state: &[<CountState$type>]) {
|
||||||
|
let result = StageResult {
|
||||||
|
kind: state.0.kind,
|
||||||
|
title: &state.0.title,
|
||||||
|
logs: state.0.logger.render(),
|
||||||
|
state: CountStateOrRef::from(&state.0),
|
||||||
|
};
|
||||||
|
print_stage(stage_num, &result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper structs
|
||||||
|
// Required as we cannot specify &'static in wasm-bindgen: issue #1187
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct [<CountState$type>](CountState<'static, $type>);
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl [<CountState$type>] {
|
||||||
|
pub fn new(election: &[<Election$type>]) -> Self {
|
||||||
|
return [<CountState$type>](CountState::new(election.as_static()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct [<Election$type>](Election<$type>);
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl [<Election$type>] {
|
||||||
|
pub fn seats(&self) -> usize { self.0.seats }
|
||||||
|
|
||||||
|
fn as_static(&self) -> &'static Election<$type> {
|
||||||
|
// Need to have this as we cannot specify &'static in wasm-bindgen: issue #1187
|
||||||
|
unsafe {
|
||||||
|
let ptr = &self.0 as *const Election<$type>;
|
||||||
|
&*ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_type!(Rational);
|
||||||
|
impl_type!(NativeFloat64);
|
||||||
|
|
||||||
|
// Reporting
|
||||||
|
|
||||||
fn print_candidates<'a, N: 'a + Number, I: Iterator<Item=(&'a Candidate, &'a CountCard<'a, N>)>>(candidates: I) {
|
fn print_candidates<'a, N: 'a + Number, I: Iterator<Item=(&'a Candidate, &'a CountCard<'a, N>)>>(candidates: I) {
|
||||||
for (candidate, count_card) in candidates {
|
for (candidate, count_card) in candidates {
|
||||||
if count_card.state == CandidateState::ELECTED {
|
if count_card.state == CandidateState::ELECTED {
|
||||||
@ -101,44 +154,6 @@ fn print_stage<N: Number>(stage_num: usize, result: &StageResult<N>) {
|
|||||||
cprintln!("");
|
cprintln!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn make_and_print_result_float64(stage_num: usize, state: &CountStateFloat64) {
|
|
||||||
let result = StageResult {
|
|
||||||
kind: state.0.kind,
|
|
||||||
title: &state.0.title,
|
|
||||||
logs: state.0.logger.render(),
|
|
||||||
state: CountStateOrRef::from(&state.0),
|
|
||||||
};
|
|
||||||
print_stage(stage_num, &result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper structs
|
|
||||||
// Required as we cannot specify &'static in wasm-bindgen: issue #1187
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct CountStateFloat64(CountState<'static, NativeFloat64>);
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl CountStateFloat64 {
|
|
||||||
pub fn new(election: &ElectionFloat64) -> Self {
|
|
||||||
return CountStateFloat64(CountState::new(election.as_static()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct ElectionFloat64(Election<NativeFloat64>);
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl ElectionFloat64 {
|
|
||||||
pub fn seats(&self) -> usize { self.0.seats }
|
|
||||||
|
|
||||||
fn as_static(&self) -> &'static Election<NativeFloat64> {
|
|
||||||
// Need to have this as we cannot specify &'static in wasm-bindgen: issue #1187
|
|
||||||
unsafe {
|
|
||||||
let ptr = &self.0 as *const Election<NativeFloat64>;
|
|
||||||
&*ptr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct STVOptions(stv::STVOptions<'static>);
|
pub struct STVOptions(stv::STVOptions<'static>);
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
Loading…
Reference in New Issue
Block a user