# `packed-data` for Haskell

[](https://hackage.haskell.org/package/packed-data-0.1.0.1/docs/Data-Packed.html)
Build, traverse and deserialise packed data in Haskell.
## What is this for?
When components of a system exchange data, each component has to make sure that they send data in a way the recipient will be able to read. A simple example is an API, sending JSON data for the client to parse. This process of decoding the data takes time, especially for big objects like HTML pages.
*Packed* data is data serialised into a binary format that is usable as-is, meaning there is no need to parse it to be able to use it. Another perk of such format is that it can be stored in files easily.
`packed-data` allows using packed data type-safely, without explicit pointer arithmetic.
## A portable library
Unlike other implementations of packed-data-support (e.g. [Gibbon](https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.ECOOP.2017.26)), `packed-data` is a library that does not modify the compiler in any way. It relies solely on already existing libraries (like `ByteString`), Template Haskell and common GHC extensions. This means that, virtually, `packed-data` can be used with any version of GHC (as of today, it has been tested GHC 9.2-9.12).
Its API is inspired by an example from the [Linear Haskell](https://dl.acm.org/doi/10.1145/3158093) paper (code available [here](https://github.com/tweag/linear-types/blob/12bed0d41d599e2697b29c5c4b37990642970e6c/Examples/src/Cursors/PureStorable.hs)).
## Example
```haskell
import qualified Data.Packed.Reader as R
import Data.Packed.Reader
import Data.Packed
data Tree a = Leaf a | Node (Tree a) (Tree a)
$(mkPacked ''Tree '[])
-- Compute sum of values in the tree
-- Using the generated 'caseTree' function
sumPacked :: PackedReader '[Tree Int] r Int
sumPacked =
caseTree -- Generated by Template Haskell
( R.do -- If Tree is a Leaf
!n <- reader
R.return n
)
( R.do -- If Tree is a Node
!left <- sumPacked
!right <- sumPacked
let !res = left + right
R.return res
)
-- Alternatively, you can use generated pattern synonyms
sumPacked = PackedReader $ \case
PackedLeaf l -> reader `with` l
PackedNode n -> threadedWith n $ R.do
!left <- sumPacked2
!right <- sumPacked2
let !res = left + right
R.return res
getSum :: Packed '[Tree Int] -> IO Int
getSum = runReader sumPacked
packTree :: Tree Int -> Packed '[Tree Int]
packTree = pack
```
Take a look at the `benchmark` directory for more examples.
Documentation is available on [Hackage](https://hackage.haskell.org/package/packed-data-0.1.0.1/docs/Data-Packed.html)
## Benchmark
To run benchmarks, run the following command:
```
stack bench packed-data:bench:tree-bench
# Saves the report as CSV
stack bench packed-data:bench:tree-bench --ba --csv bench.csv
# Saves the report, and runs a specific test
stach bench packed-data:bench:tree-bench --ba '--csv bench.csv sums'
```