Skip to content

Commit

Permalink
test build system
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmayer committed Nov 13, 2024
1 parent 5df0400 commit 77d8c40
Showing 1 changed file with 92 additions and 57 deletions.
149 changes: 92 additions & 57 deletions src/generic.rs
Original file line number Diff line number Diff line change
@@ -1,122 +1,157 @@
/// Generic functions
/// Generic functions `encode` and `decode` that taken an instance the `Encoding` trait.
/// The encode and decode come also in the flavour Encoding::encode and Encoding::decode.
///
/// The point of the whole commotion is to have single generic encode<Encoding> and decode<Encoding>
/// function that is better suited to generic programming than the wrappers codec::enc, dec, etc.
///
/// There are four such `Encoding` instances:
/// - `StandardEncoding` for unsorted integer lists (using codec::dec and enc)
/// - `IncreasingEncoding` for increasing integer lists (using codec::ddec and denc)
/// - `StrictlyIncreasingEncoding` for strictly increasing integer lists (using codec::d1dec and d1enc)
/// - `ZigZagEncoding` for unsorted integer lists (using codec::zdec and zenc)
///
/// Along with those two function we have `dec_buf_len` and `enc_buf_size` that are used to calculate
/// the safe buffer sizes.
///
/// Each encoding gets an u8 identifier `ENC_TYPE` that can be used for lookup tables, etc.
///
/// The sample function is used to generate random data for testing the encodings.
use crate::codec::*;
use crate::sample::*;
use std::marker::PhantomData;
use rand::{
use rand::{ // for testing
prelude::Distribution,
distributions::Standard
distributions::Standard,
};

/// Trait for encoding types with width.
pub trait Encoding {
type W: Width;
type T;
const ENC_TYPE: u8; // useful for identifying the encoding type in lookup tables, etc.
fn encode<EW: Width>(input: &[Self::T], output: &mut [u8]) -> usize;
fn decode<EW: Width>(input: &[u8], n: usize, output: &mut [Self::T]) -> usize;
/// Numeric ID useful for identifying the encoding type in lookup tables, etc.
const ENC_TYPE: u8;
/// Encode input data into output buffer
fn encode(input: &[Self::T], output: &mut [u8]) -> usize;
/// Decode input buffer into output data
fn decode(input: &[u8], n: usize, output: &mut [Self::T]) -> usize;
/// Minimum safe [T] array length required for decoding n T's
fn dec_buf_len(n: usize) -> usize;
/// Minimum safe u8 size required for encoding n T's
fn enc_buf_size(n: usize) -> usize;
/// Sample random data for Self::T suitable for testing this encoding
fn sample(len: usize) -> Vec<Self::T>;
}

pub struct StandardEncoding<W, T> { _marker_w: PhantomData<W>, _marker_t: PhantomData<T> }
pub struct IncreasingEncoding<W, T> { _marker_w: PhantomData<W>, _marker_t: PhantomData<T> }
pub struct StrictlyIncreasingEncoding<W, T> { _marker_w: PhantomData<W>, _marker_t: PhantomData<T> }
pub struct ZigZagEncoding<W, T> { _marker_w: PhantomData<W>, _marker_t: PhantomData<T> }
pub struct StandardEncoding<WT, T> { _marker_w: PhantomData<WT>, _marker_t: PhantomData<T> }
pub struct IncreasingEncoding<WT, T> { _marker_w: PhantomData<WT>, _marker_t: PhantomData<T> }
pub struct StrictlyIncreasingEncoding<WT, T> { _marker_w: PhantomData<WT>, _marker_t: PhantomData<T> }
pub struct ZigZagEncoding<WT, T> { _marker_w: PhantomData<WT>, _marker_t: PhantomData<T> }

// Implement the Encoding trait for each encoding type, linking to the right Codec methods
impl<W: Width, T: Codec<W>> Encoding for StandardEncoding<W, T>
impl<WT: Width, T: Codec<WT>> Encoding for StandardEncoding<WT, T>
where Standard: Distribution<T>, T: Arithmetic
{
type W = WT;
type T = T;
const ENC_TYPE: u8 = 0; // Example encoding type constant
fn encode<EW: Width>(input: &[Self::T], output: &mut [u8]) -> usize {
fn encode(input: &[Self::T], output: &mut [u8]) -> usize {
T::enc(input, output)
}
fn decode<EW: Width>(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
fn decode(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
T::dec(input, n, output)
}
fn dec_buf_len(n: usize) -> usize { Self::W::dec_buf_len::<Self::T>(n) }
fn enc_buf_size(n: usize) -> usize { Self::W::enc_buf_size::<Self::T>(n) }
fn sample(len: usize) -> Vec<Self::T> { sample_standard(len) }
}

impl<W: Width, T: Codec<W>> Encoding for IncreasingEncoding<W, T>
impl<WT: Width, T: Codec<WT>> Encoding for IncreasingEncoding<WT, T>
where Standard: Distribution<T>, T: Arithmetic
{
type W = WT;
type T = T;
const ENC_TYPE: u8 = 1;
fn encode<EW: Width>(input: &[Self::T], output: &mut [u8]) -> usize {
fn encode(input: &[Self::T], output: &mut [u8]) -> usize {
T::denc(input, output)
}
fn decode<EW: Width>(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
fn decode(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
T::ddec(input, n, output)
}
fn dec_buf_len(n: usize) -> usize { Self::W::dec_buf_len::<Self::T>(n) }
fn enc_buf_size(n: usize) -> usize { Self::W::enc_buf_size::<Self::T>(n) }
fn sample(len: usize) -> Vec<Self::T>
where Standard: Distribution<T>, T: Arithmetic
{ sample_increasing(len, 0, 10) }
}

impl<W: Width, T: Codec<W>> Encoding for StrictlyIncreasingEncoding<W, T>
impl<WT: Width, T: Codec<WT>> Encoding for StrictlyIncreasingEncoding<WT, T>
where Standard: Distribution<T>, T: Arithmetic
{
type W = WT;
type T = T;
const ENC_TYPE: u8 = 2;
fn encode<EW: Width>(input: &[Self::T], output: &mut [u8]) -> usize {
fn encode(input: &[Self::T], output: &mut [u8]) -> usize {
T::d1enc(input, output)
}
fn decode<EW: Width>(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
fn decode(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
T::d1dec(input, n, output)
}
fn dec_buf_len(n: usize) -> usize { Self::W::dec_buf_len::<Self::T>(n) }
fn enc_buf_size(n: usize) -> usize { Self::W::enc_buf_size::<Self::T>(n) }
fn sample(len: usize) -> Vec<Self::T>
where Standard: Distribution<T>, T: Arithmetic
{ sample_increasing(len, 1, 10) }
}

impl<W: Width, T: Codec<W>> Encoding for ZigZagEncoding<W, T>
impl<WT: Width, T: Codec<WT>> Encoding for ZigZagEncoding<WT, T>
where Standard: Distribution<T>, T: Arithmetic
{
type W = WT;
type T = T;
const ENC_TYPE: u8 = 3;
fn encode<EW: Width>(input: &[Self::T], output: &mut [u8]) -> usize {
fn encode(input: &[Self::T], output: &mut [u8]) -> usize {
T::zenc(input, output)
}
fn decode<EW: Width>(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
fn decode(input: &[u8], n: usize, output: &mut [Self::T]) -> usize {
T::zdec(input, n, output)
}
fn dec_buf_len(n: usize) -> usize { Self::W::dec_buf_len::<Self::T>(n) }
fn enc_buf_size(n: usize) -> usize { Self::W::enc_buf_size::<Self::T>(n) }
fn sample(len: usize) -> Vec<Self::T> { sample_standard(len) }
}

/// Generic encoding function
pub fn encode<E: Encoding, W: Width>(input: &[E::T], output: &mut [u8]) -> usize {
E::encode::<W>(input, output)
pub fn encode<E: Encoding>(input: &[E::T], output: &mut [u8]) -> usize {
E::encode(input, output)
}

/// Generic decoding function
pub fn decode<E: Encoding, W: Width>(input: &[u8], n: usize, output: &mut [E::T]) -> usize {
E::decode::<W>(input, n, output)
pub fn decode<E: Encoding>(input: &[u8], n: usize, output: &mut [E::T]) -> usize {
E::decode(input, n, output)
}

#[cfg(test)]
use rand::Rng;

#[cfg(test)]
fn test_enc_dec_generic<T, E, WidthType>()
fn test_enc_dec_generic<E>()
where
WidthType: Width,
E: Encoding<T = T>,
T: Codec<WidthType>,
T: Eq + Clone + core::fmt::Debug + Default,
u8: Codec<WidthType>, u16: Codec<WidthType>, u32: Codec<WidthType>, u64: Codec<WidthType>,
Standard: Distribution<T>, T: Arithmetic
E: Encoding,
E::T : Default + std::fmt::Debug,
E::W : Width,
Standard: Distribution<E::T>, E::T: Arithmetic
{
let mut rng = rand::thread_rng();
for _ in 0..256 {
// Generate random input data
let len = rng.gen_range(1..=16 * 1024);
let input: Vec<T> = E::sample(len);
println!("Input: {:?}", input);
let input: Vec<E::T> = E::sample(len);
// Prepare input buffer and encode
let mut buf = vec![0u8; WidthType::enc_buf_size::<T>(input.len())];
let size_enc = encode::<E, WidthType>(&input, &mut buf);
let mut buf = vec![0u8; E::enc_buf_size(input.len())];
let size_enc = encode::<E>(&input, &mut buf);
// Prepare output buffer and decode
let mut output: Vec<T> = vec![T::default(); WidthType::dec_buf_len::<T>(input.len())];
println!("Output: {:?}", output);
let size_dec = decode::<E, WidthType>(&buf[..size_enc], input.len(), &mut output);
let mut output: Vec<E::T> = vec![E::T::default(); E::dec_buf_len(input.len())];
let size_dec = decode::<E>(&buf[..size_enc], input.len(), &mut output);
// Check results
assert_eq!(size_enc, size_dec);
assert_eq!(input, output[..input.len()]);
Expand All @@ -125,80 +160,80 @@ where

#[test]
fn test_enc_dec_u8_standard() {
test_enc_dec_generic::<u8, StandardEncoding<W, u8>, W>()
test_enc_dec_generic::<StandardEncoding<W, u8>>()
}

#[test]
fn test_enc_dec_u16_standard() {
test_enc_dec_generic::<u16, StandardEncoding<W, u16>, W>()
test_enc_dec_generic::<StandardEncoding<W, u16>>()
}

#[test]
fn test_enc_dec_u32_standard() {
test_enc_dec_generic::<u32, StandardEncoding<W, u32>, W>()
test_enc_dec_generic::<StandardEncoding<W, u32>>()
}

#[test]
fn test_enc_dec_u64_standard() {
test_enc_dec_generic::<u64, StandardEncoding<W, u64>, W>()
test_enc_dec_generic::<StandardEncoding<W, u64>>()
}

#[test]
fn test_enc_dec_u8_increasing() {
test_enc_dec_generic::<u8, IncreasingEncoding<W, u8>, W>()
test_enc_dec_generic::<IncreasingEncoding<W, u8>>()
}

#[test]
fn test_enc_dec_u16_increasing() {
test_enc_dec_generic::<u16, IncreasingEncoding<W, u16>, W>()
test_enc_dec_generic::<IncreasingEncoding<W, u16>>()
}

#[test]
fn test_enc_dec_u32_increasing() {
test_enc_dec_generic::<u32, IncreasingEncoding<W, u32>, W>()
test_enc_dec_generic::<IncreasingEncoding<W, u32>>()
}

#[test]
fn test_enc_dec_u64_increasing() {
test_enc_dec_generic::<u64, IncreasingEncoding<W, u64>, W>()
test_enc_dec_generic::<IncreasingEncoding<W, u64>>()
}

#[test]
fn test_enc_dec_u8_strictly_increasing() {
test_enc_dec_generic::<u8, StrictlyIncreasingEncoding<W, u8>, W>()
test_enc_dec_generic::<StrictlyIncreasingEncoding<W, u8>>()
}

#[test]
fn test_enc_dec_u16_strictly_increasing() {
test_enc_dec_generic::<u16, StrictlyIncreasingEncoding<W, u16>, W>()
test_enc_dec_generic::<StrictlyIncreasingEncoding<W, u16>>()
}

#[test]
fn test_enc_dec_u32_strictly_increasing() {
test_enc_dec_generic::<u32, StrictlyIncreasingEncoding<W, u32>, W>()
test_enc_dec_generic::<StrictlyIncreasingEncoding<W, u32>>()
}

#[test]
fn test_enc_dec_u64_strictly_increasing() {
test_enc_dec_generic::<u64, StrictlyIncreasingEncoding<W, u64>, W>()
test_enc_dec_generic::<StrictlyIncreasingEncoding<W, u64>>()
}

#[test]
fn test_enc_dec_u8_zigzag() {
test_enc_dec_generic::<u8, ZigZagEncoding<W, u8>, W>()
test_enc_dec_generic::<ZigZagEncoding<W, u8>>()
}

#[test]
fn test_enc_dec_u16_zigzag() {
test_enc_dec_generic::<u16, ZigZagEncoding<W, u16>, W>()
test_enc_dec_generic::<ZigZagEncoding<W, u16>>()
}

#[test]
fn test_enc_dec_u32_zigzag() {
test_enc_dec_generic::<u32, ZigZagEncoding<W, u32>, W>()
test_enc_dec_generic::<ZigZagEncoding<W, u32>>()
}

#[test]
fn test_enc_dec_u64_zigzag() {
test_enc_dec_generic::<u64, ZigZagEncoding<W, u64>, W>()
}
test_enc_dec_generic::<ZigZagEncoding<W, u64>>()
}

0 comments on commit 77d8c40

Please sign in to comment.