git.iko.soy/rowtype-yoga/purescript-arraybuffer-builder
on master help sign in
144 lines 5.2 kB history raw
1# purescript-arraybuffer-builder
3[![CI](https://github.com/rowtype-yoga/purescript-arraybuffer-builder/workflows/CI/badge.svg?branch=master)](https://github.com/rowtype-yoga/purescript-arraybuffer-builder/actions)
4[![Pursuit](http://pursuit.purescript.org/packages/purescript-arraybuffer-builder/badge)](http://pursuit.purescript.org/packages/purescript-arraybuffer-builder/)
5[![Maintainer: jamesdbrock](https://img.shields.io/badge/maintainer-jamesdbrock-teal.svg)](https://github.com/jamesdbrock)
8[`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)
9serialization in the “builder monoid” and “builder monad” style.
10In this style, we build up serialized data structures by `tell`ing to
11a `Writer` monad with `do`-notation. This style of serialization
12has been used for a long time and we [insist that it works really well](https://wiki.haskell.org/Do_notation_considered_harmful#Library_design).
14This package provides a `Builder` monoid and a `PutM` monad which are roughly
15equivalent to types of the same name in the Haskell
16[__Data.Binary.Put__](https://hackage.haskell.org/package/binary/docs/Data-Binary-Put.html)
17module.
19## Usage Examples
21All `ArrayBuffer` building must occur in `Effect`.
23### Serialize an integer
25Create a two-byte `arraybuffer :: ArrayBuffer` which contains the number *-10* encoded as big-endian 16-bit two’s-complement.
26```purescript
27import Data.ArrayBuffer.Builder (execPut, putInt16be)
29do
30 arraybuffer :: ArrayBuffer <- execPut $ putInt16be (-10)
31```
33### Serialize three floats
35Create a 24-byte `arraybuffer :: ArrayBuffer` which contains three big-endian
36IEEE-754 double-precision floats.
38```purescript
39import Data.ArrayBuffer.Builder (execPut, putFloat64be)
41do
42 arraybuffer :: ArrayBuffer <- execPut do
43 putFloat64be 1.0
44 putFloat64be 2.0
45 putFloat64be 3.0
46```
48### Serialize a `String` as UTF8
50Encode a `String` as UTF8 with a length prefix into our `Builder`.
52We give this as an example, rather than supporting it in the library, because
53it depends on
54[`Web.Encoding.TextEncoder`](https://pursuit.purescript.org/packages/purescript-web-encoding/docs/Web.Encoding.TextEncoder).
56```purescript
57import Effect.Class (class MonadEffect, liftEffect)
58import Data.UInt (fromInt)
59import Data.ArrayBuffer.Types (ArrayBuffer(..))
60import Data.ArrayBuffer.Builder (PutM, putArrayBuffer, execPut, putUint32be)
61import Data.ArrayBuffer.Typed (buffer)
62import Data.ArrayBuffer.ArrayBuffer (byteLength)
63import Web.Encoding.TextEncoder (new, TextEncoder, encode)
65putStringUtf8 :: forall m. MonadEffect m => String -> PutM m Unit
66putStringUtf8 s = do
67 textEncoder <- liftEffect new
68 let stringbuf = buffer $ encode s textEncoder
69 -- Put a 32-bit big-endian length for the utf8 string, in bytes.
70 putUint32be $ fromInt $ byteLength stringbuf
71 putArrayBuffer stringbuf
73arraybuffer :: ArrayBuffer <- execPut $ putStringUtf8 "🦝"
74```
76### Serialize an `Array Int`
78Encode an `Array Int` with a length prefix in a
79way that's compatible with the
80[`Binary` instance for `[Int32]`](https://hackage.haskell.org/package/binary/docs/Data-Binary.html#t:Binary)
81from the Haskell
82[__binary__](https://hackage.haskell.org/package/binary)
83library.
85```purescript
86import Data.ArrayBuffer.Builder (execPut, putInt32be)
87import Data.Foldable (traverse_)
88import Data.Array (length)
90putArrayInt32 :: forall m. MonadEffect m => Array Int -> PutM m Unit
91putArrayInt32 xs = do
92 -- Put a 64-bit big-endian length prefix for the array.
93 putInt32be 0
94 putInt32be $ length xs
95 traverse_ putInt32be xs
97do
98 arraybuffer <- execPut $ putArrayInt32 [1,2,3]
99```
101### Serialize an `Array Int` stack-safe
103Stack-safe version of the `putArrayInt32` function above. For stack-safety
104we use `foldRecM` instead of `traverse_` because `foldRecM` has a `MonadRec`
105constraint which makes it stack-safe.
107```purescript
108import Data.Array (foldRecM)
110putArrayInt32 :: forall m. MonadEffect m => MonadRec m => Array Int -> PutM m Unit
111putArrayInt32 xs = do
112 -- Put a 64-bit big-endian length prefix for the array.
113 putInt32be 0
114 putInt32be $ length xs
115 foldRecM (\_ x -> putInt32be x) unit xs
116```
118## Stack-safety
120This package will always be stack-safe if all of the functions called inside
121of the `PutM` builder expression are stack-safe.
123## Deserialization
125This package is only for writing `ArrayBuffer`s, not reading them.
126See
127[__parsing-dataview__](https://pursuit.purescript.org/packages/purescript-parsing-dataview/)
128for a way to deserialize from `ArrayBuffer` back to Purescript data.
130## Alternative packages for serializing to an `ArrayBuffer`
132* [__dynamic-buffers__](https://pursuit.purescript.org/packages/purescript-dynamic-buffers)
133* [__node-buffer__](https://pursuit.purescript.org/packages/purescript-node-buffer)
134* [__arraybuffer-class__](https://pursuit.purescript.org/packages/purescript-arraybuffer-class)
135* [__bytestrings__](https://pursuit.purescript.org/packages/purescript-bytestrings/)
136* [__array-builder__](https://pursuit.purescript.org/packages/purescript-array-builder)
138## Development
140To run the tests,
142```shell
143spago -x spago-dev.dhall test
144```