use jam_codec::{Compact, Decode, Encode, Output};
use jam_codec_derive::{Decode as DecodeDerive, Encode as EncodeDerive};
use std::vec::Vec;
pub fn shuffle<T>(slice: &mut [T], seed: u64) {
let mut r = seed as usize;
for i in (1..slice.len()).rev() {
let j = r % (i + 1);
slice.swap(i, j);
r = r.wrapping_mul(6364793005) + 1;
}
}
trait Shuffle {
fn shuffle(self) -> Self;
}
impl<T> Shuffle for Vec<T> {
fn shuffle(mut self) -> Self {
let seed = self.len() as u64;
shuffle(&mut self[..], seed);
self
}
}
macro_rules! seq {
( $( $x:expr ),* ) => {
( $( $x ),* )
};
}
macro_rules! myvec {
($($elem:expr),* $(,)?) => {
{
let mut vec = Vec::new();
$(vec.push($elem);)*
vec
}
};
($elem:expr; $count:expr) => {
{
let mut vec = Vec::with_capacity($count);
vec.extend(std::iter::repeat($elem).take($count));
vec
}
};
($start:expr => $end:expr) => {
{
let mut v = Vec::new();
for i in $start..$end {
v.push(i);
}
v
}
};
}
#[derive(EncodeDerive, DecodeDerive, std::fmt::Debug, PartialEq)]
enum TestEnum<T> {
Dummy,
Foo(T),
Bar([T; 8]),
}
#[derive(Default)]
struct TestHarness {
dump: Vec<u8>,
}
impl TestHarness {
fn new() -> Self {
Self::default()
}
fn process<T: Encode + Decode + std::fmt::Debug + PartialEq>(&mut self, v: T) {
println!("-------------------------------");
println!("[{:#?}]", std::any::type_name::<T>());
let buf = v.encode();
println!("{}", hex::encode(&buf));
self.dump.extend_from_slice(&buf[..]);
let d = T::decode(&mut &buf[..]).unwrap();
assert_eq!(v, d);
}
fn process_bit_string_vl(&mut self, bit_string: &str) {
let buf = Compact(bit_string.len() as u64).encode();
print!("{}", hex::encode(&buf));
self.dump.extend_from_slice(&buf[..]);
self.process_bit_string_fl(bit_string);
}
fn process_bit_string_fl(&mut self, bit_string: &str) {
let mut buf = Vec::with_capacity((bit_string.len() + 7) / 8);
bit_string.as_bytes().chunks(8).for_each(|chunk| {
let octet = chunk.iter().enumerate().fold(0, |octet, (i, &bit)| {
let b = (bit == b'1') as u8;
octet | (b << i)
});
buf.push_byte(octet);
});
println!("{}", hex::encode(&buf));
self.dump.extend_from_slice(&buf[..]);
}
}
#[cfg(feature = "dump-test-vectors")]
impl Drop for TestHarness {
fn drop(&mut self) {
use std::{fs::File, io::Write};
const DUMP_FILE: &str = "vectors.bin";
let mut file = File::create(DUMP_FILE).unwrap();
file.write_all(&self.dump).unwrap()
}
}
#[test]
fn make_vectors() {
let mut t = TestHarness::new();
t.process(seq!(0xf1_u8, 0x1234_u16, 0xFF00cc11_u32, 0x1231092319023131_u64));
#[rustfmt::skip]
t.process(seq!{
0xf1_u8,
seq!{
seq!{
0x1234_u16,
0xFF00cc11_u32
},
seq!{
0x1231092319023131_u64,
seq! {
0x32_u8
},
3_i32
}
}
});
t.process([0_u8; 0]);
t.process([(3_u8, 0x3122_u16), (8, 0x3321), (9, 0x9973)]);
t.process(TryInto::<[u8; 16]>::try_into(myvec![0_u8 => 16].shuffle()).unwrap());
t.process(myvec![1_u16, 2, 3]);
t.process(myvec!(0_u16 => 127));
t.process(myvec!(0_u8 => 200));
t.process(TestEnum::<u8>::Dummy);
t.process(TestEnum::Foo(42_u8));
t.process(TestEnum::Bar([1_u8, 2, 3, 4, 5, 6, 7, 8]));
t.process(Option::<u16>::None);
t.process(Some(42_u8));
#[rustfmt::skip]
t.process(
myvec!(0 => 15).shuffle().iter().map(|&i|
if i % 3 == 0 {
Option::None
} else {
Option::Some(myvec![0_u8 => i as u8].shuffle())
},
).collect::<Vec<_>>()
);
#[rustfmt::skip]
t.process(seq! {
(Option::Some(0x1234_u16), 42_u8),
myvec!(0 => 15).shuffle().iter().map(|&i|
(
i as u8,
if i % 3 == 0 {
Option::None
} else {
Option::Some(seq!(i % 5 as u16, myvec![0_u8 => i as u8].shuffle()))
},
)
).collect::<Vec<_>>()
});
#[rustfmt::skip]
t.process(
myvec!(0 => 10).shuffle().iter().map(|&i|
seq!{
i as u16,
seq! {
2 * i as u64,
Some(3 * i as u8)
}
}
)
.collect::<Vec<_>>()
);
#[rustfmt::skip]
t.process(seq! {
3_u8,
seq! {
0x5242_u16,
0x3312_u16
},
myvec!(0_u16 => 12).shuffle(),
myvec!(0_u8 => 30).shuffle().iter().map(|&i| seq!(i as u8, i as u32)).collect::<Vec<_>>()
});
t.process(Compact(0_u32));
t.process(Compact(127_u32));
t.process(Compact(128_u32));
t.process(Compact(129_u32));
t.process(Compact(1023_u32));
t.process(Compact(0x1000_u32));
t.process(Compact(0x3fff_u32));
t.process(Compact(0x4000_u32));
t.process(Compact(0x4001_u32));
t.process(Compact(0xfff1_u32));
t.process(Compact(0x1fffff_u32));
t.process(Compact(0x200000_u32));
t.process(Compact(0x200001_u32));
t.process(Compact(0xfff1ff_u32));
t.process(Compact(0xffffffffff_u64));
t.process(Compact(0xab1c50bbc19a_u64));
println!("------------------------");
println!("Fixed-length bit-strings");
t.process_bit_string_fl("0");
t.process_bit_string_fl("000");
t.process_bit_string_fl("1");
t.process_bit_string_fl("1101");
t.process_bit_string_fl("101100001001");
t.process_bit_string_fl("100010110110100101101101");
t.process_bit_string_fl("010100101010010101010101010110101000100101011010101011010101101101001010110101010010101010101101011010111001001000110010101010010110101001110011111110100000000010101010010111101001001111100010000001010110110101011001010101011111111110101101");
println!("------------------------");
println!("Variable-length bit-strings");
t.process_bit_string_vl("0");
t.process_bit_string_vl("000");
t.process_bit_string_vl("1");
t.process_bit_string_vl("1101");
t.process_bit_string_vl("101100001001");
t.process_bit_string_vl("100010110110100101101101");
t.process_bit_string_vl("010100101010010101010101010110101000100101011010101011010101101101001010110101010010101010101101011010111001001000110010101010010110101001110011111110100000000010101010010111101001001111100010000001010110110101011001010101011111111110101101");
}