Skip to content

Commit

Permalink
Add v3-preview module gathering a few breaking changes
Browse files Browse the repository at this point in the history
This new module addresses the following breaking changes of #72:
- `static` instead of `const` for pre-defined encodings
- Private `Encoding` implementation with `unsafe` constructor
- Use `MaybeUninit` internally and expose `_uninit` functions
- Use static dispatch instead of dynamic dispatch (fixing #97)
  • Loading branch information
ia0 committed Apr 28, 2024
1 parent 18203b9 commit 88341ba
Show file tree
Hide file tree
Showing 5 changed files with 1,186 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ rustdoc-args = ["--cfg=docsrs"]
default = ["std"]
alloc = []
std = ["alloc"]
v3-preview = []
7 changes: 7 additions & 0 deletions lib/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,10 @@ name = "encode_write"
path = "fuzz_targets/encode_write.rs"
test = false
doc = false

[[bin]]
name = "v3-preview"
path = "fuzz_targets/v3-preview.rs"
test = false
doc = false
required-features = ["data-encoding/v3-preview"]
98 changes: 98 additions & 0 deletions lib/fuzz/fuzz_targets/v3-preview.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#![no_main]

use data_encoding::v3_preview::{Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Encoding, False, True};
use data_encoding_fuzz::{decode_prefix, generate_encoding};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
let mut data = data;
let dyn_base = generate_encoding(&mut data);
let mut count = 0;
macro_rules! test {
($Bit:ident, $Msb:ident, $Pad:ident, $Wrap:ident, $Ignore:ident) => {
if let Ok(base) = <&Encoding<$Bit, $Msb, $Pad, $Wrap, $Ignore>>::try_from(&dyn_base) {
count += 1;
let encoded = base.encode(data);
assert_eq!(encoded, dyn_base.encode(data));
assert_eq!(base.decode(encoded.as_bytes()).unwrap(), data);
if dyn_base.is_canonical() {
let raw = decode_prefix(&dyn_base, &mut data);
assert_eq!(base.encode(&raw).as_bytes(), data);
}
}
};
}
test!(Bit1, False, False, False, False);
test!(Bit1, False, False, False, True);
test!(Bit1, False, False, True, True);
test!(Bit1, False, True, False, False);
test!(Bit1, False, True, False, True);
test!(Bit1, False, True, True, True);
test!(Bit1, True, False, False, False);
test!(Bit1, True, False, False, True);
test!(Bit1, True, False, True, True);
test!(Bit1, True, True, False, False);
test!(Bit1, True, True, False, True);
test!(Bit1, True, True, True, True);
test!(Bit2, False, False, False, False);
test!(Bit2, False, False, False, True);
test!(Bit2, False, False, True, True);
test!(Bit2, False, True, False, False);
test!(Bit2, False, True, False, True);
test!(Bit2, False, True, True, True);
test!(Bit2, True, False, False, False);
test!(Bit2, True, False, False, True);
test!(Bit2, True, False, True, True);
test!(Bit2, True, True, False, False);
test!(Bit2, True, True, False, True);
test!(Bit2, True, True, True, True);
test!(Bit3, False, False, False, False);
test!(Bit3, False, False, False, True);
test!(Bit3, False, False, True, True);
test!(Bit3, False, True, False, False);
test!(Bit3, False, True, False, True);
test!(Bit3, False, True, True, True);
test!(Bit3, True, False, False, False);
test!(Bit3, True, False, False, True);
test!(Bit3, True, False, True, True);
test!(Bit3, True, True, False, False);
test!(Bit3, True, True, False, True);
test!(Bit3, True, True, True, True);
test!(Bit4, False, False, False, False);
test!(Bit4, False, False, False, True);
test!(Bit4, False, False, True, True);
test!(Bit4, False, True, False, False);
test!(Bit4, False, True, False, True);
test!(Bit4, False, True, True, True);
test!(Bit4, True, False, False, False);
test!(Bit4, True, False, False, True);
test!(Bit4, True, False, True, True);
test!(Bit4, True, True, False, False);
test!(Bit4, True, True, False, True);
test!(Bit4, True, True, True, True);
test!(Bit5, False, False, False, False);
test!(Bit5, False, False, False, True);
test!(Bit5, False, False, True, True);
test!(Bit5, False, True, False, False);
test!(Bit5, False, True, False, True);
test!(Bit5, False, True, True, True);
test!(Bit5, True, False, False, False);
test!(Bit5, True, False, False, True);
test!(Bit5, True, False, True, True);
test!(Bit5, True, True, False, False);
test!(Bit5, True, True, False, True);
test!(Bit5, True, True, True, True);
test!(Bit6, False, False, False, False);
test!(Bit6, False, False, False, True);
test!(Bit6, False, False, True, True);
test!(Bit6, False, True, False, False);
test!(Bit6, False, True, False, True);
test!(Bit6, False, True, True, True);
test!(Bit6, True, False, False, False);
test!(Bit6, True, False, False, True);
test!(Bit6, True, False, True, True);
test!(Bit6, True, True, False, False);
test!(Bit6, True, True, False, True);
test!(Bit6, True, True, True, True);
assert_eq!(count, 1);
});
18 changes: 11 additions & 7 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ macro_rules! check {
};
}

#[cfg(feature = "v3-preview")]
pub mod v3_preview;

trait Static<T: Copy>: Copy {
fn val(self) -> T;
}
Expand Down Expand Up @@ -255,21 +258,21 @@ macro_rules! dispatch {
($body: expr) => { $body };
}

unsafe fn chunk_unchecked(x: &[u8], n: usize, i: usize) -> &[u8] {
unsafe fn chunk_unchecked<T>(x: &[T], n: usize, i: usize) -> &[T] {
debug_assert!((i + 1) * n <= x.len());
unsafe { core::slice::from_raw_parts(x.as_ptr().add(n * i), n) }
}

unsafe fn chunk_mut_unchecked(x: &mut [u8], n: usize, i: usize) -> &mut [u8] {
unsafe fn chunk_mut_unchecked<T>(x: &mut [T], n: usize, i: usize) -> &mut [T] {
debug_assert!((i + 1) * n <= x.len());
unsafe { core::slice::from_raw_parts_mut(x.as_mut_ptr().add(n * i), n) }
}

fn div_ceil(x: usize, m: usize) -> usize {
const fn div_ceil(x: usize, m: usize) -> usize {
(x + m - 1) / m
}

fn floor(x: usize, m: usize) -> usize {
const fn floor(x: usize, m: usize) -> usize {
x / m * m
}

Expand Down Expand Up @@ -354,15 +357,15 @@ const INVALID: u8 = 128;
const IGNORE: u8 = 129;
const PADDING: u8 = 130;

fn order(msb: bool, n: usize, i: usize) -> usize {
const fn order(msb: bool, n: usize, i: usize) -> usize {
if msb {
n - 1 - i
} else {
i
}
}

fn enc(bit: usize) -> usize {
const fn enc(bit: usize) -> usize {
match bit {
1 | 2 | 4 => 1,
3 | 6 => 3,
Expand All @@ -371,7 +374,7 @@ fn enc(bit: usize) -> usize {
}
}

fn dec(bit: usize) -> usize {
const fn dec(bit: usize) -> usize {
enc(bit) * 8 / bit
}

Expand Down Expand Up @@ -880,6 +883,7 @@ pub type InternalEncoding = &'static [u8];
// - width % dec(bit) == 0
// - for all x in separator values[x] is IGNORE
#[derive(Debug, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Encoding(#[doc(hidden)] pub InternalEncoding);

/// How to translate characters when decoding
Expand Down
Loading

0 comments on commit 88341ba

Please sign in to comment.