Skip to main content

Crate encodify

Crate encodify 

Source
Expand description

§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};

// 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");

§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:

OperationApple M5 Max (NEON)AMD EPYC Zen 2 (AVX2)
Base64 encode25.7 GB/s (1.0x simdutf)19.2 GB/s (1.0x base64-turbo)
Base64 decode18.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 encode24.2 GB/s (6.5x data-encoding)7.2 GB/s (4.8x data-encoding)
Base32 decode10.6 GB/s (3.1x data-encoding)5.0 GB/s (3.9x data-encoding)
Quoted-printable encode, Latin text6.1 GB/s (5.1x quoted_printable)2.0 GB/s (5.8x quoted_printable)
Quoted-printable decode, Latin text5.3 GB/s (7.8x quoted_printable)2.2 GB/s (9.0x quoted_printable)
Apple M5 Max (NEON): every size and crate
§Base64 encode
Implementation32 B1 KiB64 KiB1 MiB
encodify6.58 GB/s25.15 GB/s25.73 GB/s25.65 GB/s
base643.90 GB/s (1.7x)5.12 GB/s (4.9x)5.04 GB/s (5.1x)5.02 GB/s (5.1x)
base64-simd6.65 GB/s (1.0x)13.07 GB/s (1.9x)12.83 GB/s (2.0x)12.82 GB/s (2.0x)
base64-turbo5.30 GB/s (1.2x)11.93 GB/s (2.1x)12.09 GB/s (2.1x)12.08 GB/s (2.1x)
data-encoding2.40 GB/s (2.7x)4.37 GB/s (5.8x)4.43 GB/s (5.8x)4.41 GB/s (5.8x)
simdutf6.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
Implementation32 B1 KiB64 KiB1 MiB
encodify6.08 GB/s17.70 GB/s18.12 GB/s18.12 GB/s
base642.65 GB/s (2.3x)4.65 GB/s (3.8x)4.63 GB/s (3.9x)4.65 GB/s (3.9x)
base64-simd7.73 GB/s (0.8x)9.72 GB/s (1.8x)9.59 GB/s (1.9x)9.59 GB/s (1.9x)
base64-turbo4.57 GB/s (1.3x)6.88 GB/s (2.6x)6.89 GB/s (2.6x)6.89 GB/s (2.6x)
data-encoding1.99 GB/s (3.1x)4.16 GB/s (4.3x)4.42 GB/s (4.1x)4.42 GB/s (4.1x)
simdutf2.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)
Implementation32 B1 KiB64 KiB1 MiB
encodify4.50 GB/s18.21 GB/s21.27 GB/s21.52 GB/s
data-encoding1.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)
Implementation32 B1 KiB64 KiB1 MiB
encodify3.48 GB/s10.82 GB/s14.08 GB/s14.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-encoding1.87 GB/s (1.9x)2.64 GB/s (4.1x)2.70 GB/s (5.2x)2.69 GB/s (5.2x)
simdutf2.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
Implementation32 B1 KiB64 KiB1 MiB
encodify3.89 GB/s24.67 GB/s24.25 GB/s24.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-encoding2.16 GB/s (1.8x)3.73 GB/s (6.6x)3.75 GB/s (6.5x)3.71 GB/s (6.5x)
fast322.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
Implementation32 B1 KiB64 KiB1 MiB
encodify2.86 GB/s10.63 GB/s10.61 GB/s10.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-encoding1.74 GB/s (1.6x)3.33 GB/s (3.2x)3.42 GB/s (3.1x)3.46 GB/s (3.1x)
fast322.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)
Implementationappenddecodeencode
encodify0.77 ns1.66 ns0.70 ns
fast322.04 ns (2.6x)1.90 ns (1.1x)
fast32 (allocates)20.53 ns (29.3x)
§Quoted-printable encode, Latin text
Implementation4 KiB64 KiB1 MiB
encodify5.97 GB/s6.13 GB/s6.21 GB/s
quoted_printable1.16 GB/s (5.2x)1.20 GB/s (5.1x)1.20 GB/s (5.2x)
§Quoted-printable encode, Cyrillic text (mostly escaped)
Implementation4 KiB64 KiB1 MiB
encodify1.21 GB/s1.16 GB/s1.23 GB/s
quoted_printable0.28 GB/s (4.3x)0.29 GB/s (4.1x)0.28 GB/s (4.3x)
§Quoted-printable decode, Latin text
Implementation4 KiB64 KiB1 MiB
encodify5.35 GB/s5.29 GB/s5.39 GB/s
quoted_printable0.64 GB/s (8.4x)0.68 GB/s (7.8x)0.70 GB/s (7.7x)
§Quoted-printable decode, Cyrillic text (mostly escaped)
Implementation4 KiB64 KiB1 MiB
encodify1.37 GB/s1.38 GB/s1.37 GB/s
quoted_printable0.27 GB/s (5.1x)0.28 GB/s (4.9x)0.28 GB/s (4.9x)
AMD EPYC, Zen 2 (AVX2): every size and crate

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

§Base64 encode
Implementation32 B1 KiB64 KiB1 MiB
encodify1.88 GB/s16.47 GB/s19.17 GB/s17.95 GB/s
base641.18 GB/s (1.6x)1.73 GB/s (9.5x)1.74 GB/s (11.0x)1.83 GB/s (9.8x)
base64-simd2.06 GB/s (0.9x)7.93 GB/s (2.1x)8.31 GB/s (2.3x)7.90 GB/s (2.3x)
base64-turbo2.20 GB/s (0.9x)14.59 GB/s (1.1x)19.91 GB/s (1.0x)18.72 GB/s (1.0x)
data-encoding0.83 GB/s (2.3x)1.78 GB/s (9.3x)1.77 GB/s (10.8x)1.76 GB/s (10.2x)
simdutf1.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
Implementation32 B1 KiB64 KiB1 MiB
encodify1.63 GB/s11.54 GB/s14.97 GB/s14.07 GB/s
base640.75 GB/s (2.2x)1.57 GB/s (7.3x)1.56 GB/s (9.6x)1.63 GB/s (8.6x)
base64-simd2.35 GB/s (0.7x)4.99 GB/s (2.3x)5.09 GB/s (2.9x)5.20 GB/s (2.7x)
base64-turbo1.59 GB/s (1.0x)11.03 GB/s (1.0x)15.64 GB/s (1.0x)13.83 GB/s (1.0x)
data-encoding0.64 GB/s (2.6x)1.60 GB/s (7.2x)1.63 GB/s (9.2x)1.65 GB/s (8.6x)
simdutf0.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)
Implementation32 B1 KiB64 KiB1 MiB
encodify1.36 GB/s7.95 GB/s10.72 GB/s10.56 GB/s
data-encoding0.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)
Implementation32 B1 KiB64 KiB1 MiB
encodify1.02 GB/s5.82 GB/s8.61 GB/s8.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-encoding0.59 GB/s (1.7x)0.89 GB/s (6.5x)0.91 GB/s (9.4x)0.89 GB/s (9.4x)
simdutf0.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
Implementation32 B1 KiB64 KiB1 MiB
encodify1.26 GB/s6.49 GB/s7.21 GB/s6.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-encoding0.75 GB/s (1.7x)1.43 GB/s (4.5x)1.51 GB/s (4.8x)1.49 GB/s (4.5x)
fast320.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
Implementation32 B1 KiB64 KiB1 MiB
encodify0.90 GB/s4.27 GB/s5.03 GB/s4.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-encoding0.49 GB/s (1.8x)1.18 GB/s (3.6x)1.29 GB/s (3.9x)1.32 GB/s (3.7x)
fast320.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)
Implementationappenddecodeencode
encodify9.78 ns5.55 ns4.43 ns
fast3213.73 ns (1.4x)12.53 ns (2.3x)
fast32 (allocates)24.55 ns (5.5x)
§Quoted-printable encode, Latin text
Implementation4 KiB64 KiB1 MiB
encodify2.05 GB/s2.00 GB/s1.76 GB/s
quoted_printable0.39 GB/s (5.2x)0.35 GB/s (5.8x)0.39 GB/s (4.5x)
§Quoted-printable encode, Cyrillic text (mostly escaped)
Implementation4 KiB64 KiB1 MiB
encodify0.41 GB/s0.46 GB/s0.45 GB/s
quoted_printable0.11 GB/s (3.9x)0.11 GB/s (4.4x)0.10 GB/s (4.6x)
§Quoted-printable decode, Latin text
Implementation4 KiB64 KiB1 MiB
encodify2.17 GB/s2.24 GB/s2.29 GB/s
quoted_printable0.22 GB/s (9.7x)0.25 GB/s (9.0x)0.24 GB/s (9.5x)
§Quoted-printable decode, Cyrillic text (mostly escaped)
Implementation4 KiB64 KiB1 MiB
encodify0.49 GB/s0.51 GB/s0.48 GB/s
quoted_printable0.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.

Operation32 B1 KiB4 KiB64 KiB1 MiB
Base64 encode1.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 decode1.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 encode1.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 decode0.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 text1.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 text2.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:

Operation32 B1 KiB4 KiB64 KiB1 MiB
Base64 encode5.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 decode3.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 encode3.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 decode2.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 text5.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 text4.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:

Operation32 B1 KiB4 KiB64 KiB1 MiB
Base64 encode1.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 decode1.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 encode1.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 decode0.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 text1.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 text1.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.

Modules§

base32
Base32 (RFC 4648 section 6) and the Stalwart base32 alphabet.
base64
Base64 (RFC 4648 sections 4 and 5, RFC 2045 section 6.8).
hex
Hexadecimal escapes shared by quoted-printable (=XX), percent-encoding (%XX) and xtext (+XX).
pem
PEM textual encoding (RFC 7468) and OpenPGP ASCII armor (RFC 9580 section 6.2).
qp
Quoted-printable (RFC 2045 section 6.7), the “Q” encoding of RFC 2047 encoded words and dkim-quoted-printable (RFC 6376 section 2.11).
rfc2047
Encoding and decoding of RFC 2047 encoded words.
utf7
UTF-7 (RFC 2152) and the modified UTF-7 of IMAP mailbox names (RFC 3501 section 5.1.3).

Structs§

Fold
How encoded text embedded in a header or a content line is folded.

Enums§

Error
Error returned by the decoders and by the encoders that write into a caller-provided slice.

Traits§

Buffer
A growable buffer that encoders append their output to.