aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-03-07 10:17:40 -0700
committerMelody Horn <melody@boringcactus.com>2021-03-07 10:17:40 -0700
commitd5083f4cce47567644fd1b2c5923e5d0dcd98d44 (patch)
treeca625bf36a221bef5fd66cec7fb793a36ebad56b /src
parentc8cfeabc011bfabb6303023a969155ded926d95c (diff)
downloadhope-d5083f4cce47567644fd1b2c5923e5d0dcd98d44.tar.gz
hope-d5083f4cce47567644fd1b2c5923e5d0dcd98d44.zip
don't round-trip everything through strings!!!
Diffstat (limited to 'src')
-rw-r--r--src/basic_actors.rs3
-rw-r--r--src/main.rs3
-rw-r--r--src/number.rs54
3 files changed, 34 insertions, 26 deletions
diff --git a/src/basic_actors.rs b/src/basic_actors.rs
index da391cf..130c1e2 100644
--- a/src/basic_actors.rs
+++ b/src/basic_actors.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use std::convert::TryInto;
use std::sync::mpsc::{SyncSender, Receiver};
use crate::actor::{Value, Type, Actorful, Slot};
@@ -98,7 +99,7 @@ impl Actorful for RepeatValue {
if let Value::Number(count) = count {
// TODO figure out what a smart thing to do would be here instead
// this API design is deliberately suboptimal because i'd like to not do it
- let count: usize = format!("{}", count).parse().unwrap();
+ let count: usize = count.try_into().unwrap();
let vec = vec![value; count];
output_channels["List"].send(Value::List(vec)).unwrap();
}
diff --git a/src/main.rs b/src/main.rs
index 6bf920b..8617d6a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
+use std::convert::TryInto;
use std::time::Duration;
use minifb::{Key, Window, WindowOptions, MouseMode};
@@ -119,7 +120,7 @@ fn main() {
let u32_data: Vec<u32> = data.into_iter()
.map(|x| {
if let actor::Value::Number(x) = x {
- format!("{}", x).parse().unwrap()
+ x.try_into().unwrap()
} else {
panic!("bruh")
}
diff --git a/src/number.rs b/src/number.rs
index 94a67f1..5ea7949 100644
--- a/src/number.rs
+++ b/src/number.rs
@@ -1,10 +1,12 @@
use std::cmp::max;
-use std::fmt::{Display, Formatter, Result as FormatResult};
+use std::convert::TryFrom;
+use std::num::TryFromIntError;
use std::ops::Add;
#[derive(Clone)]
pub struct Number {
- pub integer_part: String,
+ // least significant first
+ pub integer_part: Vec<usize>,
}
macro_rules! int_conv {
@@ -12,7 +14,19 @@ macro_rules! int_conv {
impl From<$t> for Number {
fn from(x: $t) -> Number {
Number {
- integer_part: x.to_string(),
+ integer_part: vec![x as usize],
+ }
+ }
+ }
+
+ impl TryFrom<Number> for $t {
+ type Error = TryFromIntError;
+
+ fn try_from(x: Number) -> Result<$t, TryFromIntError> {
+ if x.integer_part.len() > 1 {
+ <u8>::try_from(-1).map(|_| 0)
+ } else {
+ <$t>::try_from(x.integer_part[0]).map_err(|_| <u8>::try_from(-1).unwrap_err())
}
}
}
@@ -21,33 +35,25 @@ macro_rules! int_conv {
int_conv!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
-impl Display for Number {
- fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
- f.write_str(&self.integer_part)
- }
-}
-
impl Add for Number {
type Output = Number;
fn add(self, rhs: Self) -> Self::Output {
let longest_ipart_len = max(self.integer_part.len(), rhs.integer_part.len());
- let self_padded = format!("{:0>len$}", self.integer_part, len=longest_ipart_len);
- let rhs_padded = format!("{:0>len$}", rhs.integer_part, len=longest_ipart_len);
- let mut result_ipart_reverse = "".to_string();
- let mut carry: u8 = 0;
- for (self_char, rhs_char) in self_padded.chars().rev().zip(rhs_padded.chars().rev()) {
- let self_char_val = self_char.to_digit(10).unwrap() as u8;
- let rhs_char_val = rhs_char.to_digit(10).unwrap() as u8;
- let sum = self_char_val + rhs_char_val + carry;
- let sum_last_digit = (sum % 10).to_string().chars().next().unwrap();
- carry = sum / 10;
- result_ipart_reverse.push(sum_last_digit);
- }
- if carry > 0 {
- result_ipart_reverse.push_str(&carry.to_string());
+ let mut result_ipart = vec![];
+ let mut carry: usize = 0;
+ for i in 0..longest_ipart_len {
+ let self_part = self.integer_part.get(i).copied().unwrap_or(0);
+ let rhs_part = rhs.integer_part.get(i).copied().unwrap_or(0);
+ let (half_sum, early_carry) = self_part.overflowing_add(rhs_part);
+ let (full_sum, late_carry) = half_sum.overflowing_add(carry);
+ carry = if early_carry || late_carry {
+ 1
+ } else {
+ 0
+ };
+ result_ipart.push(full_sum);
}
- let result_ipart = result_ipart_reverse.chars().rev().collect();
Number {
integer_part: result_ipart,
}