From b4f097278c79a705470bee65dca295ac011809d4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 10 Oct 2020 23:29:52 +0100 Subject: [PATCH] drop js tests We are going to move the nontrivial zcoord stuff into Rust Signed-off-by: Ian Jackson --- Makefile | 16 +-- zcoord/zcoord.rs | 366 +++++++++++++++++++++++++---------------------- 2 files changed, 201 insertions(+), 181 deletions(-) diff --git a/Makefile b/Makefile index 1c927579..63e52690 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ WASM := wasm32-unknown-unknown #---------- toplevel aggregate targets ---------- -check: stamp/cargo.check js-check +check: stamp/cargo.check @echo 'All tests passed.' debug release:: %: stamp/cargo.% assets extra-% @@ -184,15 +184,15 @@ templates/%.js: tsc-wrap tsconfig.json ./tsc-wrap $@ tsconfig.json $(filter %.ts,$^) templates/script.js: $(TS_SRC_FILES) -templates/bigfloat-tests.js: templates/bigfloat.ts \ - templates/bigfloat-tests.ts templates/bigfloat-tests-auto.ts +#templates/bigfloat-tests.js: templates/bigfloat.ts \ +# templates/bigfloat-tests.ts templates/bigfloat-tests-auto.ts -templates/bigfloat-tests-auto.ts: extract-bf-tests src/bigfloat.rs - ./$^ >$@.tmp && mv -f $@.tmp $@ +#templates/bigfloat-tests-auto.ts: extract-bf-tests src/bigfloat.rs +# ./$^ >$@.tmp && mv -f $@.tmp $@ -js-check: templates/bigfloat-tests.js - nodejs <$< - @echo 'nodejs check $< ok' +#js-check: templates/bigfloat-tests.js +# nodejs <$< +# @echo 'nodejs check $< ok' templates/otter_wasm.ns.d.ts: $(WASM_PACKED)/otter_wasm.d.ts Makefile set -e; exec >$@.tmp; \ diff --git a/zcoord/zcoord.rs b/zcoord/zcoord.rs index 3fe70962..1e114160 100644 --- a/zcoord/zcoord.rs +++ b/zcoord/zcoord.rs @@ -13,9 +13,10 @@ use fehler::{throw, throws}; use serde::{Serialize, Serializer, Deserialize}; use thiserror::Error; +//---------- core definitions ---------- + const BITS_PER_DIGIT : usize = 5; const DIGITS_PER_LIMB : usize = 10; -const DEFAULT_TEXT : &[u8] = b"gggggggggg"; const DELTA : LimbVal = Wrapping(0x4000_0000); const ZERO : LimbVal = Wrapping(0); @@ -34,6 +35,196 @@ pub struct ZCoord(innards::Innards); type RawLimbVal = u64; type LimbVal = Wrapping; +#[derive(Error,Clone,Copy,Debug)] +#[error("error parsing zcoord (z value)")] +pub struct ParseError; + +//---------- Mutabel ---------- + +#[derive(Clone,Debug)] +pub struct Mutable { + limbs: Vec, +} + +impl ZCoord { + pub fn clone_mut(&self) -> Mutable { + let tail = self.tail(); + let nlimbs = (tail.len() + 1) / TEXT_PER_LIMB; + let mut limbs = Vec::with_capacity(nlimbs+2); + for lt in tail.chunks(TEXT_PER_LIMB) { + let s = str::from_utf8(<[0..DIGITS_PER_LIMB]).unwrap(); + let v = RawLimbVal::from_str_radix(s, 1 << BITS_PER_DIGIT).unwrap(); + limbs.push(Wrapping(v)); + } + Mutable { limbs } + } +} + +#[derive(Error,Debug,Copy,Clone,Serialize,Deserialize)] +#[error("Z coordinate overflow")] +pub struct Overflow; + +impl From for Overflow { + fn from(_: TryFromIntError) -> Overflow { Overflow } +} + +impl Mutable { + #[throws(Overflow)] + pub fn increment(&mut self) -> ZCoord { + 'attempt: loop { + let mut i = self.limbs.len() - 1; + let mut delta = DELTA; + + if (||{ + loop { + let nv = self.limbs[i] + delta; + self.limbs[i] = nv & LIMB_MASK; + if nv < LIMB_MODULUS { return Some(()) } + if i == 0 { return None } + i -= 1; + delta = ONE; + } + })() == Some(()) { break 'attempt } + + // undo + loop { + if i >= self.limbs.len() { break } + else if i == self.limbs.len()-1 { delta = DELTA; } + let nv = self.limbs[i] - delta; + self.limbs[i] = nv & LIMB_MASK; + i += 1; + } + self.limbs.push(ZERO); + self.limbs.push(ZERO); + } + self.repack()? + } + + #[throws(Overflow)] + pub fn repack(&self) -> ZCoord { self.try_into()? } +} + +//---------- main features of a Zcoord ---------- + +impl ZCoord { + pub fn as_str(&self) -> &str { + let tail = self.tail(); + str::from_utf8(tail).unwrap() + } + + pub fn to_string(&self) -> String { + self.as_str().to_string() + } +} + +impl Display for ZCoord { + #[throws(fmt::Error)] + fn fmt(&self, f: &mut Formatter) { + write!(f, "{}", self.as_str())? + } +} + +impl Debug for ZCoord { + #[throws(fmt::Error)] + fn fmt(&self, f: &mut Formatter) { + write!(f, r#"Bf""#)?; + ::fmt(self, f)?; + write!(f, r#"""#)?; + } +} + +impl Ord for ZCoord { + fn cmp(&self, other: &ZCoord) -> Ordering { + let at = self.tail(); + let bt = other.tail(); + at.cmp(bt) + } +} +impl PartialOrd for ZCoord { + fn partial_cmp(&self, other: &ZCoord) -> Option { + Some(self.cmp(other)) + } +} +impl Eq for ZCoord { +} +impl PartialEq for ZCoord { + fn eq(&self, other: &ZCoord) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl TryFrom<&str> for ZCoord { + type Error = ParseError; + #[throws(ParseError)] + fn try_from(s: &str) -> ZCoord { + ZCoord::from_str(s).ok_or(ParseError)? + } +} + +impl Serialize for ZCoord { + fn serialize(&self, s: S) -> Result { + s.serialize_str(self.as_str()) + } +} + +//---------- construction of ZCoord contents --------- +// +// We can panic if this code is buggy, but not compromise safety. + +const DEFAULT_TEXT : &[u8] = b"gggggggggg"; + +impl Default for ZCoord { + fn default() -> ZCoord { + ZCoord::alloc_copy(DEFAULT_TEXT).unwrap() + } +} + +impl ZCoord { + #[throws(as Option)] + pub fn from_str(s: &str) -> Self { + let s = s.as_bytes(); + let nomlen = s.len() + 1; + if nomlen % TEXT_PER_LIMB !=0 { None? } + for lt in s.chunks(TEXT_PER_LIMB) { + if !lt[0..DIGITS_PER_LIMB].iter().all( + |c: &u8| { + (b'0'..=b'9').contains(&c) || + (b'a'..=b'v').contains(&c) + }) { None? } + match lt[DIGITS_PER_LIMB..] { [] | [b'_'] => (), _ => None? }; + } + if &s[s.len() - DIGITS_PER_LIMB.. ] == b"0000000000" { None? } + ZCoord::alloc_copy(s).ok()? + } +} + +impl TryFrom<&Mutable> for ZCoord { + type Error = Overflow; + #[throws(Overflow)] + fn try_from(m: &Mutable) -> ZCoord { + let taillen = (m.limbs.len() * TEXT_PER_LIMB - 1).try_into()?; + let mut bf = ZCoord::alloc(taillen); + let mut w = bf.tail_mut(); + for mut l in m.limbs.iter().cloned() { + if l >= LIMB_MODULUS { throw!(Overflow) }; + for p in w[0..DIGITS_PER_LIMB].rchunks_exact_mut(1) { + let v = (l & DIGIT_MASK).0 as u8; + p[0] = if v < 10 { b'0' + v } else { (b'a' - 10) + v }; + l >>= BITS_PER_DIGIT; + } + if let Some(p) = w.get_mut(DIGITS_PER_LIMB) { + *p = b'_'; + } else { + break; + } + w = &mut w[TEXT_PER_LIMB..]; + } + bf + } +} + +//---------- innards, unsafe ---------- + mod innards { use super::*; use std::mem::{self, align_of, size_of}; @@ -163,178 +354,7 @@ mod innards { } -impl Default for ZCoord { - fn default() -> ZCoord { - ZCoord::alloc_copy(DEFAULT_TEXT).unwrap() - } -} - -#[derive(Clone,Debug)] -pub struct Mutable { - limbs: Vec, -} - -impl TryFrom<&Mutable> for ZCoord { - type Error = Overflow; - #[throws(Overflow)] - fn try_from(m: &Mutable) -> ZCoord { - let taillen = (m.limbs.len() * TEXT_PER_LIMB - 1).try_into()?; - let mut bf = ZCoord::alloc(taillen); - let mut w = bf.tail_mut(); - for mut l in m.limbs.iter().cloned() { - if l >= LIMB_MODULUS { throw!(Overflow) }; - for p in w[0..DIGITS_PER_LIMB].rchunks_exact_mut(1) { - let v = (l & DIGIT_MASK).0 as u8; - p[0] = if v < 10 { b'0' + v } else { (b'a' - 10) + v }; - l >>= BITS_PER_DIGIT; - } - if let Some(p) = w.get_mut(DIGITS_PER_LIMB) { - *p = b'_'; - } else { - break; - } - w = &mut w[TEXT_PER_LIMB..]; - } - bf - } -} - -impl ZCoord { - #[throws(as Option)] - pub fn from_str(s: &str) -> Self { - let s = s.as_bytes(); - let nomlen = s.len() + 1; - if nomlen % TEXT_PER_LIMB !=0 { None? } - for lt in s.chunks(TEXT_PER_LIMB) { - if !lt[0..DIGITS_PER_LIMB].iter().all( - |c: &u8| { - (b'0'..=b'9').contains(&c) || - (b'a'..=b'v').contains(&c) - }) { None? } - match lt[DIGITS_PER_LIMB..] { [] | [b'_'] => (), _ => None? }; - } - if &s[s.len() - DIGITS_PER_LIMB.. ] == b"0000000000" { None? } - ZCoord::alloc_copy(s).ok()? - } - - pub fn clone_mut(&self) -> Mutable { - let tail = self.tail(); - let nlimbs = (tail.len() + 1) / TEXT_PER_LIMB; - let mut limbs = Vec::with_capacity(nlimbs+2); - for lt in tail.chunks(TEXT_PER_LIMB) { - let s = str::from_utf8(<[0..DIGITS_PER_LIMB]).unwrap(); - let v = RawLimbVal::from_str_radix(s, 1 << BITS_PER_DIGIT).unwrap(); - limbs.push(Wrapping(v)); - } - Mutable { limbs } - } - - pub fn as_str(&self) -> &str { - let tail = self.tail(); - str::from_utf8(tail).unwrap() - } - - pub fn to_string(&self) -> String { - self.as_str().to_string() - } -} - -#[derive(Error,Debug,Copy,Clone,Serialize,Deserialize)] -#[error("Z coordinate overflow")] -pub struct Overflow; - -impl From for Overflow { - fn from(_: TryFromIntError) -> Overflow { Overflow } -} - -impl Mutable { - #[throws(Overflow)] - pub fn increment(&mut self) -> ZCoord { - 'attempt: loop { - let mut i = self.limbs.len() - 1; - let mut delta = DELTA; - - if (||{ - loop { - let nv = self.limbs[i] + delta; - self.limbs[i] = nv & LIMB_MASK; - if nv < LIMB_MODULUS { return Some(()) } - if i == 0 { return None } - i -= 1; - delta = ONE; - } - })() == Some(()) { break 'attempt } - - // undo - loop { - if i >= self.limbs.len() { break } - else if i == self.limbs.len()-1 { delta = DELTA; } - let nv = self.limbs[i] - delta; - self.limbs[i] = nv & LIMB_MASK; - i += 1; - } - self.limbs.push(ZERO); - self.limbs.push(ZERO); - } - self.repack()? - } - - #[throws(Overflow)] - pub fn repack(&self) -> ZCoord { self.try_into()? } -} - -impl Display for ZCoord { - #[throws(fmt::Error)] - fn fmt(&self, f: &mut Formatter) { - write!(f, "{}", self.as_str())? - } -} -impl Debug for ZCoord { - #[throws(fmt::Error)] - fn fmt(&self, f: &mut Formatter) { - write!(f, r#"Bf""#)?; - ::fmt(self, f)?; - write!(f, r#"""#)?; - } -} - -impl Ord for ZCoord { - fn cmp(&self, other: &ZCoord) -> Ordering { - let at = self.tail(); - let bt = other.tail(); - at.cmp(bt) - } -} -impl PartialOrd for ZCoord { - fn partial_cmp(&self, other: &ZCoord) -> Option { - Some(self.cmp(other)) - } -} -impl Eq for ZCoord { -} -impl PartialEq for ZCoord { - fn eq(&self, other: &ZCoord) -> bool { - self.cmp(other) == Ordering::Equal - } -} - -#[derive(Error,Clone,Copy,Debug)] -#[error("error parsing zcoord (z value)")] -pub struct ParseError; - -impl TryFrom<&str> for ZCoord { - type Error = ParseError; - #[throws(ParseError)] - fn try_from(s: &str) -> ZCoord { - ZCoord::from_str(s).ok_or(ParseError)? - } -} - -impl Serialize for ZCoord { - fn serialize(&self, s: S) -> Result { - s.serialize_str(self.as_str()) - } -} +//---------- tests ---------- #[cfg(test)] mod test { -- 2.30.2