bitfield: Generic and easy to use haskell bitfields

[ bit, data, library, mit ] [ Propose Tags ] [ Report a vulnerability ]

Generic and easy to use haskell bitfields. Allows packing and modifying datatypes in a compact representation. See README.md or Data.Bitfield for documentation.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.0.0.0, 0.0.0.1
Change log CHANGELOG.md
Dependencies base (>=4 && <5) [details]
Tested with ghc ==8.8.4 || ==8.10.7 || ==9.2.5 || ==9.4.3
License MIT
Copyright 2022 Jannis
Author Jannis
Maintainer Jannis <overesch.jannis@gmail.com>
Category Data, Bit
Source repo head: git clone https://github.com/1Jajen1/bitfield
Uploaded by JannisO at 2024-08-12T14:27:30Z
Distributions
Downloads 117 total (7 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2024-08-12 [all 1 reports]

Readme for bitfield-0.0.0.1

[back to package description]

bitfield

CI badge made with Haskell Hackage

Description

Generic and easy to use bitfields. Pack and unpack records into compact representations.

Example

import Data.Bitfield

data Example = Example { one :: Word8, two :: Bool, three :: Bool } deriving (Show, Generic)
 
x :: Bitfield Word16 Example
x = pack $ Example 5 False True

>>> x
"Example { one = 5, two = False, three = True }"
>>> get @"two" x
"False"
-- Requires OverloadedRecordDot
>>> x.two
"False"
>>> set @"three" x False
"Example { one = 5, two = False, three = False }"

x is represented using Word16 instead of the full heap object Example and thus takes far less memory.

Custom fields

There are two important typeclasses for working with types in bitfields: AsRep and HasFixedBitSize.

The most common way to use them is to derive them via either an underlying Enum or Integral instance.

Via Enum

data AEnum = A1 | A2 | A3
  deriving stock (Generic, Enum)
  deriving (HasFixedBitSize, AsRep rep) via (GenericEnum AEnum)

This still requires a Generic instance to count the constructors of AEnum for the HasFixedBitSize instance. The resulting field has a size of Log2 NumConstructors rounded up (2 bits for AEnum). The actual value will be constructed using the Enum instance, so unless that is derived, the constructor order won't matter.

Via Integral

newtype SmallInt = UnsafeSmallInt Int
  deriving (HasFixedBitSize, AsRep rep) via (ViaIntegral 5 Int)

This creates a HasFixedBitSize instance with a fixed bit size of 5 and a AsRep instance which reads and writes 5 bit values.

Note: The value is not truncated nor is it otherwise checked that the underlying value actually fits into the specified bit size. If it is too large it will write over other values!

Type safety

Any operation on a Bitfield checks (on the type level) if that Bitfield is valid. Any field operation also requires a HasField instance, guaranteeing that such a field exists. The following examples will not compile:

data Bad1 = Bad1 { a :: Bool, b :: Word8, c :: Bool }

x :: Bitfield Word8 Bad1
x = pack $ Bad1 True 1 True
-- Datatype Bad1 needs 10 bits, but the given representation Word8 has 8

y :: Bitfield Word16 Bad1 -> Word8
y b = get @"test" b
-- No instance HasField "test" Bad1 Word8