Skip to content

Commit 34ef028

Browse files
committed
Add v3-preview module gathering a few breaking changes
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)
1 parent 18203b9 commit 34ef028

File tree

11 files changed

+1551
-95
lines changed

11 files changed

+1551
-95
lines changed

lib/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ rustdoc-args = ["--cfg=docsrs"]
2121
default = ["std"]
2222
alloc = []
2323
std = ["alloc"]
24+
v3-preview = []

lib/benches/lib.rs

+38-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
#![feature(test)]
22

3-
extern crate data_encoding;
43
extern crate test;
54

6-
use data_encoding::{Specification, BASE32, BASE32_DNSCURVE, BASE64, BASE64_NOPAD, HEXLOWER};
5+
#[cfg(feature = "v3-preview")]
6+
use std::convert::TryFrom as _;
7+
8+
#[cfg(not(feature = "v3-preview"))]
9+
use data_encoding as constants;
10+
#[cfg(feature = "v3-preview")]
11+
use data_encoding::v3_preview as constants;
12+
#[cfg(feature = "v3-preview")]
13+
use data_encoding::v3_preview::{Bit1, Bit2, Bit3, Bit6, Encoding, False, True};
14+
use data_encoding::Specification;
715
use test::Bencher;
816

917
#[bench]
@@ -13,6 +21,8 @@ fn base02_encode_base(b: &mut Bencher) {
1321
let mut spec = Specification::new();
1422
spec.symbols.push_str("01");
1523
let base = spec.encoding().unwrap();
24+
#[cfg(feature = "v3-preview")]
25+
let base = Encoding::<Bit1, True, False, False, False>::try_from(base).unwrap();
1626
b.iter(|| base.encode_mut(input, output));
1727
}
1828

@@ -23,6 +33,8 @@ fn base02_decode_base(b: &mut Bencher) {
2333
let mut spec = Specification::new();
2434
spec.symbols.push_str("01");
2535
let base = spec.encoding().unwrap();
36+
#[cfg(feature = "v3-preview")]
37+
let base = Encoding::<Bit1, True, False, False, False>::try_from(base).unwrap();
2638
b.iter(|| base.decode_mut(input, output));
2739
}
2840

@@ -33,6 +45,8 @@ fn base04_encode_base(b: &mut Bencher) {
3345
let mut spec = Specification::new();
3446
spec.symbols.push_str("0123");
3547
let base = spec.encoding().unwrap();
48+
#[cfg(feature = "v3-preview")]
49+
let base = Encoding::<Bit2, True, False, False, False>::try_from(base).unwrap();
3650
b.iter(|| base.encode_mut(input, output));
3751
}
3852

@@ -43,6 +57,8 @@ fn base04_decode_base(b: &mut Bencher) {
4357
let mut spec = Specification::new();
4458
spec.symbols.push_str("0123");
4559
let base = spec.encoding().unwrap();
60+
#[cfg(feature = "v3-preview")]
61+
let base = Encoding::<Bit2, True, False, False, False>::try_from(base).unwrap();
4662
b.iter(|| base.decode_mut(input, output));
4763
}
4864

@@ -53,6 +69,8 @@ fn base08_encode_base(b: &mut Bencher) {
5369
let mut spec = Specification::new();
5470
spec.symbols.push_str("01234567");
5571
let base = spec.encoding().unwrap();
72+
#[cfg(feature = "v3-preview")]
73+
let base = Encoding::<Bit3, True, False, False, False>::try_from(base).unwrap();
5674
b.iter(|| base.encode_mut(input, output));
5775
}
5876

@@ -63,56 +81,58 @@ fn base08_decode_base(b: &mut Bencher) {
6381
let mut spec = Specification::new();
6482
spec.symbols.push_str("01234567");
6583
let base = spec.encoding().unwrap();
84+
#[cfg(feature = "v3-preview")]
85+
let base = Encoding::<Bit3, True, False, False, False>::try_from(base).unwrap();
6686
b.iter(|| base.decode_mut(input, output));
6787
}
6888

6989
#[bench]
7090
fn base16_encode_base(b: &mut Bencher) {
7191
let input = &[0u8; 4096];
7292
let output = &mut [0u8; 8192];
73-
b.iter(|| HEXLOWER.encode_mut(input, output));
93+
b.iter(|| constants::HEXLOWER.encode_mut(input, output));
7494
}
7595

7696
#[bench]
7797
fn base16_decode_base(b: &mut Bencher) {
7898
let input = &[b'0'; 4096];
7999
let output = &mut [0u8; 2048];
80-
b.iter(|| HEXLOWER.decode_mut(input, output));
100+
b.iter(|| constants::HEXLOWER.decode_mut(input, output));
81101
}
82102

83103
#[bench]
84104
fn base32_encode_base(b: &mut Bencher) {
85105
let input = &[0u8; 4096];
86106
let output = &mut [0u8; 6560];
87-
b.iter(|| BASE32.encode_mut(input, output));
107+
b.iter(|| constants::BASE32.encode_mut(input, output));
88108
}
89109

90110
#[bench]
91111
fn base32_decode_base(b: &mut Bencher) {
92112
let input = &[b'A'; 4096];
93113
let output = &mut [0u8; 2560];
94-
b.iter(|| BASE32.decode_mut(input, output));
114+
b.iter(|| constants::BASE32.decode_mut(input, output));
95115
}
96116

97117
#[bench]
98118
fn base64_encode_base(b: &mut Bencher) {
99119
let input = &[0u8; 4096];
100120
let output = &mut [0u8; 5462];
101-
b.iter(|| BASE64_NOPAD.encode_mut(input, output));
121+
b.iter(|| constants::BASE64_NOPAD.encode_mut(input, output));
102122
}
103123

104124
#[bench]
105125
fn base64_decode_base(b: &mut Bencher) {
106126
let input = &[b'A'; 4096];
107127
let output = &mut [0u8; 3072];
108-
b.iter(|| BASE64_NOPAD.decode_mut(input, output));
128+
b.iter(|| constants::BASE64_NOPAD.decode_mut(input, output));
109129
}
110130

111131
#[bench]
112132
fn base64_encode_pad(b: &mut Bencher) {
113133
let input = &mut [b'A'; 4096];
114134
let output = &mut [0u8; 5464];
115-
b.iter(|| BASE64.encode_mut(input, output));
135+
b.iter(|| constants::BASE64.encode_mut(input, output));
116136
}
117137

118138
#[bench]
@@ -126,17 +146,19 @@ fn base64_decode_pad(b: &mut Bencher) {
126146
}
127147
}
128148
let output = &mut [0u8; 3072];
129-
b.iter(|| BASE64.decode_mut(input, output).unwrap());
149+
b.iter(|| constants::BASE64.decode_mut(input, output).unwrap());
130150
}
131151

132152
#[bench]
133153
fn base64_encode_wrap(b: &mut Bencher) {
134154
let input = &[0u8; 4096];
135155
let output = &mut [0u8; 5608];
136-
let mut spec = BASE64.specification();
156+
let mut spec = data_encoding::BASE64.specification();
137157
spec.wrap.width = 76;
138158
spec.wrap.separator.push_str("\r\n");
139159
let base64 = spec.encoding().unwrap();
160+
#[cfg(feature = "v3-preview")]
161+
let base64 = Encoding::<Bit6, True, True, True, True>::try_from(base64).unwrap();
140162
b.iter(|| base64.encode_mut(input, output));
141163
}
142164

@@ -148,23 +170,25 @@ fn base64_decode_wrap(b: &mut Bencher) {
148170
input[x + 3] = b'\n';
149171
}
150172
let output = &mut [0u8; 3072];
151-
let mut spec = BASE64.specification();
173+
let mut spec = data_encoding::BASE64.specification();
152174
spec.wrap.width = 76;
153175
spec.wrap.separator.push_str("\r\n");
154176
let base64 = spec.encoding().unwrap();
177+
#[cfg(feature = "v3-preview")]
178+
let base64 = Encoding::<Bit6, True, True, True, True>::try_from(base64).unwrap();
155179
b.iter(|| base64.decode_mut(input, output).unwrap());
156180
}
157181

158182
#[bench]
159183
fn dnscurve_decode_base(b: &mut Bencher) {
160184
let input = &[b'0'; 4096];
161185
let output = &mut [0u8; 2560];
162-
b.iter(|| BASE32_DNSCURVE.decode_mut(input, output));
186+
b.iter(|| constants::BASE32_DNSCURVE.decode_mut(input, output));
163187
}
164188

165189
#[bench]
166190
fn dnscurve_encode_base(b: &mut Bencher) {
167191
let input = &[0u8; 4096];
168192
let output = &mut [0u8; 6554];
169-
b.iter(|| BASE32_DNSCURVE.encode_mut(input, output));
193+
b.iter(|| constants::BASE32_DNSCURVE.encode_mut(input, output));
170194
}

lib/fuzz/Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,10 @@ name = "encode_write"
2929
path = "fuzz_targets/encode_write.rs"
3030
test = false
3131
doc = false
32+
33+
[[bin]]
34+
name = "v3-preview"
35+
path = "fuzz_targets/v3-preview.rs"
36+
test = false
37+
doc = false
38+
required-features = ["data-encoding/v3-preview"]

lib/fuzz/examples/analyze.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
extern crate data_encoding;
2-
extern crate data_encoding_fuzz;
3-
41
use std::collections::HashMap;
52
use std::ops::AddAssign;
63

lib/fuzz/examples/debug.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
extern crate data_encoding_fuzz;
2-
31
use std::io::Read;
42

53
use data_encoding_fuzz::generate_specification;

lib/fuzz/fuzz_targets/v3-preview.rs

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#![no_main]
2+
3+
use data_encoding::v3_preview::{Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Encoding, False, True};
4+
use data_encoding_fuzz::{decode_prefix, generate_encoding};
5+
use libfuzzer_sys::fuzz_target;
6+
7+
fuzz_target!(|data: &[u8]| {
8+
let mut data = data;
9+
let dyn_base = generate_encoding(&mut data);
10+
let mut count = 0;
11+
macro_rules! test {
12+
($Bit:ident, $Msb:ident, $Pad:ident, $Wrap:ident, $Ignore:ident) => {
13+
if let Ok(base) = <&Encoding<$Bit, $Msb, $Pad, $Wrap, $Ignore>>::try_from(&dyn_base) {
14+
count += 1;
15+
let encoded = base.encode(data);
16+
assert_eq!(encoded, dyn_base.encode(data));
17+
assert_eq!(base.decode(encoded.as_bytes()).unwrap(), data);
18+
if dyn_base.is_canonical() {
19+
let raw = decode_prefix(&dyn_base, &mut data);
20+
assert_eq!(base.encode(&raw).as_bytes(), data);
21+
}
22+
}
23+
};
24+
}
25+
test!(Bit1, False, False, False, False);
26+
test!(Bit1, False, False, False, True);
27+
test!(Bit1, False, False, True, True);
28+
test!(Bit1, False, True, False, False);
29+
test!(Bit1, False, True, False, True);
30+
test!(Bit1, False, True, True, True);
31+
test!(Bit1, True, False, False, False);
32+
test!(Bit1, True, False, False, True);
33+
test!(Bit1, True, False, True, True);
34+
test!(Bit1, True, True, False, False);
35+
test!(Bit1, True, True, False, True);
36+
test!(Bit1, True, True, True, True);
37+
test!(Bit2, False, False, False, False);
38+
test!(Bit2, False, False, False, True);
39+
test!(Bit2, False, False, True, True);
40+
test!(Bit2, False, True, False, False);
41+
test!(Bit2, False, True, False, True);
42+
test!(Bit2, False, True, True, True);
43+
test!(Bit2, True, False, False, False);
44+
test!(Bit2, True, False, False, True);
45+
test!(Bit2, True, False, True, True);
46+
test!(Bit2, True, True, False, False);
47+
test!(Bit2, True, True, False, True);
48+
test!(Bit2, True, True, True, True);
49+
test!(Bit3, False, False, False, False);
50+
test!(Bit3, False, False, False, True);
51+
test!(Bit3, False, False, True, True);
52+
test!(Bit3, False, True, False, False);
53+
test!(Bit3, False, True, False, True);
54+
test!(Bit3, False, True, True, True);
55+
test!(Bit3, True, False, False, False);
56+
test!(Bit3, True, False, False, True);
57+
test!(Bit3, True, False, True, True);
58+
test!(Bit3, True, True, False, False);
59+
test!(Bit3, True, True, False, True);
60+
test!(Bit3, True, True, True, True);
61+
test!(Bit4, False, False, False, False);
62+
test!(Bit4, False, False, False, True);
63+
test!(Bit4, False, False, True, True);
64+
test!(Bit4, False, True, False, False);
65+
test!(Bit4, False, True, False, True);
66+
test!(Bit4, False, True, True, True);
67+
test!(Bit4, True, False, False, False);
68+
test!(Bit4, True, False, False, True);
69+
test!(Bit4, True, False, True, True);
70+
test!(Bit4, True, True, False, False);
71+
test!(Bit4, True, True, False, True);
72+
test!(Bit4, True, True, True, True);
73+
test!(Bit5, False, False, False, False);
74+
test!(Bit5, False, False, False, True);
75+
test!(Bit5, False, False, True, True);
76+
test!(Bit5, False, True, False, False);
77+
test!(Bit5, False, True, False, True);
78+
test!(Bit5, False, True, True, True);
79+
test!(Bit5, True, False, False, False);
80+
test!(Bit5, True, False, False, True);
81+
test!(Bit5, True, False, True, True);
82+
test!(Bit5, True, True, False, False);
83+
test!(Bit5, True, True, False, True);
84+
test!(Bit5, True, True, True, True);
85+
test!(Bit6, False, False, False, False);
86+
test!(Bit6, False, False, False, True);
87+
test!(Bit6, False, False, True, True);
88+
test!(Bit6, False, True, False, False);
89+
test!(Bit6, False, True, False, True);
90+
test!(Bit6, False, True, True, True);
91+
test!(Bit6, True, False, False, False);
92+
test!(Bit6, True, False, False, True);
93+
test!(Bit6, True, False, True, True);
94+
test!(Bit6, True, True, False, False);
95+
test!(Bit6, True, True, False, True);
96+
test!(Bit6, True, True, True, True);
97+
assert_eq!(count, 1);
98+
});

lib/fuzz/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
extern crate data_encoding;
2-
31
use data_encoding::{DecodePartial, Encoding, Specification};
42

53
pub fn generate_encoding(data: &mut &[u8]) -> Encoding {

lib/src/lib.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ macro_rules! check {
184184
};
185185
}
186186

187+
#[cfg(feature = "v3-preview")]
188+
pub mod v3_preview;
189+
187190
trait Static<T: Copy>: Copy {
188191
fn val(self) -> T;
189192
}
@@ -255,21 +258,21 @@ macro_rules! dispatch {
255258
($body: expr) => { $body };
256259
}
257260

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

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

268-
fn div_ceil(x: usize, m: usize) -> usize {
271+
const fn div_ceil(x: usize, m: usize) -> usize {
269272
(x + m - 1) / m
270273
}
271274

272-
fn floor(x: usize, m: usize) -> usize {
275+
const fn floor(x: usize, m: usize) -> usize {
273276
x / m * m
274277
}
275278

@@ -354,15 +357,15 @@ const INVALID: u8 = 128;
354357
const IGNORE: u8 = 129;
355358
const PADDING: u8 = 130;
356359

357-
fn order(msb: bool, n: usize, i: usize) -> usize {
360+
const fn order(msb: bool, n: usize, i: usize) -> usize {
358361
if msb {
359362
n - 1 - i
360363
} else {
361364
i
362365
}
363366
}
364367

365-
fn enc(bit: usize) -> usize {
368+
const fn enc(bit: usize) -> usize {
366369
match bit {
367370
1 | 2 | 4 => 1,
368371
3 | 6 => 3,
@@ -371,7 +374,7 @@ fn enc(bit: usize) -> usize {
371374
}
372375
}
373376

374-
fn dec(bit: usize) -> usize {
377+
const fn dec(bit: usize) -> usize {
375378
enc(bit) * 8 / bit
376379
}
377380

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

885889
/// How to translate characters when decoding

0 commit comments

Comments
 (0)