use std::iter::once;
use crate::common::{
base32::{BitsToBase32, FromBase32, StrEx, ToBase32},
bit_vec::BitVec,
};
pub type U224 = [u32; 7];
pub trait U224Ex {
fn parity_bit(self) -> u8;
}
impl U224Ex for &U224 {
fn parity_bit(self) -> u8 {
let r = self.iter().fold(0, |a, b| a ^ b).count_ones() & 1;
r as u8
}
}
impl ToBase32 for &U224 {
fn to_base32(self) -> String {
let (result, BitVec { value, len }) = self
.iter()
.map(|x| BitVec::new(*x, 32))
.chain(once(BitVec::new(self.parity_bit() as u32, 1)))
.bits_to_base32();
assert_eq!(len, 0);
assert_eq!(value, 0);
assert_eq!(result.len(), 45);
result
}
}
impl FromBase32 for U224 {
fn from_base32(i: &str) -> Option<Self> {
let (vec, BitVec { value, len }) = i.from_base32()?;
if vec.len() != 7 {
return None;
}
assert_eq!(len, 1);
assert_eq!(value | 1, 1);
let mut result = U224::default();
result.copy_from_slice(&vec);
if value != result.parity_bit() as u64 {
return None;
}
Some(result)
}
}
#[cfg(test)]
mod tests {
use wasm_bindgen_test::wasm_bindgen_test;
use super::{U224Ex, U224};
use crate::common::base32::{StrEx, ToBase32};
#[wasm_bindgen_test]
#[test]
fn test_parity() {
assert_eq!([0; 7].parity_bit(), 0);
assert_eq!([0xFFFF_FFFF; 7].parity_bit(), 0);
assert_eq!([0x8000_0000; 7].parity_bit(), 1);
assert_eq!([0, 1, 2, 3, 4, 5, 6].parity_bit(), 1);
}
#[wasm_bindgen_test]
#[test]
fn test() {
fn f(a: [u32; 7], b: &str) {
assert_eq!(a.to_base32(), *b);
assert_eq!(b.from_base32(), Some(a));
}
f([0; 7], "000000000000000000000000000000000000000000000");
f(
[1, 0, 0, 0, 0, 0, 0],
"10000000000000000000000000000000000000000000g",
);
f(
[3, 0, 0, 0, 0, 0, 0],
"300000000000000000000000000000000000000000000",
);
f(
[0b11_00010, 0, 0, 0, 0, 0, 0],
"23000000000000000000000000000000000000000000g",
);
f(
[0b11_00110, 0, 0, 0, 0, 0, 0],
"630000000000000000000000000000000000000000000",
);
f(
[0b110_00101_00100, 0, 0, 0, 0, 0, 0],
"45600000000000000000000000000000000000000000g",
);
f(
[0b110_00101_01100, 0, 0, 0, 0, 0, 0],
"c56000000000000000000000000000000000000000000",
);
f(
[0b1010_01001_01000_00111, 0, 0, 0, 0, 0, 0],
"789a00000000000000000000000000000000000000000",
);
f(
[0b1010_01001_01000_01111, 0, 0, 0, 0, 0, 0],
"f89a0000000000000000000000000000000000000000g",
);
f(
[0b1111_01110_01101_01100_01011, 0, 0, 0, 0, 0, 0],
"bcdef000000000000000000000000000000000000000g",
);
f(
[0b1111_01110_01101_01100_11011, 0, 0, 0, 0, 0, 0],
"vcdef0000000000000000000000000000000000000000",
);
f(
[0b10101_10100_10011_10010_10001_10000, 0, 0, 0, 0, 0, 0],
"ghjkmn00000000000000000000000000000000000000g",
);
f(
[
0b10101_10100_10011_10010_10001_10000,
0,
0,
0,
0,
0,
0x1000_0000,
],
"ghjkmn000000000000000000000000000000000000001",
);
f(
[0b11011_11010_11001_11000_10111_10110, 0, 0, 0, 0, 0, 0],
"pqrstv00000000000000000000000000000000000000g",
);
f(
[
0b11011_11010_11001_11000_10111_10110,
0,
0,
0,
0,
0,
0x8000_0000,
],
"pqrstv000000000000000000000000000000000000008",
);
f(
[
0b00_11101_11110_11111_11110_11101_11100,
0b111,
0,
0,
0,
0,
0,
],
"wxyzyxw0000000000000000000000000000000000000g",
);
f(
[
0b00_11101_11110_11111_11110_11101_11100,
0b111,
0,
0,
0,
0,
0x6000_0000,
],
"wxyzyxw0000000000000000000000000000000000000p",
);
f(
[
0xC000_0000,
0b0101_10110_10111_11000_11001_11010_110,
1,
0,
0,
0,
0,
],
"000000vtsrqpn00000000000000000000000000000000",
);
f(
[
0xC000_0001,
0b0101_10110_10111_11000_11001_11010_110,
1,
0,
0,
0,
0,
],
"100000vtsrqpn0000000000000000000000000000000g",
);
f(
[
0b_01_10010_00100_01101_00001_11011_00001, 0b_1110_11001_01010_01100_11001_00100_010, 0b0_11000_11111_11110_01100_10000_10111_0, 0b_010_11101_01101_00101_01010_10001_0000, 0b_10110_10110_00110_11101_11000_01001_01, 0b_11_01100_01101_10101_01011_01111_10101, 0b_0011_01100_01010_00001_00111_01001_100, ],
"1v1d4j94scaseqgcyzr0ha5dxa9rx6ppnfbndck971ac3",
);
f(
[
0b_01_10010_00100_01101_00001_11011_00011, 0b_1110_11001_01010_01100_11001_00100_010, 0b0_11000_11111_11110_01100_10000_10111_0, 0b_010_11101_01101_00101_01010_10001_0000, 0b_10110_10110_00110_11101_11000_01001_01, 0b_11_01100_01101_10101_01011_01111_10101, 0b_0011_01100_01010_00001_00111_01001_100, ],
"3v1d4j94scaseqgcyzr0ha5dxa9rx6ppnfbndck971ack",
);
}
#[wasm_bindgen_test]
#[test]
fn invalid_str_test() {
assert_eq!("01".from_base32::<U224>(), None);
assert!("3v1d4j94scaseqgcyzr0ha5dxa9rx6ppnfbndck971ac0"
.from_base32::<U224>()
.is_none());
assert!("1v1d4j94scaseqgcyzr0ha5dxa9rx6ppnfbndck971ac0"
.from_base32::<U224>()
.is_some());
}
}