encodify 1.0.1

Fast Base64, Base32, Quoted-Printable, RFC 2047, UTF-7 and PEM encoding and decoding
Documentation

encodify

crates.io build docs.rs msrv crates.io

encodify is a fast Base64, Base32, Quoted-Printable, RFC 2047, UTF-7 and PEM encoding and decoding library written in Rust. It implements the binary-to-text encodings used across the Internet mail protocol stack:

  • the MIME content transfer encodings (RFC 2045) and MIME encoded words (RFC 2047);
  • the Base32 and Base64 alphabets of RFC 4648;
  • UTF-7 (RFC 2152) and the modified Base64 of IMAP mailbox names (RFC 3501);
  • dkim-quoted-printable (RFC 6376), percent and xtext escapes (RFC 2231, RFC 3461);
  • the textual encoding of PEM (RFC 7468).

Features

  • Base64:
    • Standard (+/) and URL-safe (-_) alphabets, with required, omitted or optional padding, and decoders that accept both alphabets.
    • Strict decoding that accepts exactly one encoding per value, and lenient decoding that skips whitespace and tolerates missing or misplaced padding as found in real-world e-mail.
    • MIME bodies: 76-column CRLF wrapping and line-aware decoding.
    • Folded values:
      • b= values in DKIM signatures;
      • iCalendar and vCard content lines, folded when encoding and unfolded when decoding;
      • values that end at a delimiter.
    • Incremental decoding for tokenizers, streaming to io::Write, fmt::Display, and compile-time encoding.
  • Base32:
    • RFC 4648 alphabet with or without padding, and the Stalwart alphabet used by ids, blob ids and storage keys.
    • u64 numerals as used by JMAP ids, streaming encoders and decoders, fmt::Display.
  • Quoted-Printable:
    • Body and attachment encoding with soft line breaks (RFC 2045), and lenient or strict decoding that borrows the input when there is nothing to rewrite.
    • "Q" encoding for header encoded words, in text and phrase contexts (RFC 2047).
    • dkim-quoted-printable (RFC 6376).
    • Exact encoded lengths with early exit, to choose between quoted-printable and base64 without encoding twice, and exact decoded lengths without decoding.
  • RFC 2047 encoded words:
    • Encoding of header text into B or Q words that never split a character, with folding.
    • Decoding of single encoded words for structured fields, and of whole unstructured field bodies with charset conversion supplied by the caller.
  • Escapes: percent (RFC 2231) and xtext (RFC 3461) encoding and decoding, borrowing when nothing is escaped.
  • UTF-7: IMAP modified UTF-7 mailbox names (strict or lenient) and RFC 2152 UTF-7 for MIME bodies.
  • PEM: armored blocks with labels, headers and checksums.
  • Performance and safety:
    • SIMD kernels for NEON (aarch64) and SSSE3/AVX2 (x86 and x86_64, detected at runtime), with fast portable fallbacks on every other target, including 32-bit ARM, RISC-V and wasm32.
    • Output appended to caller-owned buffers or written into slices, without zero-filling or hidden reallocations.
    • Two dependencies: memchr and simdutf8.

Usage

Every operation is a method on an engine constant, so the configuration is visible at the call site:

use encodify::{Fold, base32, base64, qp, rfc2047, utf7};

# fn main() -> Result<(), encodify::Error> {
// Base64: strict and lenient decoding, MIME wrapping, URL-safe tokens.
assert_eq!(base64::STANDARD.encode(b"Hello"), "SGVsbG8=");
assert_eq!(base64::MIME.decode("SGVs\r\nbG8=\r\n")?, b"Hello");
assert_eq!(base64::URL_SAFE_NO_PAD.encode([0xfb, 0xff]), "-_8");

// Encoding into an existing buffer never zero-fills it first.
let mut header = String::from("Authorization: Basic ");
base64::STANDARD.encode_append("user:secret", &mut header);
assert_eq!(header, "Authorization: Basic dXNlcjpzZWNyZXQ=");

// Folded iCalendar/vCard values decode in one call.
let card = b"SGVsbG8s\r\n IHdvcmxk\r\n IQ==\r\nEND:VCARD\r\n";
let mut photo = Vec::new();
let value = base64::STANDARD.decode_folded(card, &mut photo)?;
assert_eq!(photo, b"Hello, world!");
assert_eq!(&card[value.next..], b"END:VCARD\r\n");

// Base32 JMAP ids and RFC 4648 text.
assert_eq!(&*base32::STALWART.encode_u64(20080258862541), "singleton");
assert_eq!(base32::STANDARD.encode(b"foobar"), "MZXW6YTBOI======");

// Quoted-printable bodies and dkim-quoted-printable tags.
assert_eq!(qp::BODY.encode("Grüße,\nJürgen\n"), "Gr=C3=BC=C3=9Fe,\r\nJ=C3=BCrgen\r\n");
assert_eq!(qp::DKIM.decode("a=3Db=3B\r\n\t=20c")?, &b"a=b; c"[..]);

// RFC 2047 encoded words, both ways.
let mut subject = String::from("Subject: ");
let mut column = subject.len();
rfc2047::Q_TEXT.encode_words("utf-8", "Grüße aus Köln", &mut column, Fold::HEADER, &mut subject);
assert_eq!(subject, "Subject: =?utf-8?Q?Gr=C3=BC=C3=9Fe_aus_K=C3=B6ln?=");
let decoded = rfc2047::decode_text(b"=?utf-8?B?0J/RgNC40LLQtdGC?=", rfc2047::utf8_charset);
assert_eq!(decoded, "Привет");

// IMAP mailbox names.
assert_eq!(utf7::IMAP.encode("Entwürfe"), "Entw&APw-rfe");
assert_eq!(utf7::IMAP.decode("Entw&APw-rfe")?, "Entwürfe");
# Ok(())
# }

Performance

Throughput measured with criterion on the same inputs for every crate (cargo bench --bench codec). Encoders are measured in bytes of input per second and decoders in bytes of output per second, in GB/s (10^9 bytes). The factor in parentheses is how many times faster encodify is than the crate on that row, or the crate named next to it: 3.0x means three times the throughput, and a value below 1.0x means encodify is slower. The base64 and base32 benchmarks write into caller-provided buffers (the base32 crate always allocates); the quoted-printable benchmarks return a new buffer for both crates.

The crates compared are base64, base64-simd, base64-turbo, data-encoding, simdutf, base32, fast32 and quoted_printable.

At 64 KiB, against the fastest other crate for each operation:

Operation Apple M5 Max (NEON) AMD EPYC Zen 2 (AVX2)
Base64 encode 25.7 GB/s (1.0x simdutf) 19.2 GB/s (1.0x base64-turbo)
Base64 decode 18.1 GB/s (1.2x simdutf) 15.0 GB/s (1.0x base64-turbo)
Base64 MIME encode (76 columns, CRLF) 21.3 GB/s (1.5x simdutf) 10.7 GB/s (1.1x simdutf)
Base64 MIME decode (76 columns, CRLF) 14.1 GB/s (1.4x simdutf) 8.6 GB/s (1.7x simdutf)
Base32 encode 24.2 GB/s (6.5x data-encoding) 7.2 GB/s (4.8x data-encoding)
Base32 decode 10.6 GB/s (3.1x data-encoding) 5.0 GB/s (3.9x data-encoding)
Quoted-printable encode, Latin text 6.1 GB/s (5.1x quoted_printable) 2.0 GB/s (5.8x quoted_printable)
Quoted-printable decode, Latin text 5.3 GB/s (7.8x quoted_printable) 2.2 GB/s (9.0x quoted_printable)

Base64 encode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 6.58 GB/s 25.15 GB/s 25.73 GB/s 25.65 GB/s
base64 3.90 GB/s (1.7x) 5.12 GB/s (4.9x) 5.04 GB/s (5.1x) 5.02 GB/s (5.1x)
base64-simd 6.65 GB/s (1.0x) 13.07 GB/s (1.9x) 12.83 GB/s (2.0x) 12.82 GB/s (2.0x)
base64-turbo 5.30 GB/s (1.2x) 11.93 GB/s (2.1x) 12.09 GB/s (2.1x) 12.08 GB/s (2.1x)
data-encoding 2.40 GB/s (2.7x) 4.37 GB/s (5.8x) 4.43 GB/s (5.8x) 4.41 GB/s (5.8x)
simdutf 6.52 GB/s (1.0x) 25.78 GB/s (1.0x) 25.95 GB/s (1.0x) 25.96 GB/s (1.0x)

Base64 decode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 6.08 GB/s 17.70 GB/s 18.12 GB/s 18.12 GB/s
base64 2.65 GB/s (2.3x) 4.65 GB/s (3.8x) 4.63 GB/s (3.9x) 4.65 GB/s (3.9x)
base64-simd 7.73 GB/s (0.8x) 9.72 GB/s (1.8x) 9.59 GB/s (1.9x) 9.59 GB/s (1.9x)
base64-turbo 4.57 GB/s (1.3x) 6.88 GB/s (2.6x) 6.89 GB/s (2.6x) 6.89 GB/s (2.6x)
data-encoding 1.99 GB/s (3.1x) 4.16 GB/s (4.3x) 4.42 GB/s (4.1x) 4.42 GB/s (4.1x)
simdutf 2.02 GB/s (3.0x) 14.57 GB/s (1.2x) 15.38 GB/s (1.2x) 15.42 GB/s (1.2x)

Base64 MIME encode (76 columns, CRLF)

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 4.50 GB/s 18.21 GB/s 21.27 GB/s 21.52 GB/s
data-encoding 1.84 GB/s (2.4x) 3.88 GB/s (4.7x) 4.05 GB/s (5.3x) 4.05 GB/s (5.3x)
simdutf (LF only) 5.75 GB/s (0.8x) 13.17 GB/s (1.4x) 14.35 GB/s (1.5x) 14.69 GB/s (1.5x)

Base64 MIME decode (76 columns, CRLF)

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 3.48 GB/s 10.82 GB/s 14.08 GB/s 14.06 GB/s
base64 (strip + decode) 0.95 GB/s (3.7x) 1.04 GB/s (10.4x) 1.04 GB/s (13.6x) 1.03 GB/s (13.6x)
base64-simd (forgiving) 2.70 GB/s (1.3x) 1.75 GB/s (6.2x) 1.64 GB/s (8.6x) 1.63 GB/s (8.6x)
data-encoding 1.87 GB/s (1.9x) 2.64 GB/s (4.1x) 2.70 GB/s (5.2x) 2.69 GB/s (5.2x)
simdutf 2.00 GB/s (1.7x) 8.23 GB/s (1.3x) 10.08 GB/s (1.4x) 10.13 GB/s (1.4x)

Base32 encode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 3.89 GB/s 24.67 GB/s 24.25 GB/s 24.25 GB/s
base32 (allocates) 0.46 GB/s (8.5x) 1.55 GB/s (15.9x) 1.64 GB/s (14.8x) 1.27 GB/s (19.1x)
data-encoding 2.16 GB/s (1.8x) 3.73 GB/s (6.6x) 3.75 GB/s (6.5x) 3.71 GB/s (6.5x)
fast32 2.86 GB/s (1.4x) 3.53 GB/s (7.0x) 3.55 GB/s (6.8x) 3.51 GB/s (6.9x)

Base32 decode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 2.86 GB/s 10.63 GB/s 10.61 GB/s 10.62 GB/s
base32 (allocates) 0.76 GB/s (3.8x) 1.45 GB/s (7.3x) 1.52 GB/s (7.0x) 1.51 GB/s (7.0x)
data-encoding 1.74 GB/s (1.6x) 3.33 GB/s (3.2x) 3.42 GB/s (3.1x) 3.46 GB/s (3.1x)
fast32 2.18 GB/s (1.3x) 2.82 GB/s (3.8x) 2.87 GB/s (3.7x) 2.84 GB/s (3.7x)

Base32 u64 numerals (per id)

Implementation append decode encode
encodify 0.77 ns 1.66 ns 0.70 ns
fast32 2.04 ns (2.6x) 1.90 ns (1.1x)
fast32 (allocates) 20.53 ns (29.3x)

Quoted-printable encode, Latin text

Implementation 4 KiB 64 KiB 1 MiB
encodify 5.97 GB/s 6.13 GB/s 6.21 GB/s
quoted_printable 1.16 GB/s (5.2x) 1.20 GB/s (5.1x) 1.20 GB/s (5.2x)

Quoted-printable encode, Cyrillic text (mostly escaped)

Implementation 4 KiB 64 KiB 1 MiB
encodify 1.21 GB/s 1.16 GB/s 1.23 GB/s
quoted_printable 0.28 GB/s (4.3x) 0.29 GB/s (4.1x) 0.28 GB/s (4.3x)

Quoted-printable decode, Latin text

Implementation 4 KiB 64 KiB 1 MiB
encodify 5.35 GB/s 5.29 GB/s 5.39 GB/s
quoted_printable 0.64 GB/s (8.4x) 0.68 GB/s (7.8x) 0.70 GB/s (7.7x)

Quoted-printable decode, Cyrillic text (mostly escaped)

Implementation 4 KiB 64 KiB 1 MiB
encodify 1.37 GB/s 1.38 GB/s 1.37 GB/s
quoted_printable 0.27 GB/s (5.1x) 0.28 GB/s (4.9x) 0.28 GB/s (4.9x)

A 4-vCPU virtual machine; the other SIMD crates use their AVX2 code as well.

Base64 encode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 1.88 GB/s 16.47 GB/s 19.17 GB/s 17.95 GB/s
base64 1.18 GB/s (1.6x) 1.73 GB/s (9.5x) 1.74 GB/s (11.0x) 1.83 GB/s (9.8x)
base64-simd 2.06 GB/s (0.9x) 7.93 GB/s (2.1x) 8.31 GB/s (2.3x) 7.90 GB/s (2.3x)
base64-turbo 2.20 GB/s (0.9x) 14.59 GB/s (1.1x) 19.91 GB/s (1.0x) 18.72 GB/s (1.0x)
data-encoding 0.83 GB/s (2.3x) 1.78 GB/s (9.3x) 1.77 GB/s (10.8x) 1.76 GB/s (10.2x)
simdutf 1.99 GB/s (0.9x) 10.96 GB/s (1.5x) 13.96 GB/s (1.4x) 13.12 GB/s (1.4x)

Base64 decode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 1.63 GB/s 11.54 GB/s 14.97 GB/s 14.07 GB/s
base64 0.75 GB/s (2.2x) 1.57 GB/s (7.3x) 1.56 GB/s (9.6x) 1.63 GB/s (8.6x)
base64-simd 2.35 GB/s (0.7x) 4.99 GB/s (2.3x) 5.09 GB/s (2.9x) 5.20 GB/s (2.7x)
base64-turbo 1.59 GB/s (1.0x) 11.03 GB/s (1.0x) 15.64 GB/s (1.0x) 13.83 GB/s (1.0x)
data-encoding 0.64 GB/s (2.6x) 1.60 GB/s (7.2x) 1.63 GB/s (9.2x) 1.65 GB/s (8.6x)
simdutf 0.56 GB/s (2.9x) 6.74 GB/s (1.7x) 11.23 GB/s (1.3x) 9.71 GB/s (1.4x)

Base64 MIME encode (76 columns, CRLF)

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 1.36 GB/s 7.95 GB/s 10.72 GB/s 10.56 GB/s
data-encoding 0.68 GB/s (2.0x) 1.38 GB/s (5.8x) 1.36 GB/s (7.9x) 1.44 GB/s (7.3x)
simdutf (LF only) 1.40 GB/s (1.0x) 7.32 GB/s (1.1x) 9.50 GB/s (1.1x) 8.59 GB/s (1.2x)

Base64 MIME decode (76 columns, CRLF)

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 1.02 GB/s 5.82 GB/s 8.61 GB/s 8.37 GB/s
base64 (strip + decode) 0.32 GB/s (3.2x) 0.39 GB/s (14.9x) 0.39 GB/s (22.3x) 0.39 GB/s (21.6x)
base64-simd (forgiving) 1.02 GB/s (1.0x) 0.79 GB/s (7.3x) 0.87 GB/s (9.9x) 0.82 GB/s (10.3x)
data-encoding 0.59 GB/s (1.7x) 0.89 GB/s (6.5x) 0.91 GB/s (9.4x) 0.89 GB/s (9.4x)
simdutf 0.55 GB/s (1.9x) 3.75 GB/s (1.6x) 5.20 GB/s (1.7x) 5.23 GB/s (1.6x)

Base32 encode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 1.26 GB/s 6.49 GB/s 7.21 GB/s 6.70 GB/s
base32 (allocates) 0.18 GB/s (7.0x) 0.35 GB/s (18.5x) 0.36 GB/s (20.0x) 0.36 GB/s (18.6x)
data-encoding 0.75 GB/s (1.7x) 1.43 GB/s (4.5x) 1.51 GB/s (4.8x) 1.49 GB/s (4.5x)
fast32 0.98 GB/s (1.3x) 1.18 GB/s (5.5x) 1.20 GB/s (6.0x) 1.17 GB/s (5.7x)

Base32 decode

Implementation 32 B 1 KiB 64 KiB 1 MiB
encodify 0.90 GB/s 4.27 GB/s 5.03 GB/s 4.81 GB/s
base32 (allocates) 0.34 GB/s (2.6x) 0.46 GB/s (9.2x) 0.46 GB/s (11.0x) 0.45 GB/s (10.8x)
data-encoding 0.49 GB/s (1.8x) 1.18 GB/s (3.6x) 1.29 GB/s (3.9x) 1.32 GB/s (3.7x)
fast32 0.70 GB/s (1.3x) 0.92 GB/s (4.6x) 0.94 GB/s (5.4x) 0.93 GB/s (5.2x)

Base32 u64 numerals (per id)

Implementation append decode encode
encodify 9.78 ns 5.55 ns 4.43 ns
fast32 13.73 ns (1.4x) 12.53 ns (2.3x)
fast32 (allocates) 24.55 ns (5.5x)

Quoted-printable encode, Latin text

Implementation 4 KiB 64 KiB 1 MiB
encodify 2.05 GB/s 2.00 GB/s 1.76 GB/s
quoted_printable 0.39 GB/s (5.2x) 0.35 GB/s (5.8x) 0.39 GB/s (4.5x)

Quoted-printable encode, Cyrillic text (mostly escaped)

Implementation 4 KiB 64 KiB 1 MiB
encodify 0.41 GB/s 0.46 GB/s 0.45 GB/s
quoted_printable 0.11 GB/s (3.9x) 0.11 GB/s (4.4x) 0.10 GB/s (4.6x)

Quoted-printable decode, Latin text

Implementation 4 KiB 64 KiB 1 MiB
encodify 2.17 GB/s 2.24 GB/s 2.29 GB/s
quoted_printable 0.22 GB/s (9.7x) 0.25 GB/s (9.0x) 0.24 GB/s (9.5x)

Quoted-printable decode, Cyrillic text (mostly escaped)

Implementation 4 KiB 64 KiB 1 MiB
encodify 0.49 GB/s 0.51 GB/s 0.48 GB/s
quoted_printable 0.09 GB/s (5.4x) 0.09 GB/s (5.8x) 0.09 GB/s (5.2x)

SSSE3

x86 CPUs without AVX2 use the SSSE3 kernels, measured on the same EPYC with --cfg encodify_no_avx2. The other SIMD crates cannot be restricted to SSSE3 in the same way, so the factors are against the fastest portable crate.

Operation 32 B 1 KiB 4 KiB 64 KiB 1 MiB
Base64 encode 1.76 GB/s (1.5x base64) 8.58 GB/s (5.1x base64) 9.92 GB/s (5.5x data-encoding) 9.83 GB/s (5.5x data-encoding)
Base64 decode 1.60 GB/s (1.9x base64) 7.45 GB/s (4.6x base64) 8.30 GB/s (5.0x base64) 8.25 GB/s (5.0x base64)
Base64 MIME encode (76 columns, CRLF) 1.37 GB/s (2.1x data-encoding) 6.35 GB/s (4.3x data-encoding) 7.78 GB/s (5.5x data-encoding) 7.17 GB/s (4.9x data-encoding)
Base64 MIME decode (76 columns, CRLF) 0.97 GB/s (1.6x data-encoding) 4.42 GB/s (5.2x data-encoding) 6.15 GB/s (6.7x data-encoding) 6.19 GB/s (7.0x data-encoding)
Base32 encode 1.23 GB/s (1.3x fast32) 5.93 GB/s (4.0x data-encoding) 7.19 GB/s (4.8x data-encoding) 6.81 GB/s (4.6x data-encoding)
Base32 decode 0.92 GB/s (1.3x fast32) 3.83 GB/s (3.2x data-encoding) 4.66 GB/s (4.0x data-encoding) 4.65 GB/s (4.2x data-encoding)
Quoted-printable encode, Latin text 1.87 GB/s (5.1x quoted_printable) 1.98 GB/s (5.4x quoted_printable) 1.97 GB/s (5.5x quoted_printable)
Quoted-printable decode, Latin text 2.24 GB/s (9.8x quoted_printable) 2.21 GB/s (9.1x quoted_printable) 2.30 GB/s (9.4x quoted_printable)

Portable fallbacks

Targets without NEON, SSSE3 or AVX2 (32-bit ARM, RISC-V, PowerPC, s390x, wasm32 and others) use portable code: table-driven base64 (two symbols per 12-bit lookup when encoding, four pre-shifted tables when decoding), table-driven base32 and SWAR quoted-printable. Measured with --cfg encodify_scalar, which forces these fallbacks, against the fastest portable crate.

Apple M5 Max:

Operation 32 B 1 KiB 4 KiB 64 KiB 1 MiB
Base64 encode 5.38 GB/s (1.4x base64) 12.94 GB/s (2.5x base64) 13.63 GB/s (2.7x base64) 13.45 GB/s (2.7x base64)
Base64 decode 3.11 GB/s (1.2x base64) 4.68 GB/s (1.0x base64) 4.66 GB/s (1.0x base64) 4.65 GB/s (1.0x base64)
Base64 MIME encode (76 columns, CRLF) 3.90 GB/s (2.1x data-encoding) 7.04 GB/s (1.8x data-encoding) 7.28 GB/s (1.8x data-encoding) 7.50 GB/s (1.9x data-encoding)
Base64 MIME decode (76 columns, CRLF) 2.42 GB/s (1.3x data-encoding) 3.48 GB/s (1.3x data-encoding) 3.54 GB/s (1.3x data-encoding) 3.55 GB/s (1.3x data-encoding)
Base32 encode 3.18 GB/s (1.1x fast32) 4.39 GB/s (1.2x data-encoding) 4.45 GB/s (1.2x data-encoding) 4.50 GB/s (1.2x data-encoding)
Base32 decode 2.53 GB/s (1.1x fast32) 3.85 GB/s (1.2x data-encoding) 3.74 GB/s (1.1x data-encoding) 3.88 GB/s (1.1x data-encoding)
Quoted-printable encode, Latin text 5.30 GB/s (4.6x quoted_printable) 5.36 GB/s (4.5x quoted_printable) 5.45 GB/s (4.5x quoted_printable)
Quoted-printable decode, Latin text 4.71 GB/s (7.0x quoted_printable) 4.74 GB/s (6.7x quoted_printable) 4.75 GB/s (6.6x quoted_printable)

AMD EPYC, Zen 2:

Operation 32 B 1 KiB 4 KiB 64 KiB 1 MiB
Base64 encode 1.54 GB/s (1.3x base64) 3.68 GB/s (2.1x data-encoding) 3.67 GB/s (2.0x base64) 3.65 GB/s (2.1x data-encoding)
Base64 decode 1.16 GB/s (1.4x base64) 2.17 GB/s (1.4x base64) 2.22 GB/s (1.4x data-encoding) 2.30 GB/s (1.4x base64)
Base64 MIME encode (76 columns, CRLF) 1.11 GB/s (1.7x data-encoding) 2.15 GB/s (1.5x data-encoding) 2.11 GB/s (1.4x data-encoding) 2.11 GB/s (1.5x data-encoding)
Base64 MIME decode (76 columns, CRLF) 0.97 GB/s (1.6x data-encoding) 1.49 GB/s (1.7x data-encoding) 1.52 GB/s (2.1x data-encoding) 1.48 GB/s (1.8x data-encoding)
Base32 encode 1.04 GB/s (1.2x fast32) 1.56 GB/s (1.1x data-encoding) 1.70 GB/s (1.2x data-encoding) 1.62 GB/s (1.1x data-encoding)
Base32 decode 0.88 GB/s (1.4x fast32) 1.65 GB/s (1.3x data-encoding) 1.80 GB/s (1.4x data-encoding) 1.74 GB/s (1.4x data-encoding)
Quoted-printable encode, Latin text 1.61 GB/s (4.3x quoted_printable) 1.57 GB/s (4.4x quoted_printable) 1.59 GB/s (4.2x quoted_printable)
Quoted-printable decode, Latin text 1.73 GB/s (7.8x quoted_printable) 1.75 GB/s (7.4x quoted_printable) 1.75 GB/s (7.4x quoted_printable)

Portability

The minimum supported Rust version is 1.89. SIMD kernels are chosen at compile time on aarch64 (NEON) and at runtime on x86 and x86_64 (SSSE3 and AVX2, when SSE2 is part of the target baseline). Every other target, including 32-bit ARM (where NEON is not stable in Rust), RISC-V, PowerPC, s390x and wasm32, uses portable fallbacks that match or beat the fastest portable crates. Building with RUSTFLAGS="--cfg encodify_scalar" forces the fallbacks everywhere, and --cfg encodify_no_avx2 limits x86 to the SSSE3 kernels; this is how both are tested and measured.

Testing, Fuzzing & Benchmarking

To run the testsuite:

 $ cargo test

including the portable fallbacks and, on Apple Silicon, the x86 kernels under Rosetta:

 $ RUSTFLAGS="--cfg encodify_scalar" cargo test --target-dir target/scalar
 $ cargo test --target x86_64-apple-darwin
 $ ROSETTA_ADVERTISE_AVX=1 cargo test --target x86_64-apple-darwin

To fuzz the library with cargo-fuzz:

 $ cargo +nightly fuzz run encodify

including the portable fallbacks and, on Apple Silicon, the x86 kernels under Rosetta (without AddressSanitizer):

 $ RUSTFLAGS="--cfg encodify_scalar" cargo +nightly fuzz run --target-dir target/fuzz-scalar encodify
 $ ROSETTA_ADVERTISE_AVX=1 cargo fuzz run --target x86_64-apple-darwin --sanitizer none encodify

and, to run the benchmarks against other crates (Rust 1.93 or later, because of base64-turbo), with the SIMD kernels, the SSSE3 kernels and the portable fallbacks:

 $ cargo bench --bench codec
 $ RUSTFLAGS="--cfg encodify_no_avx2" CARGO_TARGET_DIR=target/ssse3 cargo bench --bench codec
 $ RUSTFLAGS="--cfg encodify_scalar" CARGO_TARGET_DIR=target/scalar cargo bench --bench codec

Conformed RFCs

License

Licensed under either of

at your option.