xcodec-1.1.0.0: README.md
xcodec [](
https://hackage.haskell.org/package/xcodec)[](
https://builds.sr.ht/~z0/xcodec/commits/main/ipfshs-ci.yml?)
------------------------------------------------------------
The `xcodec` Haskell library provides a type-class for generic programming on
bit data for writing encoders and decoders for codecs. The `BinaryTranscoder`
class provides a common interface of methods for processing binary data, and
default instances for the `bytestring` types: `ByteString`, `ShortByteString`,
and `LazyByteString`. The `StreamTranscoder` class then provides the abstract
methods for a generic function encoding from and a generic function decoding to
the types implementing `BinaryTranscoder`.
Why?
----
`xcodec` exists to abstract common patterns that arise when writing code with
the `bytestring` library in Haskell:
- Reusing code for `ShortByteString`, `ByteString` and `LazyByteString`.
- Having common interface for transferring into the bytestring `Builder` type.
- Reading to and from numeric values for bitwise manipulation or initializing
from constant values.
Making bytestring code generic, can also make code more memory efficient; for
example, we can write functions for `BinaryTranscoder` and apply them to
`LazyByteString` when reading large files and to `ShortByteString` when working
on smaller internal structures.
Examples
--------
Using `xcodec` we can easily read numeric bit data to binary formats,
programmatically:
```haskell
import Data.ByteString (ByteString)
import Data.ByteString.Short (ShortByteString)
import Data.ByteString.Lazy (LazyByteString)
import Data.Word (Word16)
import Data.XCodec.BinaryTranscoder (packValue)
-- Infers: packValue :: Int -> ByteString
exStrict :: ByteString
exStrict = packValue (0xdeadbeef :: Int)
-- Infers: packValue :: Integer -> LazyByteString
exLazy :: LazyByteString
exLazy = packValue (0xf0000000000000000000000d :: Integer)
-- Infers: packValue :: Word16 -> ShortByteString
exShort :: ShortByteString
exShort = packValue (0xcafe :: Word16)
```
And then serialize them through a common interface which makes it easy to
intersperse data from different formats:
```haskell
import Data.ByteString.Builder qualified as Builder
import Data.ByteString.Lazy (LazyByteString)
import Data.XCodec.BinaryTranscoder (serializeValue)
-- We can join several BXCs and Builders into a single unit of data.
exBuilder :: LazyByteString
exBuilder =
Builder.toLazyByteString . mconcat $
[ serializeValue exLazy, -- serializeValue :: LazyByteString -> Builder
serializeValue exStrict, -- serializeValue :: ByteString -> Builder
serializeValue exShort, -- serializeValue :: ShortByteString -> Builder
Builder.string8 "Hello, World!" -- string8 :: String -> Builder
]
```
It also enables extracting binary data into `Integer` format so that bitwise
transformations can be performed on large sets of binary data in *O(n)* time
with a specified [byte-order](https://en.wikipedia.org/wiki/Endianness):
```haskell
import Data.Bits ((.>>.), (.&.))
import Data.Word (Word32)
import Data.XCodec.BinaryTranscoder (BinaryTranscoder, unpackValue)
-- We can easily read an entire bit-set representation of transcoder data,
-- directly from LazyByteString because it derives BinaryTranscoder. This
-- function produces its big-endian representation
largeBitSet :: Integer
largeBitSet = unpackValueBE exBuilder
-- Now, we can perform bitwise operations on the value, for instance, extracting
-- the lower bits 32nd-63rd bits from a little-endian value
extract32bits :: Word32
extract32bits = fromIntegral ((unpackValueLE exBuilder .>>. 32) .&. 0xFFFFFFFF)
```
Development
-----------
Unit tests are provided on the main [ipfshs repo](https://git.sr.ht/~z0/ipfshs),
and bugs can be reported on [ipfshs ticket tracker](
https://todo.sr.ht/~z0/ipfshs).
Licensing
---------
The `xcodec` project and its modules are free software and licensed under the
BSD 3-clause license. See [LICENSE.txt](LICENSE.txt).
Copyright © 2026 Zoey McBride | [zoeymcbride@mailbox.org](
mailto:zoeymcbride@mailbox.org)