diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64d0fd4..984e292 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,7 @@ jobs: - uses: actions/checkout@v4 - run: rustup install nightly - run: rustup component add --toolchain=nightly clippy miri rustfmt + - run: cargo +nightly install cargo-audit --locked - name: cd lib && cargo +nightly fmt -- --check run: cargo +nightly fmt -- --check working-directory: lib @@ -76,24 +77,6 @@ jobs: - name: cd lib && cargo +nightly build --release --no-default-features run: cargo +nightly build --release --no-default-features working-directory: lib - - name: cd lib && cargo +nightly build --features=v3-preview - run: cargo +nightly build --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --release --features=v3-preview - run: cargo +nightly build --release --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --no-default-features --features=alloc --features=v3-preview - run: cargo +nightly build --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --release --no-default-features --features=alloc --features=v3-preview - run: cargo +nightly build --release --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --no-default-features --features=v3-preview - run: cargo +nightly build --no-default-features --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --release --no-default-features --features=v3-preview - run: cargo +nightly build --release --no-default-features --features=v3-preview - working-directory: lib - name: cd lib/macro/internal && cargo +nightly build run: cargo +nightly build working-directory: lib/macro/internal @@ -127,9 +110,6 @@ jobs: - name: cd lib && cargo +nightly test run: cargo +nightly test working-directory: lib - - name: cd lib && cargo +nightly test --features=v3-preview - run: cargo +nightly test --features=v3-preview - working-directory: lib - name: cd lib/macro/internal && cargo +nightly test run: cargo +nightly test working-directory: lib/macro/internal @@ -160,15 +140,9 @@ jobs: - name: cd lib && cargo +nightly miri test run: cargo +nightly miri test working-directory: lib - - name: cd lib && cargo +nightly miri test --features=v3-preview - run: cargo +nightly miri test --features=v3-preview - working-directory: lib - name: cd lib && cargo +nightly bench run: cargo +nightly bench working-directory: lib - - name: cd lib && cargo +nightly bench --features=v3-preview - run: cargo +nightly bench --features=v3-preview - working-directory: lib - run: cd bin && ./bench.sh +nightly - name: cd lib && cargo +nightly audit --deny=warnings run: cargo +nightly audit --deny=warnings @@ -195,7 +169,7 @@ jobs: run: cargo +nightly audit --deny=warnings working-directory: www - run: rustup install stable - - run: cargo +stable install cargo-semver-checks + - run: cargo +stable install cargo-semver-checks --locked - name: cd lib && cargo +stable build run: cargo +stable build working-directory: lib @@ -214,24 +188,6 @@ jobs: - name: cd lib && cargo +stable build --release --no-default-features run: cargo +stable build --release --no-default-features working-directory: lib - - name: cd lib && cargo +stable build --features=v3-preview - run: cargo +stable build --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --release --features=v3-preview - run: cargo +stable build --release --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --no-default-features --features=alloc --features=v3-preview - run: cargo +stable build --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --release --no-default-features --features=alloc --features=v3-preview - run: cargo +stable build --release --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --no-default-features --features=v3-preview - run: cargo +stable build --no-default-features --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --release --no-default-features --features=v3-preview - run: cargo +stable build --release --no-default-features --features=v3-preview - working-directory: lib - name: cd lib/macro/internal && cargo +stable build run: cargo +stable build working-directory: lib/macro/internal @@ -322,24 +278,6 @@ jobs: - name: cd lib && cargo +nightly build --release --no-default-features run: cargo +nightly build --release --no-default-features working-directory: lib - - name: cd lib && cargo +nightly build --features=v3-preview - run: cargo +nightly build --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --release --features=v3-preview - run: cargo +nightly build --release --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --no-default-features --features=alloc --features=v3-preview - run: cargo +nightly build --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --release --no-default-features --features=alloc --features=v3-preview - run: cargo +nightly build --release --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --no-default-features --features=v3-preview - run: cargo +nightly build --no-default-features --features=v3-preview - working-directory: lib - - name: cd lib && cargo +nightly build --release --no-default-features --features=v3-preview - run: cargo +nightly build --release --no-default-features --features=v3-preview - working-directory: lib - name: cd lib/macro/internal && cargo +nightly build run: cargo +nightly build working-directory: lib/macro/internal @@ -377,24 +315,6 @@ jobs: - name: cd lib && cargo +stable build --release --no-default-features run: cargo +stable build --release --no-default-features working-directory: lib - - name: cd lib && cargo +stable build --features=v3-preview - run: cargo +stable build --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --release --features=v3-preview - run: cargo +stable build --release --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --no-default-features --features=alloc --features=v3-preview - run: cargo +stable build --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --release --no-default-features --features=alloc --features=v3-preview - run: cargo +stable build --release --no-default-features --features=alloc --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --no-default-features --features=v3-preview - run: cargo +stable build --no-default-features --features=v3-preview - working-directory: lib - - name: cd lib && cargo +stable build --release --no-default-features --features=v3-preview - run: cargo +stable build --release --no-default-features --features=v3-preview - working-directory: lib - name: cd lib/macro/internal && cargo +stable build run: cargo +stable build working-directory: lib/macro/internal diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 81af90b..7c04acc 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -17,5 +17,5 @@ name = "data-encoding" path = "src/main.rs" [dependencies] -data-encoding = { version = "2.6.1-git", path = "../lib" } +data-encoding = { version = "2.7.0-git", path = "../lib" } getopts = "0.2" diff --git a/lib/CHANGELOG.md b/lib/CHANGELOG.md index 0616093..1f4e641 100644 --- a/lib/CHANGELOG.md +++ b/lib/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## 2.6.1-git +## 2.7.0-git + +### Minor + +- Add `Encoding::encode_display()` for easier formatting (fixes #118) ### Patch diff --git a/lib/Cargo.toml b/lib/Cargo.toml index fcdc877..95b9378 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "data-encoding" -version = "2.6.1-git" +version = "2.7.0-git" authors = ["Julien Cretin "] license = "MIT" edition = "2018" @@ -21,4 +21,3 @@ rustdoc-args = ["--cfg=docsrs"] default = ["std"] alloc = [] std = ["alloc"] -v3-preview = [] diff --git a/lib/benches/lib.rs b/lib/benches/lib.rs index ea6ed0a..a5f5f3f 100644 --- a/lib/benches/lib.rs +++ b/lib/benches/lib.rs @@ -2,15 +2,6 @@ extern crate test; -#[cfg(feature = "v3-preview")] -use std::convert::TryFrom as _; - -#[cfg(not(feature = "v3-preview"))] -use data_encoding as constants; -#[cfg(feature = "v3-preview")] -use data_encoding::v3_preview as constants; -#[cfg(feature = "v3-preview")] -use data_encoding::v3_preview::{Bit1, Bit2, Bit3, Bit6, Encoding, False, True}; use data_encoding::Specification; use test::Bencher; @@ -21,8 +12,6 @@ fn base02_encode_base(b: &mut Bencher) { let mut spec = Specification::new(); spec.symbols.push_str("01"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); b.iter(|| base.encode_mut(input, output)); } @@ -33,8 +22,6 @@ fn base02_decode_base(b: &mut Bencher) { let mut spec = Specification::new(); spec.symbols.push_str("01"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); b.iter(|| base.decode_mut(input, output)); } @@ -45,8 +32,6 @@ fn base04_encode_base(b: &mut Bencher) { let mut spec = Specification::new(); spec.symbols.push_str("0123"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); b.iter(|| base.encode_mut(input, output)); } @@ -57,8 +42,6 @@ fn base04_decode_base(b: &mut Bencher) { let mut spec = Specification::new(); spec.symbols.push_str("0123"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); b.iter(|| base.decode_mut(input, output)); } @@ -69,8 +52,6 @@ fn base08_encode_base(b: &mut Bencher) { let mut spec = Specification::new(); spec.symbols.push_str("01234567"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); b.iter(|| base.encode_mut(input, output)); } @@ -81,8 +62,6 @@ fn base08_decode_base(b: &mut Bencher) { let mut spec = Specification::new(); spec.symbols.push_str("01234567"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); b.iter(|| base.decode_mut(input, output)); } @@ -90,49 +69,49 @@ fn base08_decode_base(b: &mut Bencher) { fn base16_encode_base(b: &mut Bencher) { let input = &[0u8; 4096]; let output = &mut [0u8; 8192]; - b.iter(|| constants::HEXLOWER.encode_mut(input, output)); + b.iter(|| data_encoding::HEXLOWER.encode_mut(input, output)); } #[bench] fn base16_decode_base(b: &mut Bencher) { let input = &[b'0'; 4096]; let output = &mut [0u8; 2048]; - b.iter(|| constants::HEXLOWER.decode_mut(input, output)); + b.iter(|| data_encoding::HEXLOWER.decode_mut(input, output)); } #[bench] fn base32_encode_base(b: &mut Bencher) { let input = &[0u8; 4096]; let output = &mut [0u8; 6560]; - b.iter(|| constants::BASE32.encode_mut(input, output)); + b.iter(|| data_encoding::BASE32.encode_mut(input, output)); } #[bench] fn base32_decode_base(b: &mut Bencher) { let input = &[b'A'; 4096]; let output = &mut [0u8; 2560]; - b.iter(|| constants::BASE32.decode_mut(input, output)); + b.iter(|| data_encoding::BASE32.decode_mut(input, output)); } #[bench] fn base64_encode_base(b: &mut Bencher) { let input = &[0u8; 4096]; let output = &mut [0u8; 5462]; - b.iter(|| constants::BASE64_NOPAD.encode_mut(input, output)); + b.iter(|| data_encoding::BASE64_NOPAD.encode_mut(input, output)); } #[bench] fn base64_decode_base(b: &mut Bencher) { let input = &[b'A'; 4096]; let output = &mut [0u8; 3072]; - b.iter(|| constants::BASE64_NOPAD.decode_mut(input, output)); + b.iter(|| data_encoding::BASE64_NOPAD.decode_mut(input, output)); } #[bench] fn base64_encode_pad(b: &mut Bencher) { let input = &mut [b'A'; 4096]; let output = &mut [0u8; 5464]; - b.iter(|| constants::BASE64.encode_mut(input, output)); + b.iter(|| data_encoding::BASE64.encode_mut(input, output)); } #[bench] @@ -146,7 +125,7 @@ fn base64_decode_pad(b: &mut Bencher) { } } let output = &mut [0u8; 3072]; - b.iter(|| constants::BASE64.decode_mut(input, output).unwrap()); + b.iter(|| data_encoding::BASE64.decode_mut(input, output).unwrap()); } #[bench] @@ -157,8 +136,6 @@ fn base64_encode_wrap(b: &mut Bencher) { spec.wrap.width = 76; spec.wrap.separator.push_str("\r\n"); let base64 = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base64 = Encoding::::try_from(base64).unwrap(); b.iter(|| base64.encode_mut(input, output)); } @@ -174,8 +151,6 @@ fn base64_decode_wrap(b: &mut Bencher) { spec.wrap.width = 76; spec.wrap.separator.push_str("\r\n"); let base64 = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base64 = Encoding::::try_from(base64).unwrap(); b.iter(|| base64.decode_mut(input, output).unwrap()); } @@ -183,12 +158,12 @@ fn base64_decode_wrap(b: &mut Bencher) { fn dnscurve_decode_base(b: &mut Bencher) { let input = &[b'0'; 4096]; let output = &mut [0u8; 2560]; - b.iter(|| constants::BASE32_DNSCURVE.decode_mut(input, output)); + b.iter(|| data_encoding::BASE32_DNSCURVE.decode_mut(input, output)); } #[bench] fn dnscurve_encode_base(b: &mut Bencher) { let input = &[0u8; 4096]; let output = &mut [0u8; 6554]; - b.iter(|| constants::BASE32_DNSCURVE.encode_mut(input, output)); + b.iter(|| data_encoding::BASE32_DNSCURVE.encode_mut(input, output)); } diff --git a/lib/fuzz/Cargo.toml b/lib/fuzz/Cargo.toml index d54b745..0e9cdae 100644 --- a/lib/fuzz/Cargo.toml +++ b/lib/fuzz/Cargo.toml @@ -30,10 +30,3 @@ 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"] diff --git a/lib/fuzz/fuzz_targets/v3-preview.rs b/lib/fuzz/fuzz_targets/v3-preview.rs deleted file mode 100644 index 80112cf..0000000 --- a/lib/fuzz/fuzz_targets/v3-preview.rs +++ /dev/null @@ -1,98 +0,0 @@ -#![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); -}); diff --git a/lib/macro/Cargo.toml b/lib/macro/Cargo.toml index 78ab99b..773bbf5 100644 --- a/lib/macro/Cargo.toml +++ b/lib/macro/Cargo.toml @@ -14,5 +14,5 @@ description = "Macros for data-encoding" include = ["Cargo.toml", "LICENSE", "README.md", "src/lib.rs"] [dependencies] -data-encoding = { version = "2.6.1-git", path = "..", default-features = false } +data-encoding = { version = "2.7.0-git", path = "..", default-features = false } data-encoding-macro-internal = { version = "0.1.14-git", path = "internal" } diff --git a/lib/macro/internal/Cargo.toml b/lib/macro/internal/Cargo.toml index f39a829..2b9b259 100644 --- a/lib/macro/internal/Cargo.toml +++ b/lib/macro/internal/Cargo.toml @@ -14,7 +14,7 @@ include = ["Cargo.toml", "LICENSE", "README.md", "src/lib.rs"] proc-macro = true [dependencies.data-encoding] -version = "2.6.1-git" +version = "2.7.0-git" path = "../.." default-features = false features = ["alloc"] diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 1653f07..e169c10 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -184,9 +184,6 @@ macro_rules! check { }; } -#[cfg(feature = "v3-preview")] -pub mod v3_preview; - trait Static: Copy { fn val(self) -> T; } diff --git a/lib/src/v3_preview.rs b/lib/src/v3_preview.rs deleted file mode 100644 index bf6bcde..0000000 --- a/lib/src/v3_preview.rs +++ /dev/null @@ -1,1275 +0,0 @@ -//! Provides an unstable preview of the 3.0.0 version. -//! -//! This module is gated by the `v3-preview` feature. This feature and this module are unstable in -//! the sense that breaking changes are only considered minor changes instead of major changes. In -//! particular, you should use the tilde requirement `~2.6.0` instead of the default caret -//! requirement `2.6.0` (or explicitly `^2.6.0`). For more information, consult the [SemVer -//! compatibility][semver] section of the Cargo Book. -//! -//! This feature and this module also have a different MSRV: 1.70 instead of 1.48. -//! -//! [semver]: https://doc.rust-lang.org/cargo/reference/resolver.html#semver-compatibility - -#![warn(let_underscore_drop)] -#![warn(unsafe_op_in_unsafe_fn)] -#![allow(clippy::incompatible_msrv)] -#![allow(clippy::match_bool)] - -#[cfg(feature = "alloc")] -use alloc::borrow::Cow; -#[cfg(feature = "alloc")] -use alloc::string::String; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -use core::convert::{TryFrom, TryInto as _}; -use core::marker::PhantomData; -use core::mem::MaybeUninit; - -#[cfg(feature = "alloc")] -pub use crate::Specification; -use crate::{ - chunk_mut_unchecked, chunk_unchecked, dec, div_ceil, enc, floor, order, vectorize, - InternalEncoding, IGNORE, PADDING, -}; -pub use crate::{DecodeError, DecodeKind, DecodePartial, Encoding as DynEncoding}; - -/// Type-level bit-width of an encoding. -pub trait BitWidth: sealed::BitWidth {} - -/// Type-level bool. -pub trait Bool: sealed::Bool {} - -mod sealed { - pub trait BitWidth { - const VAL: usize; - } - - pub trait Bool { - type If: Copy; - const VAL: bool; - fn open(cond: Self::If) -> If; - fn make( - then: impl FnOnce() -> Then, else_: impl FnOnce() -> Else, - ) -> Self::If; - } - - #[derive(Debug, Copy, Clone)] - pub enum If { - Then(Then), - Else(Else), - } -} -use sealed::If; - -macro_rules! new_bit_width { - ($(($N:ident, $v:expr, $b:literal),)*) => { - $( - #[doc = concat!(" Bit-width of ", $b, " encodings.")] - #[derive(Debug)] - pub enum $N {} - impl BitWidth for $N {} - impl sealed::BitWidth for $N { const VAL: usize = $v; } - )* - }; -} -new_bit_width![ - (Bit1, 1, "base2"), - (Bit2, 2, "base4"), - (Bit3, 3, "base8"), - (Bit4, 4, "base16"), - (Bit5, 5, "base32"), - (Bit6, 6, "base64"), -]; - -/// Type-level false. -#[derive(Debug)] -pub enum False {} -impl Bool for False {} -impl sealed::Bool for False { - type If = Else; - const VAL: bool = false; - fn open(cond: Self::If) -> If { - If::Else(cond) - } - fn make( - _then: impl FnOnce() -> Then, else_: impl FnOnce() -> Else, - ) -> Self::If { - else_() - } -} - -/// Type-level true. -#[derive(Debug, Copy, Clone)] -pub enum True {} -impl Bool for True {} -impl sealed::Bool for True { - type If = Then; - const VAL: bool = true; - fn open(cond: Self::If) -> If { - If::Then(cond) - } - fn make( - then: impl FnOnce() -> Then, _else: impl FnOnce() -> Else, - ) -> Self::If { - then() - } -} - -// TODO(https://github.com/rust-lang/rust/issues/79995): Use write_slice() instead. -unsafe fn copy_from_slice(dst: &mut [MaybeUninit], src: &[u8]) { - dst.copy_from_slice(unsafe { &*(src as *const [u8] as *const [MaybeUninit]) }); -} - -// TODO(https://github.com/rust-lang/rust/issues/63569): Use slice_assume_init_mut() instead. -unsafe fn slice_assume_init_mut(xs: &mut [MaybeUninit]) -> &mut [u8] { - unsafe { &mut *(xs as *mut [MaybeUninit] as *mut [u8]) } -} - -unsafe fn slice_uninit_mut(xs: &mut [u8]) -> &mut [MaybeUninit] { - unsafe { &mut *(xs as *mut [u8] as *mut [MaybeUninit]) } -} - -#[cfg(feature = "alloc")] -fn reserve_spare(xs: &mut Vec, n: usize) -> &mut [MaybeUninit] { - xs.reserve(n); - &mut xs.spare_capacity_mut()[.. n] -} - -fn encode_len(len: usize) -> usize { - div_ceil(8 * len, Bit::VAL) -} - -fn encode_block( - symbols: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) { - debug_assert!(input.len() <= enc(Bit::VAL)); - debug_assert_eq!(output.len(), encode_len::(input.len())); - let bit = Bit::VAL; - let msb = Msb::VAL; - let mut x = 0u64; - for (i, input) in input.iter().enumerate() { - x |= u64::from(*input) << (8 * order(msb, enc(bit), i)); - } - for (i, output) in output.iter_mut().enumerate() { - let y = x >> (bit * order(msb, dec(bit), i)); - let _ = output.write(symbols[(y & 0xff) as usize]); - } -} - -fn encode_mut( - symbols: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) { - debug_assert_eq!(output.len(), encode_len::(input.len())); - let bit = Bit::VAL; - let enc = enc(bit); - let dec = dec(bit); - let n = input.len() / enc; - let bs = match bit { - 5 => 2, - 6 => 4, - _ => 1, - }; - vectorize(n, bs, |i| { - let input = unsafe { chunk_unchecked(input, enc, i) }; - let output = unsafe { chunk_mut_unchecked(output, dec, i) }; - encode_block::(symbols, input, output); - }); - encode_block::(symbols, &input[enc * n ..], &mut output[dec * n ..]); -} - -// Fails if an input character does not translate to a symbol. The error is the -// lowest index of such character. The output is not written to. -fn decode_block( - values: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) -> Result<(), usize> { - debug_assert!(output.len() <= enc(Bit::VAL)); - debug_assert_eq!(input.len(), encode_len::(output.len())); - let bit = Bit::VAL; - let msb = Msb::VAL; - let mut x = 0u64; - for j in 0 .. input.len() { - let y = values[input[j] as usize]; - check!(j, y < 1 << bit); - x |= u64::from(y) << (bit * order(msb, dec(bit), j)); - } - for (j, output) in output.iter_mut().enumerate() { - let _ = output.write((x >> (8 * order(msb, enc(bit), j)) & 0xff) as u8); - } - Ok(()) -} - -// Fails if an input character does not translate to a symbol. The error `pos` -// is the lowest index of such character. The output is valid up to `pos / dec * -// enc` excluded. -fn decode_mut( - values: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) -> Result<(), usize> { - debug_assert_eq!(input.len(), encode_len::(output.len())); - let bit = Bit::VAL; - let enc = enc(bit); - let dec = dec(bit); - let n = input.len() / dec; - for i in 0 .. n { - let input = unsafe { chunk_unchecked(input, dec, i) }; - let output = unsafe { chunk_mut_unchecked(output, enc, i) }; - decode_block::(values, input, output).map_err(|e| dec * i + e)?; - } - decode_block::(values, &input[dec * n ..], &mut output[enc * n ..]) - .map_err(|e| dec * n + e) -} - -// Fails if there are non-zero trailing bits. -fn check_trail( - ctb: bool, values: &[u8; 256], input: &[u8], -) -> Result<(), ()> { - if 8 % Bit::VAL == 0 || !ctb { - return Ok(()); - } - let trail = Bit::VAL * input.len() % 8; - if trail == 0 { - return Ok(()); - } - let mut mask = (1 << trail) - 1; - if !Msb::VAL { - mask <<= Bit::VAL - trail; - } - check!((), values[input[input.len() - 1] as usize] & mask == 0); - Ok(()) -} - -// Fails if the padding length is invalid. The error is the index of the first -// padding character. -fn check_pad(values: &[u8; 256], input: &[u8]) -> Result { - let bit = Bit::VAL; - debug_assert_eq!(input.len(), dec(bit)); - let is_pad = |x: &&u8| values[**x as usize] == PADDING; - let count = input.iter().rev().take_while(is_pad).count(); - let len = input.len() - count; - check!(len, len > 0 && bit * len % 8 < bit); - Ok(len) -} - -fn encode_base_len(len: usize) -> usize { - encode_len::(len) -} - -fn encode_base( - symbols: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) { - debug_assert_eq!(output.len(), encode_base_len::(input.len())); - encode_mut::(symbols, input, output); -} - -fn encode_pad_len(len: usize) -> usize { - match Pad::VAL { - false => encode_base_len::(len), - true => div_ceil(len, enc(Bit::VAL)) * dec(Bit::VAL), - } -} - -fn encode_pad( - symbols: &[u8; 256], pad: Pad::If, input: &[u8], output: &mut [MaybeUninit], -) { - let pad = match Pad::open(pad) { - If::Then(x) => x, - If::Else(()) => return encode_base::(symbols, input, output), - }; - debug_assert_eq!(output.len(), encode_pad_len::(input.len())); - let olen = encode_base_len::(input.len()); - encode_base::(symbols, input, &mut output[.. olen]); - for output in output.iter_mut().skip(olen) { - let _ = output.write(pad); - } -} - -fn encode_wrap_len( - wrap: Wrap::If<(usize, &[u8]), ()>, ilen: usize, -) -> usize { - let olen = encode_pad_len::(ilen); - match Wrap::open(wrap) { - If::Then((col, end)) => olen + end.len() * div_ceil(olen, col), - If::Else(()) => olen, - } -} - -fn encode_wrap_mut( - symbols: &[u8; 256], pad: Pad::If, wrap: Wrap::If<(usize, &[u8]), ()>, input: &[u8], - output: &mut [MaybeUninit], -) { - let (col, end) = match Wrap::open(wrap) { - If::Then((col, end)) => (col, end), - If::Else(()) => return encode_pad::(symbols, pad, input, output), - }; - debug_assert_eq!(output.len(), encode_wrap_len::(wrap, input.len())); - debug_assert_eq!(col % dec(Bit::VAL), 0); - let bit = Bit::VAL; - let col = col / dec(bit); - let enc = col * enc(bit); - let dec = col * dec(bit) + end.len(); - let olen = dec - end.len(); - let n = input.len() / enc; - for i in 0 .. n { - let input = unsafe { chunk_unchecked(input, enc, i) }; - let output = unsafe { chunk_mut_unchecked(output, dec, i) }; - encode_base::(symbols, input, &mut output[.. olen]); - unsafe { copy_from_slice(&mut output[olen ..], end) }; - } - if input.len() > enc * n { - let olen = dec * n + encode_pad_len::(input.len() - enc * n); - encode_pad::(symbols, pad, &input[enc * n ..], &mut output[dec * n .. olen]); - unsafe { copy_from_slice(&mut output[olen ..], end) }; - } -} - -// Returns the longest valid input length and associated output length. -fn decode_wrap_len(len: usize) -> (usize, usize) { - let bit = Bit::VAL; - if Pad::VAL { - (floor(len, dec(bit)), len / dec(bit) * enc(bit)) - } else { - let trail = bit * len % 8; - (len - trail / bit, bit * len / 8) - } -} - -// Fails with Length if length is invalid. The error is the largest valid -// length. -fn decode_pad_len(len: usize) -> Result { - let (ilen, olen) = decode_wrap_len::(len); - check!(DecodeError { position: ilen, kind: DecodeKind::Length }, ilen == len); - Ok(olen) -} - -// Fails with Length if length is invalid. The error is the largest valid -// length. -fn decode_base_len(len: usize) -> Result { - decode_pad_len::(len) -} - -// Fails with Symbol if an input character does not translate to a symbol. The -// error is the lowest index of such character. -// Fails with Trailing if there are non-zero trailing bits. -fn decode_base_mut( - ctb: bool, values: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) -> Result { - debug_assert_eq!(Ok(output.len()), decode_base_len::(input.len())); - let bit = Bit::VAL; - let fail = |pos, kind| DecodePartial { - read: pos / dec(bit) * dec(bit), - written: pos / dec(bit) * enc(bit), - error: DecodeError { position: pos, kind }, - }; - decode_mut::(values, input, output).map_err(|pos| fail(pos, DecodeKind::Symbol))?; - check_trail::(ctb, values, input) - .map_err(|()| fail(input.len() - 1, DecodeKind::Trailing))?; - Ok(output.len()) -} - -// Fails with Symbol if an input character does not translate to a symbol. The -// error is the lowest index of such character. -// Fails with Padding if some padding length is invalid. The error is the index -// of the first padding character of the invalid padding. -// Fails with Trailing if there are non-zero trailing bits. -fn decode_pad_mut( - ctb: bool, values: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) -> Result { - if !Pad::VAL { - return decode_base_mut::(ctb, values, input, output); - } - debug_assert_eq!(Ok(output.len()), decode_pad_len::(input.len())); - let bit = Bit::VAL; - let enc = enc(bit); - let dec = dec(bit); - let mut inpos = 0; - let mut outpos = 0; - let mut outend = output.len(); - while inpos < input.len() { - match decode_base_mut::( - ctb, - values, - &input[inpos ..], - &mut output[outpos .. outend], - ) { - Ok(written) => { - if cfg!(debug_assertions) { - inpos = input.len(); - } - outpos += written; - break; - } - Err(partial) => { - inpos += partial.read; - outpos += partial.written; - } - } - let inlen = check_pad::(values, &input[inpos .. inpos + dec]).map_err(|pos| { - DecodePartial { - read: inpos, - written: outpos, - error: DecodeError { position: inpos + pos, kind: DecodeKind::Padding }, - } - })?; - let outlen = decode_base_len::(inlen).unwrap(); - let written = decode_base_mut::( - ctb, - values, - &input[inpos .. inpos + inlen], - &mut output[outpos .. outpos + outlen], - ) - .map_err(|partial| { - debug_assert_eq!(partial.read, 0); - debug_assert_eq!(partial.written, 0); - DecodePartial { - read: inpos, - written: outpos, - error: DecodeError { - position: inpos + partial.error.position, - kind: partial.error.kind, - }, - } - })?; - debug_assert_eq!(written, outlen); - inpos += dec; - outpos += outlen; - outend -= enc - outlen; - } - debug_assert_eq!(inpos, input.len()); - debug_assert_eq!(outpos, outend); - Ok(outend) -} - -fn skip_ignore(values: &[u8; 256], input: &[u8], mut inpos: usize) -> usize { - while inpos < input.len() && values[input[inpos] as usize] == IGNORE { - inpos += 1; - } - inpos -} - -// Returns next input and output position. -// Fails with Symbol if an input character does not translate to a symbol. The -// error is the lowest index of such character. -// Fails with Padding if some padding length is invalid. The error is the index -// of the first padding character of the invalid padding. -// Fails with Trailing if there are non-zero trailing bits. -fn decode_wrap_block( - ctb: bool, values: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) -> Result<(usize, usize), DecodeError> { - let bit = Bit::VAL; - let dec = dec(bit); - let mut buf = [0u8; 8]; - let mut shift = [0usize; 8]; - let mut bufpos = 0; - let mut inpos = 0; - while bufpos < dec { - inpos = skip_ignore(values, input, inpos); - if inpos == input.len() { - break; - } - shift[bufpos] = inpos; - buf[bufpos] = input[inpos]; - bufpos += 1; - inpos += 1; - } - let olen = decode_pad_len::(bufpos).map_err(|mut e| { - e.position = shift[e.position]; - e - })?; - let written = - decode_pad_mut::(ctb, values, &buf[.. bufpos], &mut output[.. olen]) - .map_err(|partial| { - debug_assert_eq!(partial.read, 0); - debug_assert_eq!(partial.written, 0); - DecodeError { position: shift[partial.error.position], kind: partial.error.kind } - })?; - Ok((inpos, written)) -} - -// Fails with Symbol if an input character does not translate to a symbol. The -// error is the lowest index of such character. -// Fails with Padding if some padding length is invalid. The error is the index -// of the first padding character of the invalid padding. -// Fails with Trailing if there are non-zero trailing bits. -// Fails with Length if input length (without ignored characters) is invalid. -fn decode_wrap_mut( - ctb: bool, values: &[u8; 256], input: &[u8], output: &mut [MaybeUninit], -) -> Result { - if !Ignore::VAL { - return decode_pad_mut::(ctb, values, input, output); - } - debug_assert_eq!(output.len(), decode_wrap_len::(input.len()).1); - let mut inpos = 0; - let mut outpos = 0; - while inpos < input.len() { - let (inlen, outlen) = decode_wrap_len::(input.len() - inpos); - match decode_pad_mut::( - ctb, - values, - &input[inpos .. inpos + inlen], - &mut output[outpos .. outpos + outlen], - ) { - Ok(written) => { - inpos += inlen; - outpos += written; - break; - } - Err(partial) => { - inpos += partial.read; - outpos += partial.written; - } - } - let (ipos, opos) = decode_wrap_block::( - ctb, - values, - &input[inpos ..], - &mut output[outpos ..], - ) - .map_err(|mut error| { - error.position += inpos; - DecodePartial { read: inpos, written: outpos, error } - })?; - inpos += ipos; - outpos += opos; - } - let inpos = skip_ignore(values, input, inpos); - if inpos == input.len() { - Ok(outpos) - } else { - Err(DecodePartial { - read: inpos, - written: outpos, - error: DecodeError { position: inpos, kind: DecodeKind::Length }, - }) - } -} - -/// Error converting from a dynamic encoding to a static one. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ConvertError { - /// Different bit-width. - BitWidth, - - /// Different bit-order. - BitOrder, - - /// Different padding. - Padding, - - /// Different wrap. - Wrap, - - /// Different ignore. - Ignore, -} - -/// Base-conversion encoding. -/// -/// See [`Specification`] for technical details or how to define a new one. -#[derive(Debug, Clone)] -#[repr(transparent)] -pub struct Encoding { - // The config match the fields in data. In particular, we have the following properties: - // - If Bit is Bit1, Bit2, or Bit4 then Pad is False. - // - If Wrap is True, then Ignore is True. - data: InternalEncoding, - _type: PhantomData<(Bit, Msb, Pad, Wrap, Ignore)>, -} - -impl PartialEq - for Encoding -{ - fn eq(&self, other: &Self) -> bool { - self.data == other.data - } -} - -impl Eq - for Encoding -{ -} - -impl - Encoding -{ - fn sym(&self) -> &[u8; 256] { - self.data[0 .. 256].try_into().unwrap() - } - - fn val(&self) -> &[u8; 256] { - self.data[256 .. 512].try_into().unwrap() - } - - fn pad(&self) -> Pad::If { - Pad::make(|| self.data[512], || ()) - } - - fn ctb(&self) -> bool { - self.data[513] & 0x10 != 0 - } - - fn wrap(&self) -> Wrap::If<(usize, &[u8]), ()> { - Wrap::make(|| (self.data[514] as usize, &self.data[515 ..]), || ()) - } - - fn has_ignore(&self) -> bool { - self.data.len() >= 515 - } - - /// Minimum number of input and output blocks when encoding. - fn block_len(&self) -> (usize, usize) { - let bit = Bit::VAL; - match Wrap::open(self.wrap()) { - If::Then((col, end)) => (col / dec(bit) * enc(bit), col + end.len()), - If::Else(()) => (enc(bit), dec(bit)), - } - } - - /// Returns the encoded length of an input of length `len`. - /// - /// See [`Self::encode_mut()`] for when to use it. - #[must_use] - pub fn encode_len(&self, len: usize) -> usize { - encode_wrap_len::(self.wrap(), len) - } - - /// Encodes `input` in `output`. - /// - /// # Panics - /// - /// Panics if the `output` length does not match the result of [`Self::encode_len()`] for the - /// `input` length. - pub fn encode_mut_uninit<'a>( - &self, input: &[u8], output: &'a mut [MaybeUninit], - ) -> &'a mut [u8] { - assert_eq!(output.len(), self.encode_len(input.len())); - encode_wrap_mut::(self.sym(), self.pad(), self.wrap(), input, output); - unsafe { slice_assume_init_mut(output) } - } - - /// Encodes `input` in `output`. - /// - /// # Panics - /// - /// Panics if the `output` length does not match the result of [`Self::encode_len()`] for the - /// `input` length. - pub fn encode_mut(&self, input: &[u8], output: &mut [u8]) { - let _ = self.encode_mut_uninit(input, unsafe { slice_uninit_mut(output) }); - } - - /// Appends the encoding of `input` to `output`. - #[cfg(feature = "alloc")] - pub fn encode_append(&self, input: &[u8], output: &mut String) { - let output = unsafe { output.as_mut_vec() }; - let output_len = output.len(); - let len = self.encode_len(input.len()); - let _len = self.encode_mut_uninit(input, reserve_spare(output, len)).len(); - debug_assert_eq!(len, _len); - unsafe { output.set_len(output_len + len) }; - } - - /// Returns an object to encode a fragmented input and append it to `output`. - /// - /// See the documentation of [`Encoder`] for more details and examples. - #[cfg(feature = "alloc")] - pub fn new_encoder<'a>( - &'a self, output: &'a mut String, - ) -> Encoder<'a, Bit, Msb, Pad, Wrap, Ignore> { - Encoder::new(self, output) - } - - /// Writes the encoding of `input` to `output` using a temporary `buffer`. - /// - /// # Panics - /// - /// Panics if the buffer is shorter than 510 bytes. - /// - /// # Errors - /// - /// Returns an error when writing to the output fails. - pub fn encode_write_buffer_uninit( - &self, input: &[u8], output: &mut impl core::fmt::Write, buffer: &mut [MaybeUninit], - ) -> core::fmt::Result { - assert!(510 <= buffer.len()); - let (enc, dec) = self.block_len(); - for input in input.chunks(buffer.len() / dec * enc) { - let buffer = &mut buffer[.. self.encode_len(input.len())]; - let buffer = self.encode_mut_uninit(input, buffer); - output.write_str(unsafe { core::str::from_utf8_unchecked(buffer) })?; - } - Ok(()) - } - - /// Writes the encoding of `input` to `output` using a temporary `buffer`. - /// - /// # Panics - /// - /// Panics if the buffer is shorter than 510 bytes. - /// - /// # Errors - /// - /// Returns an error when writing to the output fails. - pub fn encode_write_buffer( - &self, input: &[u8], output: &mut impl core::fmt::Write, buffer: &mut [u8], - ) -> core::fmt::Result { - self.encode_write_buffer_uninit(input, output, unsafe { slice_uninit_mut(buffer) }) - } - - /// Writes the encoding of `input` to `output`. - /// - /// This allocates a buffer of 1024 bytes on the stack. If you want to control the buffer size - /// and location, use [`Self::encode_write_buffer()`] instead. - /// - /// # Errors - /// - /// Returns an error when writing to the output fails. - pub fn encode_write( - &self, input: &[u8], output: &mut impl core::fmt::Write, - ) -> core::fmt::Result { - self.encode_write_buffer(input, output, &mut [0; 1024]) - } - - /// Returns encoded `input`. - #[cfg(feature = "alloc")] - #[must_use] - pub fn encode(&self, input: &[u8]) -> String { - let mut output = Vec::new(); - let len = self.encode_len(input.len()); - let _len = self.encode_mut_uninit(input, reserve_spare(&mut output, len)).len(); - debug_assert_eq!(len, _len); - unsafe { output.set_len(len) }; - unsafe { String::from_utf8_unchecked(output) } - } - - /// Returns the decoded length of an input of length `len`. - /// - /// See [`Self::decode_mut()`] for when to use it. - /// - /// # Errors - /// - /// Returns an error if `len` is invalid. The error [kind][DecodeError::kind] is - /// [`DecodeKind::Length`] and the error [position][DecodeError::position] is the greatest valid - /// input length. - pub fn decode_len(&self, len: usize) -> Result { - let (ilen, olen) = decode_wrap_len::(len); - check!( - DecodeError { position: ilen, kind: DecodeKind::Length }, - self.has_ignore() || len == ilen - ); - Ok(olen) - } - - /// Decodes `input` in `output`. - /// - /// Returns the decoded output. Its length may be smaller than the output length if the input - /// contained padding or ignored characters. The output bytes after the returned length are not - /// initialized and should not be read. - /// - /// # Panics - /// - /// Panics if the `output` length does not match the result of [`Self::decode_len()`] for the - /// `input` length. Also panics if `decode_len` fails for the `input` length. - /// - /// # Errors - /// - /// Returns an error if `input` is invalid. See [`Self::decode_mut()`] for more details. - pub fn decode_mut_uninit<'a>( - &self, input: &[u8], output: &'a mut [MaybeUninit], - ) -> Result<&'a mut [u8], DecodePartial> { - assert_eq!(Ok(output.len()), self.decode_len(input.len())); - let len = decode_wrap_mut::(self.ctb(), self.val(), input, output)?; - Ok(unsafe { slice_assume_init_mut(&mut output[.. len]) }) - } - - /// Decodes `input` in `output`. - /// - /// Returns the length of the decoded output. This length may be smaller than the output length - /// if the input contained padding or ignored characters. The output bytes after the returned - /// length are not initialized and should not be read. - /// - /// # Panics - /// - /// Panics if the `output` length does not match the result of [`Self::decode_len()`] for the - /// `input` length. Also panics if `decode_len` fails for the `input` length. - /// - /// # Errors - /// - /// Returns an error if `input` is invalid. See [`Self::decode()`] for more details. The are two - /// differences though: - /// - /// - [`DecodeKind::Length`] may be returned only if the encoding allows ignored characters, - /// because otherwise this is already checked by [`Self::decode_len()`]. - /// - The [`DecodePartial::read`] first bytes of the input have been successfully decoded to the - /// [`DecodePartial::written`] first bytes of the output. - pub fn decode_mut(&self, input: &[u8], output: &mut [u8]) -> Result { - Ok(self.decode_mut_uninit(input, unsafe { slice_uninit_mut(output) })?.len()) - } - - /// Returns decoded `input`. - /// - /// # Errors - /// - /// Returns an error if `input` is invalid. The error kind can be: - /// - /// - [`DecodeKind::Length`] if the input length is invalid. The [position] is the greatest - /// valid input length. - /// - [`DecodeKind::Symbol`] if the input contains an invalid character. The [position] is the - /// first invalid character. - /// - [`DecodeKind::Trailing`] if the input has non-zero trailing bits. This is only possible if - /// the encoding checks trailing bits. The [position] is the first character containing - /// non-zero trailing bits. - /// - [`DecodeKind::Padding`] if the input has an invalid padding length. This is only possible - /// if the encoding uses padding. The [position] is the first padding character of the first - /// padding of invalid length. - /// - /// [position]: DecodeError::position - #[cfg(feature = "alloc")] - pub fn decode(&self, input: &[u8]) -> Result, DecodeError> { - let max_len = self.decode_len(input.len())?; - let mut output = Vec::new(); - let len = self - .decode_mut_uninit(input, reserve_spare(&mut output, max_len)) - .map_err(|partial| partial.error)? - .len(); - unsafe { output.set_len(len) }; - Ok(output) - } - - #[doc(hidden)] - #[must_use] - pub const unsafe fn new_unchecked(data: &'static [u8]) -> Self { - #[cfg(feature = "alloc")] - let data = Cow::Borrowed(data); - Encoding { data, _type: PhantomData } - } - - fn check_compatible(base: &DynEncoding) -> Result<(), ConvertError> { - check!(ConvertError::BitWidth, base.bit() == Bit::VAL); - check!(ConvertError::BitOrder, base.msb() == Msb::VAL); - check!(ConvertError::Padding, base.pad().is_some() == Pad::VAL); - check!(ConvertError::Wrap, base.wrap().is_some() == Wrap::VAL); - check!(ConvertError::Ignore, base.has_ignore() == Ignore::VAL); - Ok(()) - } -} - -/// Encodes fragmented input to an output. -/// -/// It is equivalent to use an [`Encoder`] with multiple calls to [`Encoder::append()`] than to -/// first concatenate all the input and then use [`Encoding::encode_append()`]. In particular, this -/// function will not introduce padding or wrapping between inputs. -#[cfg(feature = "alloc")] -#[derive(Debug)] -pub struct Encoder<'a, Bit: BitWidth, Msb: Bool, Pad: Bool, Wrap: Bool, Ignore: Bool> { - encoding: &'a Encoding, - output: &'a mut String, - buffer: [u8; 255], - length: u8, -} - -#[cfg(feature = "alloc")] -impl<'a, Bit: BitWidth, Msb: Bool, Pad: Bool, Wrap: Bool, Ignore: Bool> Drop - for Encoder<'a, Bit, Msb, Pad, Wrap, Ignore> -{ - fn drop(&mut self) { - self.encoding.encode_append(&self.buffer[.. self.length as usize], self.output); - } -} - -#[cfg(feature = "alloc")] -impl<'a, Bit: BitWidth, Msb: Bool, Pad: Bool, Wrap: Bool, Ignore: Bool> - Encoder<'a, Bit, Msb, Pad, Wrap, Ignore> -{ - fn new(encoding: &'a Encoding, output: &'a mut String) -> Self { - Encoder { encoding, output, buffer: [0; 255], length: 0 } - } - - /// Encodes the provided input fragment and appends the result to the output. - pub fn append(&mut self, mut input: &[u8]) { - #[allow(clippy::cast_possible_truncation)] // no truncation - let max = self.encoding.block_len().0 as u8; - if self.length != 0 { - let len = self.length; - #[allow(clippy::cast_possible_truncation)] // no truncation - let add = core::cmp::min((max - len) as usize, input.len()) as u8; - self.buffer[len as usize ..][.. add as usize].copy_from_slice(&input[.. add as usize]); - self.length += add; - input = &input[add as usize ..]; - if self.length != max { - debug_assert!(self.length < max); - debug_assert!(input.is_empty()); - return; - } - self.encoding.encode_append(&self.buffer[.. max as usize], self.output); - self.length = 0; - } - let len = floor(input.len(), max as usize); - self.encoding.encode_append(&input[.. len], self.output); - input = &input[len ..]; - #[allow(clippy::cast_possible_truncation)] // no truncation - let len = input.len() as u8; - self.buffer[.. len as usize].copy_from_slice(input); - self.length = len; - } - - /// Makes sure all inputs have been encoded and appended to the output. - /// - /// This is equivalent to dropping the encoder and required for correctness, otherwise some - /// encoded data may be missing at the end. - pub fn finalize(self) {} -} - -impl TryFrom - for Encoding -{ - type Error = ConvertError; - - fn try_from(base: DynEncoding) -> Result { - Encoding::::check_compatible(&base)?; - Ok(Encoding { data: base.0, _type: PhantomData }) - } -} - -impl - From> for DynEncoding -{ - fn from(base: Encoding) -> Self { - DynEncoding(base.data) - } -} - -impl<'a, Bit: BitWidth, Msb: Bool, Pad: Bool, Wrap: Bool, Ignore: Bool> TryFrom<&'a DynEncoding> - for &'a Encoding -{ - type Error = ConvertError; - - fn try_from(base: &'a DynEncoding) -> Result { - Encoding::::check_compatible(base)?; - Ok(unsafe { - &*(base as *const DynEncoding).cast::>() - }) - } -} - -impl<'a, Bit: BitWidth, Msb: Bool, Pad: Bool, Wrap: Bool, Ignore: Bool> - From<&'a Encoding> for &'a DynEncoding -{ - fn from(base: &'a Encoding) -> Self { - unsafe { &*(base as *const Encoding).cast::() } - } -} - -/// Hexadecimal encoding. -pub type Hex = Encoding; - -/// Base32 encoding. -pub type Base32 = Encoding; - -/// Base32 encoding (no padding). -pub type Base32NoPad = Encoding; - -/// Base32 encoding (LSB first, no padding). -pub type Base32LsbNoPad = Encoding; - -/// Base64 encoding. -pub type Base64 = Encoding; - -/// Base64 encoding (no padding). -pub type Base64NoPad = Encoding; - -/// Base64 encoding (wrap). -pub type Base64Wrap = Encoding; - -/// Lowercase hexadecimal encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Hex, HEXLOWER}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789abcdef"); -/// assert_eq!(HEXLOWER, Hex::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static HEXLOWER: Hex = unsafe { Hex::new_unchecked(crate::HEXLOWER_IMPL) }; - -/// Lowercase hexadecimal encoding with case-insensitive decoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Hex, HEXLOWER_PERMISSIVE}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789abcdef"); -/// spec.translate.from.push_str("ABCDEF"); -/// spec.translate.to.push_str("abcdef"); -/// assert_eq!(HEXLOWER_PERMISSIVE, Hex::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static HEXLOWER_PERMISSIVE: Hex = - unsafe { Hex::new_unchecked(crate::HEXLOWER_PERMISSIVE_IMPL) }; - -/// Uppercase hexadecimal encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Hex, HEXUPPER}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789ABCDEF"); -/// assert_eq!(HEXUPPER, Hex::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It is compliant with [RFC4648] and known as "base16" or "hex". -/// -/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-8 -pub static HEXUPPER: Hex = unsafe { Hex::new_unchecked(crate::HEXUPPER_IMPL) }; - -/// Uppercase hexadecimal encoding with case-insensitive decoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Hex, HEXUPPER_PERMISSIVE}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789ABCDEF"); -/// spec.translate.from.push_str("abcdef"); -/// spec.translate.to.push_str("ABCDEF"); -/// assert_eq!(HEXUPPER_PERMISSIVE, Hex::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static HEXUPPER_PERMISSIVE: Hex = - unsafe { Hex::new_unchecked(crate::HEXUPPER_PERMISSIVE_IMPL) }; - -/// Padded base32 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base32, BASE32}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"); -/// spec.padding = Some('='); -/// assert_eq!(BASE32, Base32::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It conforms to [RFC4648]. -/// -/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-6 -pub static BASE32: Base32 = unsafe { Base32::new_unchecked(crate::BASE32_IMPL) }; - -/// Unpadded base32 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base32NoPad, BASE32_NOPAD}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"); -/// assert_eq!(BASE32_NOPAD, Base32NoPad::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static BASE32_NOPAD: Base32NoPad = - unsafe { Base32NoPad::new_unchecked(crate::BASE32_NOPAD_IMPL) }; - -/// Padded base32hex encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base32, BASE32HEX}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789ABCDEFGHIJKLMNOPQRSTUV"); -/// spec.padding = Some('='); -/// assert_eq!(BASE32HEX, Base32::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It conforms to [RFC4648]. -/// -/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-7 -pub static BASE32HEX: Base32 = unsafe { Base32::new_unchecked(crate::BASE32HEX_IMPL) }; - -/// Unpadded base32hex encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base32NoPad, BASE32HEX_NOPAD}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789ABCDEFGHIJKLMNOPQRSTUV"); -/// assert_eq!(BASE32HEX_NOPAD, Base32NoPad::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static BASE32HEX_NOPAD: Base32NoPad = - unsafe { Base32NoPad::new_unchecked(crate::BASE32HEX_NOPAD_IMPL) }; - -/// DNSSEC base32 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base32NoPad, BASE32_DNSSEC}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789abcdefghijklmnopqrstuv"); -/// spec.translate.from.push_str("ABCDEFGHIJKLMNOPQRSTUV"); -/// spec.translate.to.push_str("abcdefghijklmnopqrstuv"); -/// assert_eq!(BASE32_DNSSEC, Base32NoPad::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It conforms to [RFC5155]: -/// -/// - It uses a base32 extended hex alphabet. -/// - It is case-insensitive when decoding and uses lowercase when encoding. -/// - It does not use padding. -/// -/// [RFC5155]: https://tools.ietf.org/html/rfc5155 -pub static BASE32_DNSSEC: Base32NoPad = - unsafe { Base32NoPad::new_unchecked(crate::BASE32_DNSSEC_IMPL) }; - -#[allow(clippy::doc_markdown)] -/// DNSCurve base32 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::{BitOrder, Specification}; -/// # use data_encoding::v3_preview::{Base32LsbNoPad, BASE32_DNSCURVE}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("0123456789bcdfghjklmnpqrstuvwxyz"); -/// spec.bit_order = BitOrder::LeastSignificantFirst; -/// spec.translate.from.push_str("BCDFGHJKLMNPQRSTUVWXYZ"); -/// spec.translate.to.push_str("bcdfghjklmnpqrstuvwxyz"); -/// assert_eq!(BASE32_DNSCURVE, Base32LsbNoPad::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It conforms to [DNSCurve]. -/// -/// [DNSCurve]: https://dnscurve.org/in-implement.html -pub static BASE32_DNSCURVE: Base32LsbNoPad = - unsafe { Base32LsbNoPad::new_unchecked(crate::BASE32_DNSCURVE_IMPL) }; - -/// Padded base64 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base64, BASE64}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); -/// spec.padding = Some('='); -/// assert_eq!(BASE64, Base64::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It conforms to [RFC4648]. -/// -/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-4 -pub static BASE64: Base64 = unsafe { Base64::new_unchecked(crate::BASE64_IMPL) }; - -/// Unpadded base64 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base64NoPad, BASE64_NOPAD}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); -/// assert_eq!(BASE64_NOPAD, Base64NoPad::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static BASE64_NOPAD: Base64NoPad = - unsafe { Base64NoPad::new_unchecked(crate::BASE64_NOPAD_IMPL) }; - -/// MIME base64 encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base64Wrap, BASE64_MIME}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); -/// spec.padding = Some('='); -/// spec.wrap.width = 76; -/// spec.wrap.separator.push_str("\r\n"); -/// assert_eq!(BASE64_MIME, Base64Wrap::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It does not exactly conform to [RFC2045] because it does not print the header -/// and does not ignore all characters. -/// -/// [RFC2045]: https://tools.ietf.org/html/rfc2045 -pub static BASE64_MIME: Base64Wrap = unsafe { Base64Wrap::new_unchecked(crate::BASE64_MIME_IMPL) }; - -/// MIME base64 encoding without trailing bits check. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base64Wrap, BASE64_MIME_PERMISSIVE}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); -/// spec.padding = Some('='); -/// spec.wrap.width = 76; -/// spec.wrap.separator.push_str("\r\n"); -/// spec.check_trailing_bits = false; -/// assert_eq!(BASE64_MIME_PERMISSIVE, Base64Wrap::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It does not exactly conform to [RFC2045] because it does not print the header -/// and does not ignore all characters. -/// -/// [RFC2045]: https://tools.ietf.org/html/rfc2045 -pub static BASE64_MIME_PERMISSIVE: Base64Wrap = - unsafe { Base64Wrap::new_unchecked(crate::BASE64_MIME_PERMISSIVE_IMPL) }; - -/// Padded base64url encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base64, BASE64URL}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"); -/// spec.padding = Some('='); -/// assert_eq!(BASE64URL, Base64::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -/// -/// It conforms to [RFC4648]. -/// -/// [RFC4648]: https://tools.ietf.org/html/rfc4648#section-5 -pub static BASE64URL: Base64 = unsafe { Base64::new_unchecked(crate::BASE64URL_IMPL) }; - -/// Unpadded base64url encoding. -/// -/// This encoding is a static version of: -/// -/// ```rust -/// # use data_encoding::Specification; -/// # use data_encoding::v3_preview::{Base64NoPad, BASE64URL_NOPAD}; -/// # use core::convert::TryFrom as _; -/// let mut spec = Specification::new(); -/// spec.symbols.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"); -/// assert_eq!(BASE64URL_NOPAD, Base64NoPad::try_from(spec.encoding().unwrap()).unwrap()); -/// ``` -pub static BASE64URL_NOPAD: Base64NoPad = - unsafe { Base64NoPad::new_unchecked(crate::BASE64URL_NOPAD_IMPL) }; diff --git a/lib/tests/lib.rs b/lib/tests/lib.rs index b34f0f6..9f004de 100644 --- a/lib/tests/lib.rs +++ b/lib/tests/lib.rs @@ -1,41 +1,13 @@ -#[cfg(feature = "v3-preview")] -use core::convert::TryFrom as _; - -#[cfg(not(feature = "v3-preview"))] -use data_encoding as constants; -#[cfg(feature = "v3-preview")] -use data_encoding::v3_preview as constants; -#[cfg(feature = "v3-preview")] -use data_encoding::v3_preview::{ - Bit1, Bit2, Bit3, Bit4, Bit6, BitWidth, Bool, Encoding, False, True, -}; use data_encoding::DecodeKind::*; -#[cfg(not(feature = "v3-preview"))] -use data_encoding::Encoding; -use data_encoding::{DecodeError, Specification}; - -macro_rules! split_v3 { - (fn $name:ident[$($g:tt)*]($base:ident: &Encoding[$($i:tt)*] - $(, $x:ident: $t:ty)* $(,)?) $(-> $r:ty)? { $($body:tt)* } - ) => { - #[cfg(feature = "v3-preview")] - fn $name<$($g)*>($base: &Encoding<$($i)*> $(, $x: $t)*) $(-> $r)? { $($body)* } - #[cfg(not(feature = "v3-preview"))] - fn $name($base: &Encoding $(, $x: $t)*) $(-> $r)? { $($body)* } - }; -} +use data_encoding::{DecodeError, Encoding, Specification}; macro_rules! test { (fn $t: ident; $($s: stmt);*;) => { #[test] fn $t() { - split_v3! { - fn test[Bit: BitWidth, Msb: Bool, Pad: Bool, Wrap: Bool, Ignore: Bool]( - b: &Encoding[Bit, Msb, Pad, Wrap, Ignore], x: &[u8], y: &[u8], - ) { - assert_eq!(&b.encode(x).into_bytes() as &[u8], y); - assert_eq!(&b.decode(y).unwrap() as &[u8], x); - } + fn test(b: &Encoding, x: &[u8], y: &[u8]) { + assert_eq!(&b.encode(x).into_bytes() as &[u8], y); + assert_eq!(&b.decode(y).unwrap() as &[u8], x); } $($s)* } @@ -51,8 +23,6 @@ test! { let mut s = Specification::new(); s.symbols.push_str("01"); let b = s.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); test(&b, b"", b""); test(&b, b"f", b"01100110"); test(&b, b"fo", b"0110011001101111"); @@ -64,8 +34,6 @@ test! { let mut s = Specification::new(); s.symbols.push_str("0123"); let b = s.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); test(&b, b"", b""); test(&b, b"f", b"1212"); test(&b, b"fo", b"12121233"); @@ -81,8 +49,6 @@ test! { s.symbols.push_str("01234567"); s.padding = Some('='); let b = s.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); test(&b, b"", b""); test(&b, b"f", b"314====="); test(&b, b"fo", b"314674=="); @@ -94,7 +60,7 @@ test! { test! { fn hexlower; - let b = &constants::HEXLOWER; + let b = &data_encoding::HEXLOWER; test(b, b"", b""); test(b, b"f", b"66"); test(b, b"fo", b"666f"); @@ -102,14 +68,14 @@ test! { test(b, b"foob", b"666f6f62"); test(b, b"fooba", b"666f6f6261"); test(b, b"foobar", b"666f6f626172"); - assert_eq!(constants::HEXLOWER.decode(b"6f").unwrap(), b"o"); - assert!(constants::HEXLOWER.decode(b"6F").is_err()); - assert_eq!(constants::HEXLOWER_PERMISSIVE.decode(b"6F").unwrap(), b"o"); + assert_eq!(data_encoding::HEXLOWER.decode(b"6f").unwrap(), b"o"); + assert!(data_encoding::HEXLOWER.decode(b"6F").is_err()); + assert_eq!(data_encoding::HEXLOWER_PERMISSIVE.decode(b"6F").unwrap(), b"o"); } test! { fn hexupper; - let b = &constants::HEXUPPER; + let b = &data_encoding::HEXUPPER; test(b, b"", b""); test(b, b"f", b"66"); test(b, b"fo", b"666F"); @@ -117,14 +83,14 @@ test! { test(b, b"foob", b"666F6F62"); test(b, b"fooba", b"666F6F6261"); test(b, b"foobar", b"666F6F626172"); - assert_eq!(constants::HEXUPPER.decode(b"6F").unwrap(), b"o"); - assert!(constants::HEXUPPER.decode(b"6f").is_err()); - assert_eq!(constants::HEXUPPER_PERMISSIVE.decode(b"6f").unwrap(), b"o"); + assert_eq!(data_encoding::HEXUPPER.decode(b"6F").unwrap(), b"o"); + assert!(data_encoding::HEXUPPER.decode(b"6f").is_err()); + assert_eq!(data_encoding::HEXUPPER_PERMISSIVE.decode(b"6f").unwrap(), b"o"); } test! { fn base32; - let b = &constants::BASE32; + let b = &data_encoding::BASE32; test(b, b"", b""); test(b, b"f", b"MY======"); test(b, b"fo", b"MZXQ===="); @@ -136,7 +102,7 @@ test! { test! { fn base32hex; - let b = &constants::BASE32HEX; + let b = &data_encoding::BASE32HEX; test(b, b"", b""); test(b, b"f", b"CO======"); test(b, b"fo", b"CPNG===="); @@ -148,7 +114,7 @@ test! { test! { fn base32_dnscurve; - let b = &constants::BASE32_DNSCURVE; + let b = &data_encoding::BASE32_DNSCURVE; test(b, &[0x64, 0x88], b"4321"); test(b, b"f", b"63"); test(b, b"fo", b"6vv0"); @@ -168,7 +134,7 @@ test! { test! { fn base64; - let b = &constants::BASE64; + let b = &data_encoding::BASE64; test(b, b"", b""); test(b, b"f", b"Zg=="); test(b, b"fo", b"Zm8="); @@ -181,7 +147,7 @@ test! { test! { fn base64url; - let b = &constants::BASE64URL; + let b = &data_encoding::BASE64URL; test(b, b"", b""); test(b, b"f", b"Zg=="); test(b, b"fo", b"Zm8="); @@ -194,7 +160,7 @@ test! { test! { fn base64_no_pad; - let b = &constants::BASE64_NOPAD; + let b = &data_encoding::BASE64_NOPAD; test(&b, b"", b""); test(&b, b"f", b"Zg"); test(&b, b"fo", b"Zm8"); @@ -206,7 +172,7 @@ test! { #[test] fn base32_error() { - let b = &constants::BASE32; + let b = &data_encoding::BASE32; assert_eq!(b.decode(b"ABC").err().unwrap(), DecodeError { position: 0, kind: Length }); assert_eq!(b.decode(b"========").err().unwrap(), DecodeError { position: 0, kind: Padding }); assert_eq!(b.decode(b"MB======").err().unwrap(), DecodeError { position: 1, kind: Trailing }); @@ -217,7 +183,7 @@ fn base32_error() { #[test] fn base64_error() { - let b = &constants::BASE64; + let b = &data_encoding::BASE64; assert_eq!(b.decode(b"====").err().unwrap(), DecodeError { position: 0, kind: Padding }); assert_eq!(b.decode(b"====").err().unwrap(), DecodeError { position: 0, kind: Padding }); assert_eq!( @@ -250,7 +216,7 @@ fn base64_error() { #[test] fn base64_nopad_error() { - let b = &constants::BASE64_NOPAD; + let b = &data_encoding::BASE64_NOPAD; assert_eq!(b.decode(b"Z").err().unwrap(), DecodeError { position: 0, kind: Length }); assert_eq!(b.decode(b"Zh").err().unwrap(), DecodeError { position: 1, kind: Trailing }); assert_eq!(b.decode(b"Zg==").err().unwrap(), DecodeError { position: 2, kind: Symbol }); @@ -267,10 +233,6 @@ fn bit_order() { let msb = spec.encoding().unwrap(); spec.bit_order = data_encoding::BitOrder::LeastSignificantFirst; let lsb = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let msb = Encoding::::try_from(msb).unwrap(); - #[cfg(feature = "v3-preview")] - let lsb = Encoding::::try_from(lsb).unwrap(); assert_eq!(msb.encode(b"ABC"), "414243"); assert_eq!(lsb.encode(b"ABC"), "142434"); } @@ -282,10 +244,6 @@ fn trailing_bits() { let strict = spec.encoding().unwrap(); spec.check_trailing_bits = false; let permissive = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let strict = Encoding::::try_from(strict).unwrap(); - #[cfg(feature = "v3-preview")] - let permissive = Encoding::::try_from(permissive).unwrap(); assert!(strict.decode(b"001").is_err()); assert!(permissive.decode(b"001").is_ok()); } @@ -304,17 +262,13 @@ fn ignore() { } j } - split_v3! { - fn check[Pad: Bool]( - base: &Encoding[Bit3, True, Pad, False, True], buf: &[u8], cmp: &[u8], shift: &[usize] - ) { - let res = base.decode(buf); - match base.decode(cmp) { - Ok(x) => assert_eq!(Ok(x), res), - Err(mut x) => { - x.position = shift[x.position]; - assert_eq!(Err(x), res); - } + fn check(base: &Encoding, buf: &[u8], cmp: &[u8], shift: &[usize]) { + let res = base.decode(buf); + match base.decode(cmp) { + Ok(x) => assert_eq!(Ok(x), res), + Err(mut x) => { + x.position = shift[x.position]; + assert_eq!(Err(x), res); } } } @@ -331,21 +285,17 @@ fn ignore() { } false } - split_v3! { - fn forall[Pad: Bool]( - base: &Encoding[Bit3, True, Pad, False, True], chars: &[u8], max: usize - ) { - let mut idx = vec![0; max]; - let mut buf = vec![0; max]; - let mut cmp = vec![0; max]; - let mut shift = vec![0; max]; - for size in 0 .. (max + 1) { - loop { - let len = skip(&buf[.. size], &mut cmp, &mut shift); - check(base, &buf[.. size], &cmp[.. len], &shift[.. len]); - if !incr(chars, &mut idx[.. size], &mut buf[.. size]) { - break; - } + fn forall(base: &Encoding, chars: &[u8], max: usize) { + let mut idx = vec![0; max]; + let mut buf = vec![0; max]; + let mut cmp = vec![0; max]; + let mut shift = vec![0; max]; + for size in 0 .. (max + 1) { + loop { + let len = skip(&buf[.. size], &mut cmp, &mut shift); + check(base, &buf[.. size], &cmp[.. len], &shift[.. len]); + if !incr(chars, &mut idx[.. size], &mut buf[.. size]) { + break; } } } @@ -356,10 +306,6 @@ fn ignore() { let no_pad = spec.encoding().unwrap(); spec.padding = Some('='); let padded = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let no_pad = Encoding::::try_from(no_pad).unwrap(); - #[cfg(feature = "v3-preview")] - let padded = Encoding::::try_from(padded).unwrap(); #[cfg(miri)] const MAX: [usize; 4] = [4, 3, 3, 2]; #[cfg(all(not(miri), debug_assertions))] @@ -388,8 +334,6 @@ fn translate() { spec.translate.from.push_str("-_O"); spec.translate.to.push_str("=.0"); let base = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let base = Encoding::::try_from(base).unwrap(); assert_eq!(base.decode(b" O OO= = = == ").unwrap(), [0]); assert_eq!(base.decode(b"O__OO__--_--.-").unwrap(), [0]); assert_eq!(base.decode(b"_____. . . ... ..").unwrap(), []); @@ -446,7 +390,6 @@ fn specification() { assert_eq!(errmsg(spec.encoding()), "invalid wrap width or separator length"); } -#[cfg(not(feature = "v3-preview"))] #[test] fn round_trip() { let test = |e: Encoding| { @@ -496,7 +439,7 @@ fn is_canonical() { #[test] fn decode_error() { - let b = &constants::BASE64; + let b = &data_encoding::BASE64; assert_eq!(errmsg(b.decode(b"A")), "invalid length at 0"); assert_eq!(errmsg(b.decode(b"A.AA")), "invalid symbol at 1"); assert_eq!(errmsg(b.decode(b"AAB=")), "non-zero trailing bits at 2"); @@ -505,7 +448,7 @@ fn decode_error() { #[test] fn encode_base() { - let b = &constants::BASE64_NOPAD; + let b = &data_encoding::BASE64_NOPAD; assert_eq!(b.encode(b""), ""); assert_eq!(b.encode(b"h"), "aA"); assert_eq!(b.encode(b"he"), "aGU"); @@ -516,7 +459,7 @@ fn encode_base() { #[test] fn decode_base() { - let b = &constants::BASE64_NOPAD; + let b = &data_encoding::BASE64_NOPAD; let err_length = |pos| Err(DecodeError { position: pos, kind: Length }); let err_symbol = |pos| Err(DecodeError { position: pos, kind: Symbol }); let err_trailing = |pos| Err(DecodeError { position: pos, kind: Trailing }); @@ -544,7 +487,7 @@ fn decode_base() { #[test] fn encode_pad() { - let b = &constants::BASE64; + let b = &data_encoding::BASE64; assert_eq!(b.encode(b""), ""); assert_eq!(b.encode(b"h"), "aA=="); assert_eq!(b.encode(b"he"), "aGU="); @@ -555,7 +498,7 @@ fn encode_pad() { #[test] fn decode_pad() { - let b = &constants::BASE64; + let b = &data_encoding::BASE64; let err_length = |pos| Err(DecodeError { position: pos, kind: Length }); let err_symbol = |pos| Err(DecodeError { position: pos, kind: Symbol }); let err_trailing = |pos| Err(DecodeError { position: pos, kind: Trailing }); @@ -605,8 +548,6 @@ fn encode_wrap() { spec.wrap.width = 4; spec.wrap.separator.push_str(":"); let b = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); assert_eq!(b.encode(b""), ""); assert_eq!(b.encode(b"h"), "aA:"); assert_eq!(b.encode(b"he"), "aGU:"); @@ -620,8 +561,6 @@ fn decode_wrap() { let mut spec = data_encoding::BASE64_NOPAD.specification(); spec.ignore.push_str(":"); let b = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); let err_length = |pos| Err(DecodeError { position: pos, kind: Length }); let err_symbol = |pos| Err(DecodeError { position: pos, kind: Symbol }); let err_trailing = |pos| Err(DecodeError { position: pos, kind: Trailing }); @@ -653,8 +592,6 @@ fn encode_pad_wrap() { spec.wrap.width = 4; spec.wrap.separator.push_str(":"); let b = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); assert_eq!(b.encode(b""), ""); assert_eq!(b.encode(b"h"), "aA==:"); assert_eq!(b.encode(b"he"), "aGU=:"); @@ -668,8 +605,6 @@ fn decode_pad_wrap() { let mut spec = data_encoding::BASE64.specification(); spec.ignore.push_str(":"); let b = spec.encoding().unwrap(); - #[cfg(feature = "v3-preview")] - let b = Encoding::::try_from(b).unwrap(); let err_length = |pos| Err(DecodeError { position: pos, kind: Length }); let err_symbol = |pos| Err(DecodeError { position: pos, kind: Symbol }); let err_trailing = |pos| Err(DecodeError { position: pos, kind: Trailing }); @@ -717,7 +652,7 @@ fn decode_pad_wrap() { fn encode_append() { fn test(input: &[u8], output: &str, expected: &str) { let mut output = output.to_string(); - constants::BASE64.encode_append(input, &mut output); + data_encoding::BASE64.encode_append(input, &mut output); assert_eq!(output, expected); } test(b"", "", ""); @@ -731,7 +666,7 @@ fn encode_append() { fn encode_write() { fn test(input: &[u8], output: &str, expected: &str) { let mut output = output.to_string(); - constants::BASE64.encode_write(input, &mut output).unwrap(); + data_encoding::BASE64.encode_write(input, &mut output).unwrap(); assert_eq!(output, expected); } test(b"", "", ""); @@ -746,9 +681,6 @@ fn encoder() { #[track_caller] fn test(inputs: &[&[u8]], expected: &str) { let mut output = String::new(); - #[cfg(feature = "v3-preview")] - use constants::BASE64; - #[cfg(not(feature = "v3-preview"))] static BASE64: Encoding = data_encoding::BASE64; let mut encoder = BASE64.new_encoder(&mut output); for input in inputs { diff --git a/xtask/src/main.rs b/xtask/src/main.rs index ceaf53d..81a231e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -139,12 +139,6 @@ impl Action { &[&["--no-default-features", "--features=alloc"], &["--no-default-features"]]; } } - if self.dir == Dir::Lib - && matches!(self.task, Task::Build | Task::Test | Task::Miri | Task::Bench) - && !matches!(self.toolchain, Toolchain::Msrv) - { - instructions *= &[&["--features=v3-preview"]]; - } if self.dir == Dir::Nostd && self.task == Task::Test { instructions = Instructions::default(); instructions += Instruction { @@ -412,14 +406,16 @@ impl Flags { } job.steps.push(WorkflowStep { run: Some(run), ..Default::default() }); } - if actions.iter().find(|x| matches!(x.task, Task::SemverChecks)).is_some() { - job.steps.push(WorkflowStep { - run: Some(format!( - "cargo +{} install cargo-semver-checks", - actions[0].toolchain - )), - ..Default::default() - }); + for task in [Task::Audit, Task::SemverChecks] { + if actions.iter().any(|x| x.task == task) { + job.steps.push(WorkflowStep { + run: Some(format!( + "cargo +{} install cargo-{task} --locked", + actions[0].toolchain + )), + ..Default::default() + }); + } } for action in actions { for instruction in action.interpret().0 {