Skip to content

Commit

Permalink
Merge efc2f74 into fa73403
Browse files Browse the repository at this point in the history
  • Loading branch information
uhmarcel committed Nov 15, 2022
2 parents fa73403 + efc2f74 commit 50128d0
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 76 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
on:
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
push:
paths:
- '**/Cargo.toml'
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rbase64"
version = "1.2.0"
version = "1.2.1"
edition = "2021"
description = "A simple base64 encoder / decoder CLI tool made in Rust"
authors = ["Marcel Riera <marcel.riera@outlook.com>"]
Expand Down
64 changes: 32 additions & 32 deletions benches/baseline.txt
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
encode/3 time: [33.109 ns 33.342 ns 33.580 ns]
thrpt: [85.199 MiB/s 85.809 MiB/s 86.413 MiB/s]
encode/50 time: [190.49 ns 192.28 ns 194.19 ns]
thrpt: [245.55 MiB/s 247.99 MiB/s 250.32 MiB/s]
encode/100 time: [343.82 ns 345.70 ns 347.64 ns]
thrpt: [274.33 MiB/s 275.87 MiB/s 277.38 MiB/s]
encode/500 time: [1.4328 µs 1.4373 µs 1.4417 µs]
thrpt: [330.74 MiB/s 331.77 MiB/s 332.80 MiB/s]
encode/3072 time: [8.6495 µs 8.8042 µs 8.9640 µs]
thrpt: [326.83 MiB/s 332.76 MiB/s 338.71 MiB/s]
encode/1048576 time: [7.9042 ms 7.9168 ms 7.9307 ms]
thrpt: [126.09 MiB/s 126.31 MiB/s 126.52 MiB/s
encode/2097152 time: [15.845 ms 15.885 ms 15.924 ms]
thrpt: [125.59 MiB/s 125.91 MiB/s 126.22 MiB/s]
encode/10485760 time: [78.152 ms 78.241 ms 78.335 ms]
thrpt: [127.66 MiB/s 127.81 MiB/s 127.96 MiB/s]
decode/3 time: [29.147 ns 29.206 ns 29.267 ns]
thrpt: [97.754 MiB/s 97.961 MiB/s 98.158 MiB/s]
decode/50 time: [108.45 ns 109.36 ns 110.35 ns]
thrpt: [432.12 MiB/s 436.02 MiB/s 439.70 MiB/s]
decode/100 time: [194.52 ns 196.01 ns 197.53 ns]
thrpt: [482.81 MiB/s 486.55 MiB/s 490.27 MiB/s]
decode/500 time: [916.66 ns 921.43 ns 926.93 ns]
thrpt: [514.43 MiB/s 517.50 MiB/s 520.19 MiB/s]
decode/3072 time: [5.8147 µs 5.9745 µs 6.1469 µs]
thrpt: [476.61 MiB/s 490.36 MiB/s 503.84 MiB/s]
decode/1048576 time: [5.6218 ms 5.6280 ms 5.6343 ms]
thrpt: [177.49 MiB/s 177.68 MiB/s 177.88 MiB/s]
decode/2097152 time: [11.238 ms 11.252 ms 11.268 ms]
thrpt: [177.50 MiB/s 177.74 MiB/s 177.96 MiB/s]
decode/10485760 time: [56.401 ms 56.472 ms 56.544 ms]
thrpt: [176.85 MiB/s 177.08 MiB/s 177.30 MiB/s]
encode/3 time: [30.485 ns 30.506 ns 30.527 ns]
thrpt: [93.722 MiB/s 93.785 MiB/s 93.851 MiB/s]
encode/50 time: [107.04 ns 107.23 ns 107.42 ns]
thrpt: [443.91 MiB/s 444.68 MiB/s 445.46 MiB/s]
encode/100 time: [184.46 ns 184.73 ns 185.03 ns]
thrpt: [515.40 MiB/s 516.27 MiB/s 517.02 MiB/s]
encode/500 time: [858.73 ns 936.36 ns 1.0542 µs]
thrpt: [452.31 MiB/s 509.24 MiB/s 555.28 MiB/s]
encode/3072 time: [4.6974 µs 4.7034 µs 4.7098 µs]
thrpt: [622.05 MiB/s 622.89 MiB/s 623.68 MiB/s]
encode/1048576 time: [1.5902 ms 1.5917 ms 1.5933 ms]
thrpt: [627.62 MiB/s 628.27 MiB/s 628.87 MiB/s]
encode/2097152 time: [3.3397 ms 3.3656 ms 3.3957 ms]
thrpt: [588.99 MiB/s 594.24 MiB/s 598.85 MiB/s]
encode/10485760 time: [16.818 ms 16.878 ms 16.962 ms]
thrpt: [589.54 MiB/s 592.48 MiB/s 594.62 MiB/s]
decode/3 time: [28.726 ns 28.797 ns 28.867 ns]
thrpt: [99.111 MiB/s 99.353 MiB/s 99.597 MiB/s]
decode/50 time: [84.385 ns 84.588 ns 84.795 ns]
thrpt: [562.34 MiB/s 563.72 MiB/s 565.08 MiB/s]
decode/100 time: [137.05 ns 137.27 ns 137.46 ns]
thrpt: [693.80 MiB/s 694.75 MiB/s 695.86 MiB/s]
decode/500 time: [583.58 ns 584.72 ns 586.16 ns]
thrpt: [813.49 MiB/s 815.50 MiB/s 817.09 MiB/s]
decode/3072 time: [3.3073 µs 3.3134 µs 3.3195 µs]
thrpt: [882.57 MiB/s 884.21 MiB/s 885.84 MiB/s]
decode/1048576 time: [1.1804 ms 1.1826 ms 1.1848 ms]
thrpt: [844.01 MiB/s 845.57 MiB/s 847.20 MiB/s]
decode/2097152 time: [2.3595 ms 2.3639 ms 2.3682 ms]
thrpt: [844.51 MiB/s 846.07 MiB/s 847.64 MiB/s]
decode/10485760 time: [12.206 ms 12.238 ms 12.277 ms]
thrpt: [814.50 MiB/s 817.11 MiB/s 819.25 MiB/s]
91 changes: 56 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
const ENCODE_MAP: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const DECODE_MAP: &[u8; 256] = &construct_decode_map();

const INVALID_BYTE: u8 = 0x40;

pub fn encode(value: &[u8]) -> String {
let mut encoded = String::with_capacity(value.len() * 4 / 3);
let mut encoded = String::with_capacity((value.len() * 4 / 3) + 8);
let mut bytes = 0u32;
let mut size = 0u8;

Expand All @@ -12,7 +17,7 @@ pub fn encode(value: &[u8]) -> String {

let mask = 0x3f << size;
encoded.push(to_base64_char(((bytes & mask) >> size) as u8));
bytes = bytes & !mask;
bytes &= !mask;
}
}

Expand All @@ -36,58 +41,51 @@ pub fn decode(encoded: &str) -> Vec<u8> {
if char == &b'=' {
break;
}
bytes = (bytes << 6) + to_byte(char) as u32;
bytes = (bytes << 6) + to_byte(*char) as u32;
size += 6;

while size >= 8 {
size -= 8;

let mask = 0xff << size;
decoded.push(((bytes & mask) >> size) as u8);
bytes = bytes & !mask;
bytes &= !mask;
}
}
decoded
}

fn to_base64_char(value: u8) -> char {
if value < 26 {
char::from(b'A' + value)
} else if value < 52 {
char::from(b'a' + (value - 26))
} else if value < 62 {
char::from(b'0' + (value - 52))
} else if value < 63 {
'+'
} else if value < 64 {
'/'
} else {
panic!("Input byte is not in base 64 ({})", value)
}
ENCODE_MAP[value as usize] as char
}

fn to_byte(base64: &u8) -> u8 {
if (b'A'..=b'Z').contains(&base64) {
base64 - b'A'
} else if (b'a'..=b'z').contains(&base64) {
base64 - b'a' + 26
} else if (b'0'..=b'9').contains(&base64) {
base64 - b'0' + 52
} else if base64 == &b'+' {
62
} else if base64 == &b'/' {
63
} else {
fn to_byte(encoded_byte: u8) -> u8 {
let decoded = DECODE_MAP[encoded_byte as usize];

if decoded == INVALID_BYTE {
panic!(
"Character '{}' is not part of the base64 spec ([a-z][A-Z][0-9]+/=)",
*base64 as char
"Unable to decode non-base64 character '{}'",
encoded_byte as char
)
}
decoded
}

const fn construct_decode_map() -> [u8; 256] {
let mut map = [INVALID_BYTE; 256];
let mut index = 0;

while index < 64 {
map[ENCODE_MAP[index] as usize] = index as u8;
index += 1;
}
map
}

#[cfg(test)]
mod tests {
use super::*;
use rand::{Rng, SeedableRng};

#[test]
fn should_encode_following_base64_spec() {
Expand Down Expand Up @@ -116,9 +114,32 @@ mod tests {
}

#[test]
fn should_preserve_original_value() {
assert_eq!(decode(&encode(b"Hello!")), b"Hello!");
assert_eq!(decode(&encode(b"Large msg...")), b"Large msg...");
assert_eq!(decode(&encode(b"!@#$%^&*()_+")), b"!@#$%^&*()_+")
#[should_panic(expected = "Unable to decode non-base64 character '^'")]
fn should_panic_when_decode_non_base64_input() {
decode("AAA^AAA==");
}

#[test]
fn should_preserve_original_input() {
for size in 0..512 {
let bytes = random_bytes(size);
assert_eq!(decode(&encode(&bytes)), bytes);
}
}

#[test]
fn should_construct_matching_encode_decode_tables() {
for byte in 0..64 {
assert_eq!(construct_decode_map()[ENCODE_MAP[byte] as usize], byte as u8);
}
}

fn random_bytes(size: usize) -> Vec<u8> {
let mut bytes = Vec::with_capacity(size);
let mut r = rand::rngs::SmallRng::from_entropy();
while bytes.len() < size {
bytes.push(r.gen::<u8>());
}
bytes
}
}
2 changes: 0 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use std::fs;
use std::io;
use std::io::Read;

use rbase64;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
Expand Down
2 changes: 1 addition & 1 deletion tests/cli-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn given_invalid_stdin_and_decode_arg_expect_error() {
.assert()
.failure()
.stderr(predicate::str::contains(
"Character '!' is not part of the base64 spec",
"Unable to decode non-base64 character '!'",
));
}

Expand Down

0 comments on commit 50128d0

Please sign in to comment.