packages feed

packed-data-0.2.0.0: README.md

# `packed-data` for Haskell

![Hackage Version](https://img.shields.io/hackage/v/packed-data)
[![Doc](https://img.shields.io/badge/Documentation-Haddock-purple)](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'
```