Skip to content

Commit

Permalink
Make encoded_len const
Browse files Browse the repository at this point in the history
Addresses #251
  • Loading branch information
marshallpierce committed Sep 10, 2023
1 parent 6f9f734 commit 59048ff
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 9 deletions.
10 changes: 8 additions & 2 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.21.4

- Make `encoded_len` `const`, allowing the creation of arrays sized to encode compile-time-known data lengths

# 0.21.3

- Implement `source` instead of `cause` on Error types
Expand All @@ -12,7 +16,8 @@
# 0.21.1

- Remove the possibility of panicking during decoded length calculations
- `DecoderReader` no longer sometimes erroneously ignores padding [#226](https://github.com/marshallpierce/rust-base64/issues/226)
- `DecoderReader` no longer sometimes erroneously ignores
padding [#226](https://github.com/marshallpierce/rust-base64/issues/226)

## Breaking changes

Expand Down Expand Up @@ -64,7 +69,8 @@ precisely, see the following table.

## Breaking changes

- Re-exports of preconfigured engines in `engine` are removed in favor of `base64::prelude::...` that are better suited to those who wish to `use` the entire path to a name.
- Re-exports of preconfigured engines in `engine` are removed in favor of `base64::prelude::...` that are better suited
to those who wish to `use` the entire path to a name.

# 0.21.0-beta.1

Expand Down
21 changes: 14 additions & 7 deletions src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,25 +94,32 @@ pub(crate) fn encode_with_padding<E: Engine + ?Sized>(
///
/// Returns `None` if the encoded length can't be represented in `usize`. This will happen for
/// input lengths in approximately the top quarter of the range of `usize`.
pub fn encoded_len(bytes_len: usize, padding: bool) -> Option<usize> {
pub const fn encoded_len(bytes_len: usize, padding: bool) -> Option<usize> {
let rem = bytes_len % 3;

let complete_input_chunks = bytes_len / 3;
let complete_chunk_output = complete_input_chunks.checked_mul(4);
// `let Some(_) = _ else` requires 1.65.0, whereas this messier one works on 1.48
let complete_chunk_output =
if let Some(complete_chunk_output) = complete_input_chunks.checked_mul(4) {
complete_chunk_output
} else {
return None;
};

if rem > 0 {
if padding {
complete_chunk_output.and_then(|c| c.checked_add(4))
complete_chunk_output.checked_add(4)
} else {
let encoded_rem = match rem {
1 => 2,
2 => 3,
_ => unreachable!("Impossible remainder"),
// only other possible remainder is 2
// can't use a separate _ => unreachable!() in const fns in ancient rust versions
_ => 3,
};
complete_chunk_output.and_then(|c| c.checked_add(encoded_rem))
complete_chunk_output.checked_add(encoded_rem)
}
} else {
complete_chunk_output
Some(complete_chunk_output)
}
}

Expand Down
31 changes: 31 additions & 0 deletions tests/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,34 @@ fn encode_all_bytes_url() {
&engine::GeneralPurpose::new(&URL_SAFE, PAD).encode(bytes)
);
}

#[test]
fn encoded_len_unpadded() {
assert_eq!(0, encoded_len(0, false).unwrap());
assert_eq!(2, encoded_len(1, false).unwrap());
assert_eq!(3, encoded_len(2, false).unwrap());
assert_eq!(4, encoded_len(3, false).unwrap());
assert_eq!(6, encoded_len(4, false).unwrap());
assert_eq!(7, encoded_len(5, false).unwrap());
assert_eq!(8, encoded_len(6, false).unwrap());
assert_eq!(10, encoded_len(7, false).unwrap());
}

#[test]
fn encoded_len_padded() {
assert_eq!(0, encoded_len(0, true).unwrap());
assert_eq!(4, encoded_len(1, true).unwrap());
assert_eq!(4, encoded_len(2, true).unwrap());
assert_eq!(4, encoded_len(3, true).unwrap());
assert_eq!(8, encoded_len(4, true).unwrap());
assert_eq!(8, encoded_len(5, true).unwrap());
assert_eq!(8, encoded_len(6, true).unwrap());
assert_eq!(12, encoded_len(7, true).unwrap());
}
#[test]
fn encoded_len_overflow() {
let max_size = usize::MAX / 4 * 3 + 2;
assert_eq!(2, max_size % 3);
assert_eq!(Some(usize::MAX), encoded_len(max_size, false));
assert_eq!(None, encoded_len(max_size + 1, false));
}

0 comments on commit 59048ff

Please sign in to comment.