blockset-lib 0.7.0

BLOCKSET internal library
Documentation
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);
        //                      0  1  1  2  1  2  2 =  9
        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, // 1V1D4J
                0b_1110_11001_01010_01100_11001_00100_010, // 94SCAS
                0b0_11000_11111_11110_01100_10000_10111_0, // EQGCYZR
                0b_010_11101_01101_00101_01010_10001_0000, // 0HA5DX
                0b_10110_10110_00110_11101_11000_01001_01, // A9RX6PP
                0b_11_01100_01101_10101_01011_01111_10101, // NFBNDC
                0b_0011_01100_01010_00001_00111_01001_100, // K971AC3
            ],
            "1v1d4j94scaseqgcyzr0ha5dxa9rx6ppnfbndck971ac3",
        );
        f(
            [
                0b_01_10010_00100_01101_00001_11011_00011, // 3V1D4J
                0b_1110_11001_01010_01100_11001_00100_010, // 94SCAS
                0b0_11000_11111_11110_01100_10000_10111_0, // EQGCYZR
                0b_010_11101_01101_00101_01010_10001_0000, // 0HA5DX
                0b_10110_10110_00110_11101_11000_01001_01, // A9RX6PP
                0b_11_01100_01101_10101_01011_01111_10101, // NFBNDC
                0b_0011_01100_01010_00001_00111_01001_100, // K971AC3
            ],
            "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());
    }
}