1[base64](https://crates.io/crates/base64) 2=== 3 4[![](https://img.shields.io/crates/v/base64.svg)](https://crates.io/crates/base64) [![Docs](https://docs.rs/base64/badge.svg)](https://docs.rs/base64) [![Build](https://travis-ci.org/marshallpierce/rust-base64.svg?branch=master)](https://travis-ci.org/marshallpierce/rust-base64) [![codecov](https://codecov.io/gh/marshallpierce/rust-base64/branch/master/graph/badge.svg)](https://codecov.io/gh/marshallpierce/rust-base64) [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) 5 6<a href="https://www.jetbrains.com/?from=rust-base64"><img src="/icon_CLion.svg" height="40px"/></a> 7 8Made with CLion. Thanks to JetBrains for supporting open source! 9 10It's base64. What more could anyone want? 11 12This library's goals are to be *correct* and *fast*. It's thoroughly tested and widely used. It exposes functionality at multiple levels of abstraction so you can choose the level of convenience vs performance that you want, e.g. `decode_config_slice` decodes into an existing `&mut [u8]` and is pretty fast (2.6GiB/s for a 3 KiB input), whereas `decode_config` allocates a new `Vec<u8>` and returns it, which might be more convenient in some cases, but is slower (although still fast enough for almost any purpose) at 2.1 GiB/s. 13 14Example 15--- 16 17```rust 18extern crate base64; 19 20use base64::{encode, decode}; 21 22fn main() { 23 let a = b"hello world"; 24 let b = "aGVsbG8gd29ybGQ="; 25 26 assert_eq!(encode(a), b); 27 assert_eq!(a, &decode(b).unwrap()[..]); 28} 29``` 30 31See the [docs](https://docs.rs/base64) for all the details. 32 33Rust version compatibility 34--- 35 36The minimum required Rust version is 1.34.0. 37 38Developing 39--- 40 41Benchmarks are in `benches/`. Running them requires nightly rust, but `rustup` makes it easy: 42 43```bash 44rustup run nightly cargo bench 45``` 46 47Decoding is aided by some pre-calculated tables, which are generated by: 48 49```bash 50cargo run --example make_tables > src/tables.rs.tmp && mv src/tables.rs.tmp src/tables.rs 51``` 52 53no_std 54--- 55 56This crate supports no_std. By default the crate targets std via the `std` feature. You can deactivate the `default-features` to target core instead. In that case you lose out on all the functionality revolving around `std::io`, `std::error::Error` and heap allocations. There is an additional `alloc` feature that you can activate to bring back the support for heap allocations. 57 58Profiling 59--- 60 61On Linux, you can use [perf](https://perf.wiki.kernel.org/index.php/Main_Page) for profiling. Then compile the benchmarks with `rustup nightly run cargo bench --no-run`. 62 63Run the benchmark binary with `perf` (shown here filtering to one particular benchmark, which will make the results easier to read). `perf` is only available to the root user on most systems as it fiddles with event counters in your CPU, so use `sudo`. We need to run the actual benchmark binary, hence the path into `target`. You can see the actual full path with `rustup run nightly cargo bench -v`; it will print out the commands it runs. If you use the exact path that `bench` outputs, make sure you get the one that's for the benchmarks, not the tests. You may also want to `cargo clean` so you have only one `benchmarks-` binary (they tend to accumulate). 64 65```bash 66sudo perf record target/release/deps/benchmarks-* --bench decode_10mib_reuse 67``` 68 69Then analyze the results, again with perf: 70 71```bash 72sudo perf annotate -l 73``` 74 75You'll see a bunch of interleaved rust source and assembly like this. The section with `lib.rs:327` is telling us that 4.02% of samples saw the `movzbl` aka bit shift as the active instruction. However, this percentage is not as exact as it seems due to a phenomenon called *skid*. Basically, a consequence of how fancy modern CPUs are is that this sort of instruction profiling is inherently inaccurate, especially in branch-heavy code. 76 77```text 78 lib.rs:322 0.70 : 10698: mov %rdi,%rax 79 2.82 : 1069b: shr $0x38,%rax 80 : if morsel == decode_tables::INVALID_VALUE { 81 : bad_byte_index = input_index; 82 : break; 83 : }; 84 : accum = (morsel as u64) << 58; 85 lib.rs:327 4.02 : 1069f: movzbl (%r9,%rax,1),%r15d 86 : // fast loop of 8 bytes at a time 87 : while input_index < length_of_full_chunks { 88 : let mut accum: u64; 89 : 90 : let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]); 91 : morsel = decode_table[(input_chunk >> 56) as usize]; 92 lib.rs:322 3.68 : 106a4: cmp $0xff,%r15 93 : if morsel == decode_tables::INVALID_VALUE { 94 0.00 : 106ab: je 1090e <base64::decode_config_buf::hbf68a45fefa299c1+0x46e> 95``` 96 97 98Fuzzing 99--- 100 101This uses [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). See `fuzz/fuzzers` for the available fuzzing scripts. To run, use an invocation like these: 102 103```bash 104cargo +nightly fuzz run roundtrip 105cargo +nightly fuzz run roundtrip_no_pad 106cargo +nightly fuzz run roundtrip_random_config -- -max_len=10240 107cargo +nightly fuzz run decode_random 108``` 109 110 111License 112--- 113 114This project is dual-licensed under MIT and Apache 2.0. 115