base16: Fast RFC 4648-compliant Base16 encoding

[ bsd3, data, library ] [ Propose Tags ] [ Report a vulnerability ]

RFC 4648-compliant Base16 encodings and decodings. This library provides performant encoding and decoding primitives, as well as support for textual values.


[Skip to Readme]

Flags

Manual Flags

NameDescriptionDefault
simd

Use bundled SIMD kernels where supported, with a scalar fallback

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0, 0.1.1, 0.1.2, 0.1.2.1, 0.1.3.0, 0.2.0.0, 0.2.0.1, 0.2.1.0, 0.3.0.0, 0.3.0.1, 0.3.0.2, 0.3.1.0, 0.3.2.0, 0.3.2.1, 1.0, 2.0
Change log CHANGELOG.md
Dependencies base (>=4.18 && <4.23), bytestring (>=0.11 && <0.13), deepseq (>=1.4.4.0 && <1.6), primitive (>=0.6 && <0.10), text (>=2.0 && <2.3), text-short (>=0.1 && <0.2) [details]
Tested with ghc ==9.6.7 || ==9.8.4 || ==9.10.3 || ==9.12.4 || ==9.14.1
License BSD-3-Clause
Copyright (c) 2020-2026 Emily Pillmore
Author Emily Pillmore
Maintainer Emily Pillmore <emilypi@cohomolo.gy>
Uploaded by topos at 2026-10-19T17:45:51Z
Category Data
Home page https://github.com/emilypi/base16
Bug tracker https://github.com/emilypi/base16/issues
Source repo head: git clone https://github.com/emilypi/base16.git
Distributions Arch:1.0, LTSHaskell:1.0, Stackage:1.0
Reverse Dependencies 19 direct, 4025 indirect [details]
Downloads 10948 total (92 in the last 30 days)
Rating 2.25 (votes: 2) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2026-10-19 [all 1 reports]

Readme for base16-2.0

[back to package description]

Base16

Build Status Hackage

RFC 4648-compliant Base16 encoding and decoding for strict, lazy, and short ByteString and Text values. Encoding produces lowercase hex; decoding accepts lowercase, uppercase, and mixed case.

The API tracks encoded values with the Base16 wrapper. Use parseBase16 to validate external input and retain its original representation:

{-# LANGUAGE OverloadedStrings #-}
import Data.Base16.Types (extractBase16)
import qualified Data.ByteString.Base16 as B16

extractBase16 (B16.encodeBase16' "Sun") -- "53756e"
B16.parseBase16 "53756E"               -- Right "53756E"
B16.decodeBase16Untyped "53756E"       -- Right "Sun"
B16.parseBase16 "abc"                  -- Left "invalid bytestring size"

For a Boolean check, use isRight . parseBase16 from Data.Either. Version 2.0 removes isBase16 and isValidBase16; see MIGRATION-2.0.md for replacement examples, lazy decoding changes, and compiler requirements. For companion optics and pattern synonyms, see base16-lens.

Lenient Text decoding ignores non-hex characters and a final unpaired hex digit. It preserves valid UTF-8 sequences and interprets each invalid UTF-8 byte as Latin-1, so malformed input does not raise Unicode exceptions. This also applies to lazy Text and ShortText; see the migration guide for details.

SIMD

The optional, manual simd flag enables bundled ARM64 NEON and runtime-detected x86-64 AVX2/SSSE3 kernels for strict ByteString and ShortByteString encoding, checked decoding, and typed decoding, including the lazy and Text APIs built on those operations. ShortByteString and ShortText use direct byte-array bindings without pinning or copying through strict ByteString. Their parsers validate through the short decoder. Unsupported targets and inputs below the SIMD thresholds fall back to Haskell scalar loops. Lenient decoding remains scalar.

The flag is off by default. Enable it in your cabal.project:

package base16
  flags: +simd

No external native library is needed. SIMD uses the same alphabet checks and error offsets as the scalar implementation.

Development

GHC 9.6 or later is required. Test both build configurations:

cabal test --flags=-simd
cabal test --flags=simd
cabal bench --flags=-simd --benchmark-options='--iters 1'
cabal bench --flags=simd --benchmark-options='--iters 1'

The benchmark suite covers small inputs, vector/call boundaries, and buffers up to one million bytes. For timings, omit --iters 1 and use separate build directories (--builddir=dist-scalar and --builddir=dist-simd). Compare on the same machine and compiler; gains depend on input size and CPU.

Native differential tests check exact buffer bounds, alignment, invalid bytes, and scalar fallback. CI runs them with address/undefined-behavior sanitizers and guard pages, and builds the Haskell tests, benchmarks, and Haddock from the source distribution with both flag settings.