Skip to content

Commit

Permalink
capacity calc w padding, and capacity calc on alphabets
Browse files Browse the repository at this point in the history
  • Loading branch information
rogusdev committed Dec 27, 2023
1 parent b802fb5 commit d73d8d8
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 16 deletions.
53 changes: 47 additions & 6 deletions src/base32/alphabet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use uuid::Uuid;

use crate::DecodeError;

use super::decode_bytes::{decode, decode_into};
use super::decode_bytes::{capacity_decode, decode, decode_into};
use super::decode_u128::decode_u128;
use super::decode_u64::decode_u64;
use super::encode_bytes::{encode, encode_into};
use super::encode_u128::{encode_u128, encode_u128_into};
use super::encode_u64::{encode_u64, encode_u64_into};
use super::encode_bytes::{capacity_encode, encode, encode_into};
use super::encode_u128::{capacity_encode_u128, encode_u128, encode_u128_into};
use super::encode_u64::{capacity_encode_u64, encode_u64, encode_u64_into};

#[cfg(feature = "uuid")]
use super::uuid::{decode_uuid, encode_uuid, encode_uuid_into};
Expand Down Expand Up @@ -101,6 +101,12 @@ pub const WIDTH_23: usize = 115;
pub const WIDTH_24: usize = 120;
pub const WIDTH_25: usize = 125;

#[inline]
const fn pad_len(len: usize) -> usize {
// 0 len needs to go to 0 padding, not WIDTH_ENC
(WIDTH_ENC - (len % WIDTH_ENC)) % WIDTH_ENC
}

unsafe fn add_pad(b: &mut Vec<u8>, pad: char) {
let len = b.len();
match len % WIDTH_ENC {
Expand Down Expand Up @@ -191,14 +197,25 @@ impl Alphabet32Padded {
Self { enc, dec, pad }
}

/// Capacity needed in dest `Vec<u8>` to encode this byte array -- with padding!
#[inline]
pub const fn capacity_encode(&self, a: &[u8]) -> usize {
let len = capacity_encode(a);
len + pad_len(len)
}

/// Capacity needed in dest `Vec<u8>` to decode this byte array -- with padding!
pub fn capacity_decode(&self, a: &[u8]) -> usize {
capacity_decode(rem_pad(a, self.pad))
}

/// Pass encoder array to [`encode`](super::encode()), and add padding as needed
#[inline]
pub fn encode(&self, a: &[u8]) -> String {
let mut s = encode(self.enc, a);
unsafe {
let b = s.as_mut_vec();
// make space for max possible padding
b.reserve(6);
b.reserve(pad_len(b.len()));
add_pad(b, self.pad);
}
s
Expand Down Expand Up @@ -249,6 +266,30 @@ impl Alphabet32Nopad {
Self { enc, dec }
}

/// Pass input bytes to [`capacity_encode`](super::capacity_encode())
#[inline]
pub const fn capacity_encode(&self, a: &[u8]) -> usize {
capacity_encode(a)
}

/// Pass input u64 to [`capacity_encode_u64`](super::capacity_encode_u64())
#[inline]
pub const fn capacity_encode_u64(&self, n: u64) -> usize {
capacity_encode_u64(n)
}

/// Pass input u128 to [`capacity_encode_u128`](super::capacity_encode_u128())
#[inline]
pub const fn capacity_encode_u128(&self, n: u128) -> usize {
capacity_encode_u128(n)
}

/// Pass input bytes to [`capacity_decode`](super::capacity_decode())
#[inline]
pub const fn capacity_decode(&self, a: &[u8]) -> usize {
capacity_decode(a)
}

/// Pass encoder array to [`encode_u64`](super::encode_u64())
#[inline]
pub fn encode_u64(&self, n: u64) -> String {
Expand Down
2 changes: 1 addition & 1 deletion src/base32/decode_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::shared::{bits_or_err_u8, DecodeError};

use super::alphabet::{WIDTH_DEC, WIDTH_ENC};

/// Capacity needed in dest `Vec<u8>` to decode this byte array
/// Capacity needed in dest `Vec<u8>` to decode this byte array -- without padding!
#[inline]
pub const fn capacity_decode(a: &[u8]) -> usize {
a.len() * WIDTH_DEC / WIDTH_ENC
Expand Down
2 changes: 1 addition & 1 deletion src/base32/encode_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::alphabet::{BITS, WIDTH_DEC, WIDTH_ENC};
const U8_MASK_MID_2: u8 = 0b01111100;
const U8_MASK_MID_1: u8 = 0b00111110;

/// Capacity needed in dest `Vec<u8>` to encode this byte array
/// Capacity needed in dest `Vec<u8>` to encode this byte array -- without padding!
#[inline]
pub const fn capacity_encode(a: &[u8]) -> usize {
// https://stackoverflow.com/questions/23636240/how-do-i-predict-the-required-size-of-a-base32-decode-output
Expand Down
53 changes: 47 additions & 6 deletions src/base64/alphabet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use uuid::Uuid;

use crate::DecodeError;

use super::decode_bytes::{decode, decode_into};
use super::decode_bytes::{capacity_decode, decode, decode_into};
use super::decode_u128::decode_u128;
use super::decode_u64::decode_u64;
use super::encode_bytes::{encode, encode_into};
use super::encode_u128::{encode_u128, encode_u128_into};
use super::encode_u64::{encode_u64, encode_u64_into};
use super::encode_bytes::{capacity_encode, encode, encode_into};
use super::encode_u128::{capacity_encode_u128, encode_u128, encode_u128_into};
use super::encode_u64::{capacity_encode_u64, encode_u64, encode_u64_into};

#[cfg(feature = "uuid")]
use super::uuid::{decode_uuid, encode_uuid, encode_uuid_into};
Expand Down Expand Up @@ -81,6 +81,12 @@ pub const WIDTH_19: usize = 114;
pub const WIDTH_20: usize = 120;
pub const WIDTH_21: usize = 126;

#[inline]
const fn pad_len(len: usize) -> usize {
// 0 len needs to go to 0 padding, not WIDTH_ENC
(WIDTH_ENC - (len % WIDTH_ENC)) % WIDTH_ENC
}

unsafe fn add_pad(b: &mut Vec<u8>, pad: char) {
let len = b.len();
match len % WIDTH_ENC {
Expand Down Expand Up @@ -142,14 +148,25 @@ impl Alphabet64Padded {
Self { enc, dec, pad }
}

/// Capacity needed in dest `Vec<u8>` to encode this byte array -- with padding!
#[inline]
pub const fn capacity_encode(&self, a: &[u8]) -> usize {
let len = capacity_encode(a);
len + pad_len(len)
}

/// Capacity needed in dest `Vec<u8>` to decode this byte array -- with padding!
pub fn capacity_decode(&self, a: &[u8]) -> usize {
capacity_decode(rem_pad(a, self.pad))
}

/// Pass encoder array to [`encode`](super::encode()), and add padding as needed
#[inline]
pub fn encode(&self, a: &[u8]) -> String {
let mut s = encode(self.enc, a);
unsafe {
let b = s.as_mut_vec();
// make space for max possible padding
b.reserve(2);
b.reserve(pad_len(b.len()));
add_pad(b, self.pad);
}
s
Expand Down Expand Up @@ -200,6 +217,30 @@ impl Alphabet64Nopad {
Self { enc, dec }
}

/// Pass input bytes to [`capacity_encode`](super::capacity_encode())
#[inline]
pub const fn capacity_encode(&self, a: &[u8]) -> usize {
capacity_encode(a)
}

/// Pass input u64 to [`capacity_encode_u64`](super::capacity_encode_u64())
#[inline]
pub const fn capacity_encode_u64(&self, n: u64) -> usize {
capacity_encode_u64(n)
}

/// Pass input u128 to [`capacity_encode_u128`](super::capacity_encode_u128())
#[inline]
pub const fn capacity_encode_u128(&self, n: u128) -> usize {
capacity_encode_u128(n)
}

/// Pass input bytes to [`capacity_decode`](super::capacity_decode())
#[inline]
pub const fn capacity_decode(&self, a: &[u8]) -> usize {
capacity_decode(a)
}

/// Pass encoder array to [`encode_u64`](super::encode_u64())
#[inline]
pub fn encode_u64(&self, n: u64) -> String {
Expand Down
2 changes: 1 addition & 1 deletion src/base64/decode_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::shared::{bits_or_err_u8, DecodeError};

use super::alphabet::{WIDTH_DEC, WIDTH_ENC};

/// Capacity needed in dest `Vec<u8>` to decode this byte array
/// Capacity needed in dest `Vec<u8>` to decode this byte array -- without padding!
#[inline]
pub const fn capacity_decode(a: &[u8]) -> usize {
a.len() * WIDTH_DEC / WIDTH_ENC
Expand Down
2 changes: 1 addition & 1 deletion src/base64/encode_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::shared::*;

use super::alphabet::{BITS, WIDTH_DEC, WIDTH_ENC};

/// Capacity needed in dest `Vec<u8>` to encode this byte array
/// Capacity needed in dest `Vec<u8>` to encode this byte array -- without padding!
#[inline]
pub const fn capacity_encode(a: &[u8]) -> usize {
// https://stackoverflow.com/questions/23636240/how-do-i-predict-the-required-size-of-a-base32-decode-output
Expand Down
23 changes: 23 additions & 0 deletions tests/base32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,29 @@ fn both_bytes_into() {
assert_eq!(&b[1..17], n);
}

#[test]
fn check_capacity() {
let n = b"AAJA====";
assert_eq!(RFC4648.capacity_decode(n), 2);

let n = b"AAJA";
assert_eq!(CROCKFORD.capacity_decode(n), 2);

let n = &[0x00, 0x12];
assert_eq!(RFC4648.capacity_encode(n), 8);
assert_eq!(CROCKFORD.capacity_encode(n), 4);

let n = &[];
assert_eq!(RFC4648.capacity_encode(n), 0);
assert_eq!(CROCKFORD.capacity_encode(n), 0);

let n = 111;
assert_eq!(CROCKFORD.capacity_encode_u64(n), 2);

let n = 111;
assert_eq!(CROCKFORD.capacity_encode_u128(n), 2);
}

#[test]
#[should_panic(expected = "Missing capacity for encoding")]
fn panic_bytes_into() {
Expand Down
23 changes: 23 additions & 0 deletions tests/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,29 @@ fn both_bytes_into() {
assert_eq!(&b[1..17], n);
}

#[test]
fn check_capacity() {
let n = b"ABI=";
assert_eq!(RFC4648.capacity_decode(n), 2);

let n = b"ABI";
assert_eq!(RFC4648_NOPAD.capacity_decode(n), 2);

let n = &[0x00, 0x12];
assert_eq!(RFC4648.capacity_encode(n), 4);
assert_eq!(RFC4648_NOPAD.capacity_encode(n), 3);

let n = &[];
assert_eq!(RFC4648.capacity_encode(n), 0);
assert_eq!(RFC4648_NOPAD.capacity_encode(n), 0);

let n = 111;
assert_eq!(RFC4648_NOPAD.capacity_encode_u64(n), 2);

let n = 111;
assert_eq!(RFC4648_NOPAD.capacity_encode_u128(n), 2);
}

#[test]
#[should_panic(expected = "Missing capacity for encoding")]
fn panic_bytes_into() {
Expand Down

0 comments on commit d73d8d8

Please sign in to comment.