git.iko.soy/rowtype-yoga/purescript-arraybuffer-builder
on 8846714 help sign in
.github/workflows/ci.ymldeleted−46
since splitsnapshots
unifiedsplit
@@ -1,46 +0,0 @@
1−name: CI
2−
3−on:
4− push:
5− pull_request:
6−
7−jobs:
8− build:
9− runs-on: ubuntu-latest
10−
11− steps:
12− - uses: actions/checkout@v2
13−
14− - name: Set up a PureScript toolchain
15− uses: purescript-contrib/setup-purescript@main
16− with:
17− purescript: "unstable"
18− purs-tidy: "latest"
19−
20− - name: Cache PureScript dependencies
21− uses: actions/cache@v2
22− with:
23− key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }}-2
24− path: |
25− .spago
26− output
27− - name: Install dependencies
28− run: spago install
29−
30− - name: Build source
31− run: spago build --no-install --purs-args '--censor-lib --strict --censor-codes='UserDefinedWarning''
32−
33− - name: Install dev dependencies
34− run: spago -x spago-dev.dhall install
35−
36− - name: Run tests
37− run: spago -x spago-dev.dhall test --no-install
38−
39− - name: Check formatting
40− run: purs-tidy check src test bench
41−
42− - name: Verify Bower & Pulp
43− run: |
44− npm install bower pulp@16.0.0-0
45− npx bower install
46− npx pulp build -- --censor-lib --strict
.github/workflows/push-build.ymlnew file+42
@@ -0,0 +1,42 @@
1+name: CI
2+
3+on: [push]
4+
5+jobs:
6+ build:
7+
8+ runs-on: ubuntu-latest
9+
10+ # https://github.com/purescript-contrib/setup-purescript
11+
12+ steps:
13+ # https://github.com/cachix/install-nix-action
14+ - uses: actions/checkout@v2.3.4
15+ - uses: cachix/install-nix-action@v13
16+ with:
17+ nix_path: nixpkgs=channel:nixos-unstable
18+ - run: nix-shell --command 'spago --global-cache skip --config test.dhall test'
19+
20+ # https://github.com/purescript-contrib/setup-purescript
21+
22+ # - uses: actions/checkout@v2
23+ # - name: Set up a PureScript toolchain
24+ # uses: purescript-contrib/setup-purescript@main
25+ # with:
26+ # purescript: "0.14.1"
27+ # spago: "0.20.1"
28+
29+# - name: Cache PureScript dependencies
30+# uses: actions/cache@v2
31+# # This cache uses the .dhall files to know when it should reinstall
32+# # and rebuild packages. It caches both the installed packages from
33+# # the `.spago` directory and compilation artifacts from the `output`
34+# # directory. When restored the compiler will rebuild any files that
35+# # have changed. If you do not want to cache compiled output, remove
36+# # the `output` path.
37+# with:
38+# key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }}
39+# path: |
40+# .spago
41+
42+ # - run: spago -x test.dhall test
CHANGELOG.md−21
@@ -1,26 +1,5 @@
1# Changelog
1# Changelog
2
2
3−## v3.1.0 2022-12-10
4−
5−- Transfer to __rowtype-yoga__.
6−- Docs.
7−
8−## v3.0.1 2022-05-04
9−
10−CI repair. Change `test.dhall` to `spago-dev.dhall`.
11−
12−## v3.0.0 2022-05-04
13−
14−Build for PureScript v0.15.
15−
16−Added `MonadRec` constraint to `execPut`, `execPutM`, `foldl`, `foldM`,
17−they are now stack-safe.
18−
19−## v2.1.0 2021-07-22
20−
21−Renamed `Data.ArrayBuffer.Internal.Bytes` and exported
22−it as `Data.ArrayBuffer.DataBuff`.
23−
24## v2.0.0 2021-07-19
3## v2.0.0 2021-07-19
25
4
26Build for PureScript v0.14.
5Build for PureScript v0.14.
DEVELOPMENT.mdnew file+43
@@ -0,0 +1,43 @@
1+# Development Notes
2+
3+All of the commands needed for development are in the `shell.nix` environment.
4+
5+```
6+$ nix-shell
7+```
8+
9+## Edit
10+
11+The `psc-ide` command is available for the [VS Code Purescript IDE extension](https://github.com/nwolverson/vscode-ide-purescript.git).
12+
13+```
14+[nix-shell:]$ code .
15+```
16+
17+## Build
18+
19+```
20+[nix-shell:]$ spago build
21+```
22+
23+## Test
24+
25+The test dependencies are specified seperately in `test.dhall`.
26+
27+```
28+[nix-shell:]$ spago -x test.dhall test
29+```
30+
31+## Publishing to Pursuit with `spago`
32+
33+[Publishing with `spago`](https://github.com/purescript/spago#publish-my-library).
34+
35+```
36+[nix-shell:]$ bower install --save
37+[nix-shell:]$ spago bump-version --no-dry-run major
38+[nix-shell:]$ pulp publish --no-push
39+```
40+
41+## Bower
42+
43+The `bower.json` is generated by running `spago bump-version`, do not edit it.
README.md+43−50
@@ -1,21 +1,27 @@
1# purescript-arraybuffer-builder
1# purescript-arraybuffer-builder
2
2
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)
3+[![CI](https://github.com/jamesdbrock/purescript-arraybuffer-builder/workflows/CI/badge.svg?branch=master)](https://github.com/jamesdbrock/purescript-arraybuffer-builder/actions)
4[![Pursuit](http://pursuit.purescript.org/packages/purescript-arraybuffer-builder/badge)](http://pursuit.purescript.org/packages/purescript-arraybuffer-builder/)
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)
6
5
7−
8−[`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)
9−serialization in the “builder monoid” and “builder monad” style.
6+`ArrayBuffer` serialization in the “builder monoid” and “builder monad” style.
10−In this style, we build up serialized data structures by `tell`ing to
7+In this style, we build up serialized data structures by `append`ing to
11−a `Writer` monad with `do`-notation. This style of serialization
8+a monoid in a 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).
9has been used for a long time and we [insist that it works really well](https://wiki.haskell.org/Do_notation_considered_harmful#Library_design).
13
10
14This package provides a `Builder` monoid and a `PutM` monad which are roughly
11This package provides a `Builder` monoid and a `PutM` monad which are roughly
15equivalent to types of the same name in the Haskell
12equivalent to types of the same name in the Haskell
16−[__Data.Binary.Put__](https://hackage.haskell.org/package/binary/docs/Data-Binary-Put.html)
13+[`Data.Binary.Put`](https://hackage.haskell.org/package/binary/docs/Data-Binary-Put.html)
17module.
14module.
18
15
16+This package defines
17+[no typeclasses](http://code.slipthrough.net/2018/03/13/thoughts-on-typeclass-codecs/).
18+Typeclass-based
19+serialization/deserialization generally assumes that we are round-tripping
20+some data structures out to storage and then back into our program.
21+This package is designed for the case in which we are serializing some data
22+to be sent to another program which expects a serialization format
23+that we don't control.
24+
19## Usage Examples
25## Usage Examples
20
26
21All `ArrayBuffer` building must occur in `Effect`.
27All `ArrayBuffer` building must occur in `Effect`.
@@ -39,7 +45,7 @@ IEEE-754 double-precision floats.
39import Data.ArrayBuffer.Builder (execPut, putFloat64be)
45import Data.ArrayBuffer.Builder (execPut, putFloat64be)
40
46
41do
47do
42− arraybuffer :: ArrayBuffer <- execPut do
48+ arraybuffer :: ArrayBuffer <- execPut $ do
43 putFloat64be 1.0
49 putFloat64be 1.0
44 putFloat64be 2.0
50 putFloat64be 2.0
45 putFloat64be 3.0
51 putFloat64be 3.0
@@ -51,26 +57,23 @@ Encode a `String` as UTF8 with a length prefix into our `Builder`.
51
57
52We give this as an example, rather than supporting it in the library, because
58We give this as an example, rather than supporting it in the library, because
53it depends on
59it depends on
54−[`Web.Encoding.TextEncoder`](https://pursuit.purescript.org/packages/purescript-web-encoding/docs/Web.Encoding.TextEncoder).
60+[`Data.TextEncoding.encodeUtf8`](https://pursuit.purescript.org/packages/purescript-text-encoding/docs/Data.TextEncoding#v:encodeUtf8).
55
61
56```purescript
62```purescript
57−import Effect.Class (class MonadEffect, liftEffect)
58−import Data.UInt (fromInt)
59−import Data.ArrayBuffer.Types (ArrayBuffer(..))
60−import Data.ArrayBuffer.Builder (PutM, putArrayBuffer, execPut, putUint32be)
63+import Data.ArrayBuffer.Builder (PutM, putArrayBuffer, execPut)
61import Data.ArrayBuffer.Typed (buffer)
64import Data.ArrayBuffer.Typed (buffer)
65+import Data.TextEncoding (encodeUtf8)
62import Data.ArrayBuffer.ArrayBuffer (byteLength)
66import Data.ArrayBuffer.ArrayBuffer (byteLength)
63−import Web.Encoding.TextEncoder (new, TextEncoder, encode)
64
67
65−putStringUtf8 :: forall m. MonadEffect m => String -> PutM m Unit
68+putStringUtf8 :: forall m. (MonadEffect m) => String -> PutM m Unit
66putStringUtf8 s = do
69putStringUtf8 s = do
67− textEncoder <- liftEffect new
68− let stringbuf = buffer $ encode s textEncoder
70+ let stringbuf = buffer $ encodeUtf8 s
69− -- Put a 32-bit big-endian length for the utf8 string, in bytes.
71+ -- Put a 32-bit big-endian length prefix for the length of the utf8 string, in bytes.
70− putUint32be $ fromInt $ byteLength stringbuf
72+ putInt32be $ byteLength stringbuf
71 putArrayBuffer stringbuf
73 putArrayBuffer stringbuf
72
74
75+do
73−arraybuffer :: ArrayBuffer <- execPut $ putStringUtf8 "🦝"
76+ arraybuffer :: ArrayBuffer <- execPut $ putStringUtf8 "BLM"
74```
77```
75
78
76### Serialize an `Array Int`
79### Serialize an `Array Int`
@@ -87,9 +90,9 @@ import Data.ArrayBuffer.Builder (execPut, putInt32be)
87import Data.Foldable (traverse_)
90import Data.Foldable (traverse_)
88import Data.Array (length)
91import Data.Array (length)
89
92
90−putArrayInt32 :: forall m. MonadEffect m => Array Int -> PutM m Unit
93+putArrayInt32 :: forall m. (MonadEffect m) => Array Int -> PutM m Unit
91putArrayInt32 xs = do
94putArrayInt32 xs = do
92− -- Put a 64-bit big-endian length prefix for the array.
95+ -- Put a 64-bit big-endian length prefix for the length of the array.
93 putInt32be 0
96 putInt32be 0
94 putInt32be $ length xs
97 putInt32be $ length xs
95 traverse_ putInt32be xs
98 traverse_ putInt32be xs
@@ -98,47 +101,37 @@ do
98 arraybuffer <- execPut $ putArrayInt32 [1,2,3]
101 arraybuffer <- execPut $ putArrayInt32 [1,2,3]
99```
102```
100
103
101−### Serialize an `Array Int` stack-safe
102
104
103−Stack-safe version of the `putArrayInt32` function above. For stack-safety
105+## `unsafePerformEffect execPut`
104−we use `foldRecM` instead of `traverse_` because `foldRecM` has a `MonadRec`
105−constraint which makes it stack-safe.
106
106
107−```purescript
107+Dear computer programmer, you can call `execPut` inside `unsafePerformEffect`.
108−import Data.Array (foldRecM)
109
108
110−putArrayInt32 :: forall m. MonadEffect m => MonadRec m => Array Int -> PutM m Unit
109+The reason why this whole library is `Effect`ful is that `ArrayBuffer`s are mutable, so the `ArrayBuffer` library functions do everything in `Effect` to to confirm that any mutations are properly sequenced.
111−putArrayInt32 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−```
117
110
118−## Stack-safety
111+However, all of the `put` functions in this library are actually side-effect free, so we can use `unsafePerformEffect` to tell the compiler to trust us that we don't perform any side-effects while we're building an `ArrayBuffer`.
119
112
120−This package will always be stack-safe if all of the functions called inside
113+```purescript
121−of the `PutM` builder expression are stack-safe.
114+let serialized :: ArrayBuffer
115+ serialized = unsafePerformEffect $ execPut do
116+ putInt32be 3 -- ✅ Good, this has no side-effects
117+ putInt32be =<< getCurrentPosixTime -- ❌ No don't do this
118+ putArrayBuffer =<< readFileFromMyFilesystem -- ❌ No don’t do this either
119+```
122
120
123## Deserialization
121## Deserialization
124
122
125This package is only for writing `ArrayBuffer`s, not reading them.
123This package is only for writing `ArrayBuffer`s, not reading them.
126See
124See
127−[__parsing-dataview__](https://pursuit.purescript.org/packages/purescript-parsing-dataview/)
125+[__purescript-parsing-dataview__](https://pursuit.purescript.org/packages/purescript-parsing-dataview/)
128for a way to deserialize from `ArrayBuffer` back to Purescript data.
126for a way to deserialize from `ArrayBuffer` back to Purescript data.
129
127
128+## References
129+
130+* [MDN `ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)
131+
130## Alternative packages for serializing to an `ArrayBuffer`
132## Alternative packages for serializing to an `ArrayBuffer`
131
133
132* [__dynamic-buffers__](https://pursuit.purescript.org/packages/purescript-dynamic-buffers)
134* [__dynamic-buffers__](https://pursuit.purescript.org/packages/purescript-dynamic-buffers)
133* [__node-buffer__](https://pursuit.purescript.org/packages/purescript-node-buffer)
135* [__node-buffer__](https://pursuit.purescript.org/packages/purescript-node-buffer)
134* [__arraybuffer-class__](https://pursuit.purescript.org/packages/purescript-arraybuffer-class)
136* [__arraybuffer-class__](https://pursuit.purescript.org/packages/purescript-arraybuffer-class)
135−* [__bytestrings__](https://pursuit.purescript.org/packages/purescript-bytestrings/)
137+* [__bytestrings__](https://pursuit.purescript.org/packages/purescript-bytestrings/)
136−* [__array-builder__](https://pursuit.purescript.org/packages/purescript-array-builder)
137−
138−## Development
139−
140−To run the tests,
141−
142−```shell
143−spago -x spago-dev.dhall test
144−```
bower.json+34−12
@@ -14,17 +14,39 @@
14 "output"
14 "output"
15 ],
15 ],
16 "dependencies": {
16 "dependencies": {
17− "purescript-arraybuffer": "^v13.1.1",
17+ "purescript-arraybuffer": "^v8.0.3",
18− "purescript-arraybuffer-types": "^v3.0.2",
18+ "purescript-arraybuffer-types": "^v3.0.0",
19+ "purescript-effect": "^v3.0.0",
20+ "purescript-float32": "^v0.2.0",
21+ "purescript-maybe": "^v5.0.0",
22+ "purescript-prelude": "^v5.0.0",
19− "purescript-effect": "^v4.0.0",
23+ "purescript-transformers": "^v5.0.0",
20− "purescript-float32": "^v2.0.0",
24+ "purescript-uint": "^v5.1.4"
25+ },
26+ "resolutions": {
27+ "purescript-effect": "^v3.0.0",
28+ "purescript-arraybuffer-types": "^v3.0.0",
29+ "purescript-prelude": "^v5.0.0",
30+ "purescript-transformers": "^v5.0.0",
31+ "purescript-maybe": "^v5.0.0",
32+ "purescript-float32": "^v0.2.0",
33+ "purescript-partial": "^3.0.0",
34+ "purescript-control": "^5.0.0",
35+ "purescript-lazy": "^5.0.0",
36+ "purescript-distributive": "^5.0.0",
37+ "purescript-either": "^5.0.0",
38+ "purescript-exceptions": "^5.0.0",
39+ "purescript-foldable-traversable": "^5.0.0",
40+ "purescript-tuples": "^6.0.0",
21− "purescript-identity": "^v6.0.0",
41+ "purescript-identity": "^5.0.0",
22− "purescript-lists": "^v7.0.0",
42+ "purescript-tailrec": "^5.0.0",
23− "purescript-maybe": "^v6.0.0",
24− "purescript-newtype": "^v5.0.0",
43+ "purescript-newtype": "^4.0.0",
44+ "purescript-unfoldable": "^5.0.0",
45+ "purescript-unsafe-coerce": "^5.0.0",
46+ "purescript-invariant": "^5.0.0",
25− "purescript-prelude": "^v6.0.1",
47+ "purescript-bifunctors": "^5.0.0",
26− "purescript-tailrec": "^v6.1.0",
48+ "purescript-orders": "^5.0.0",
27− "purescript-transformers": "^v6.0.0",
49+ "purescript-type-equality": "^4.0.0",
28− "purescript-uint": "^v7.0.0"
50+ "purescript-refs": "^5.0.0"
29 }
51 }
30}
52}
packages.dhall+47−3
@@ -116,12 +116,56 @@ let additions =
116 }
116 }
117-------------------------------
117-------------------------------
118-}
118-}
119+
119let upstream =
120let upstream =
120− https://raw.githubusercontent.com/purescript/package-sets/psc-0.15.4-20221209/src/packages.dhall
121+ https://github.com/purescript/package-sets/releases/download/psc-0.14.1-20210427/packages.dhall sha256:edbb8f70232fb83895c7ce02f5d2b29f6ee1722f1a70fc58d3bc0ab0de18afe4
121− sha256:b55c24bf585df4041ae6e87124cab7b35d474a9a77c9c3862ee6bf1dae618d72
122
122
123let overrides = {=}
123let overrides = {=}
124
124
125+-- TODO Remove all of these additions when they are in package-sets for
126+-- Purescript v0.14.
125−let additions = {=}
127+let additions =
128+ { arraybuffer =
129+ { dependencies =
130+ [ "effect"
131+ , "arraybuffer-types"
132+ , "maybe"
133+ , "typelevel"
134+ , "uint"
135+ , "float32"
136+ , "partial"
137+ , "nullable"
138+ , "functions"
139+ ]
140+ , repo =
141+ "https://github.com/jacereda/purescript-arraybuffer.git"
142+ , version =
143+ "v8.0.3"
144+ }
145+ , float32 =
146+ { dependencies =
147+ [ "prelude"
148+ ]
149+ , repo =
150+ "https://github.com/athanclark/purescript-float32.git"
151+ , version =
152+ "v0.2.0"
153+ }
154+ , uint =
155+ { dependencies =
156+ [ "effect"
157+ , "quickcheck-laws"
158+ , "console"
159+ , "maybe"
160+ , "math"
161+ , "psci-support"
162+ , "quickcheck"
163+ ]
164+ , repo =
165+ "https://github.com/zaquest/purescript-uint.git"
166+ , version =
167+ "v5.1.4"
168+ }
169+ }
126
170
127in upstream // overrides // additions
171in upstream // overrides // additions
psc-package.jsonnew file+16
@@ -0,0 +1,16 @@
1+{
2+ "name": "purescript-arraybuffer-builder",
3+ "set": "psc-0.14.1-20210429",
4+ "source": "https://github.com/purescript/package-sets.git",
5+ "depends": [
6+ "prelude",
7+ "effect",
8+ "float32",
9+ "maybe",
10+ "prelude",
11+ "transformers",
12+ "uint",
13+ "arraybuffer-types",
14+ "arraybuffer"
15+ ]
16+}
shell.nixnew file+21
@@ -0,0 +1,21 @@
1+{ pkgs ? import <nixpkgs> { } }:
2+let
3+ easy-ps = import (builtins.fetchGit {
4+ # url = "git@github.com:justinwoo/easy-purescript-nix.git";
5+ url = "https://github.com/justinwoo/easy-purescript-nix.git";
6+ ref = "master";
7+ rev = "dae91f43317fd5ff207e11ea6bf4b6130e4ba9fc";
8+ }) { inherit pkgs; };
9+in
10+pkgs.mkShell {
11+ buildInputs = [
12+ easy-ps.purs-0_14_1
13+ easy-ps.spago
14+ easy-ps.pulp
15+ easy-ps.psc-package
16+ # easy-ps.psc-publish
17+ pkgs.nodejs-14_x
18+ pkgs.nodePackages.bower
19+ ];
20+ LC_ALL = "C.UTF-8"; # https://github.com/purescript/spago/issues/507
21+}
spago.dhall−4
@@ -4,16 +4,12 @@
4, dependencies =
4, dependencies =
5 [ "effect"
5 [ "effect"
6 , "float32"
6 , "float32"
7− , "identity"
8− , "lists"
9 , "maybe"
7 , "maybe"
10− , "newtype"
11 , "prelude"
8 , "prelude"
12 , "transformers"
9 , "transformers"
13 , "uint"
10 , "uint"
14 , "arraybuffer-types"
11 , "arraybuffer-types"
15 , "arraybuffer"
12 , "arraybuffer"
16− , "tailrec"
17 ]
13 ]
18, packages = ./packages.dhall
14, packages = ./packages.dhall
19, sources = [ "src/**/*.purs" ]
15, sources = [ "src/**/*.purs" ]
src/Data/ArrayBuffer/Builder.purs+56−55
@@ -5,42 +5,47 @@
5-- | Writing to an `ArrayBuffer` is an `Effect`ful activity, so most
5-- | Writing to an `ArrayBuffer` is an `Effect`ful activity, so most
6-- | functions in this module must be run in a `MonadEffect` context.
6-- | functions in this module must be run in a `MonadEffect` context.
7-- |
7-- |
8−-- | For other operations for working with `ArrayBuffer`, see
8+-- | For operations for working with `ArrayBuffer`, see
9-- | module
9-- | module
10-- | [`Data.ArrayBuffer.ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.ArrayBuffer)
10-- | [`Data.ArrayBuffer.ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.ArrayBuffer)
11−-- | in package __arraybuffer__.
11+-- | in package __purescript-arraybuffer__.
12module Data.ArrayBuffer.Builder
12module Data.ArrayBuffer.Builder
13− ( PutM
13+( PutM
14− , Put
14+, Put
15− , execPutM
15+, execPutM
16− , execPut
16+, execPut
17− , subBuilder
17+, subBuilder
18− , putArrayBuffer
18+, putArrayBuffer
19− , putDataView
19+, putDataView
20− , putDataBuff
21− , putUint8
20+, putUint8
22− , putInt8
21+, putInt8
23− , putUint16be
22+, putUint16be
24− , putUint16le
23+, putUint16le
25− , putInt16be
24+, putInt16be
26− , putInt16le
25+, putInt16le
27− , putUint32be
26+, putUint32be
28− , putUint32le
27+, putUint32le
29− , putInt32be
28+, putInt32be
30− , putInt32le
29+, putInt32le
31− , putFloat32be
30+, putFloat32be
32− , putFloat32le
31+, putFloat32le
33− , putFloat64be
32+, putFloat64be
34− , putFloat64le
33+, putFloat64le
35− , module Data.ArrayBuffer.Builder.Internal
34+, module Data.ArrayBuffer.Builder.Internal
35+)
36− ) where
36+where
37+
38+import Data.ArrayBuffer.Builder.Internal
39+ ( Builder
40+ , (<>>)
41+ , length
42+ )
43+
44+import Data.ArrayBuffer.Builder.Internal as Internal
37
45
38import Prelude
46import Prelude
39
47
40−import Control.Monad.Rec.Class (class MonadRec)
41import Control.Monad.Writer.Trans (WriterT, execWriterT, tell, lift)
48import Control.Monad.Writer.Trans (WriterT, execWriterT, tell, lift)
42−import Data.ArrayBuffer.Builder.Internal (Builder, DataBuff(..), length, toView, (<>>))
43−import Data.ArrayBuffer.Builder.Internal as Internal
44import Data.ArrayBuffer.Types (ArrayBuffer, DataView)
49import Data.ArrayBuffer.Types (ArrayBuffer, DataView)
45import Data.Float32 (Float32)
50import Data.Float32 (Float32)
46import Data.UInt (UInt)
51import Data.UInt (UInt)
@@ -58,11 +63,11 @@ type PutM = WriterT Builder
58-- | The `PutM` type reified to `Effect`, in other words `WriterT Builder Effect`.
63-- | The `PutM` type reified to `Effect`, in other words `WriterT Builder Effect`.
59type Put = PutM Effect
64type Put = PutM Effect
60
65
61−-- | Build an `ArrayBuffer` with do-notation in any `MonadEffect`. *O(n)* Stack-safe.
66+-- | Build an `ArrayBuffer` with do-notation in any `MonadEffect`. *O(n)*
62−execPutM :: forall m. MonadEffect m => MonadRec m => PutM m Unit -> m ArrayBuffer
67+execPutM :: forall m. (MonadEffect m) => PutM m Unit -> m ArrayBuffer
63execPutM = Internal.execBuilder <=< execWriterT
68execPutM = Internal.execBuilder <=< execWriterT
64
69
65−-- | Build an `ArrayBuffer` with do-notation in `Effect`. *O(n)* Stack-safe.
70+-- | Build an `ArrayBuffer` with do-notation in `Effect`. *O(n)*
66execPut :: Put Unit -> Effect ArrayBuffer
71execPut :: Put Unit -> Effect ArrayBuffer
67execPut = execPutM
72execPut = execPutM
68
73
@@ -84,73 +89,69 @@ execPut = execPutM
84-- | putInt32be $ length messageBuilder
89-- | putInt32be $ length messageBuilder
85-- | tell messageBuilder
90-- | tell messageBuilder
86-- | ```
91-- | ```
87−subBuilder :: forall m. Monad m => PutM m Unit -> PutM m Builder
92+subBuilder :: forall m. (MonadEffect m) => PutM m Unit -> PutM m Builder
88subBuilder = lift <<< execWriterT
93subBuilder = lift <<< execWriterT
89
94
90-- | Append an `ArrayBuffer` to the builder.
95-- | Append an `ArrayBuffer` to the builder.
91−putArrayBuffer :: forall m. Monad m => ArrayBuffer -> PutM m Unit
96+putArrayBuffer :: forall m. (MonadEffect m) => ArrayBuffer -> PutM m Unit
92−putArrayBuffer = tell <<< Internal.singleton <<< Internal.Buff
97+putArrayBuffer = tell <<< Internal.singleton
93
98
94-- | Append a `DataView` to the builder.
99-- | Append a `DataView` to the builder.
95−putDataView :: forall m. Monad m => DataView -> PutM m Unit
100+putDataView :: forall m. (MonadEffect m) => DataView -> PutM m Unit
96−putDataView = tell <<< Internal.singleton <<< Internal.View
101+putDataView = tell <<< Internal.singleton_
97−
98−-- | Append either an `ArrayBuffer` or a `DataView` to the builder.
99−putDataBuff :: forall m. Monad m => DataBuff -> PutM m Unit
100−putDataBuff = tell <<< Internal.singleton
101
102
102-- | Append an 8-bit unsigned integer (byte) to the builder.
103-- | Append an 8-bit unsigned integer (byte) to the builder.
103−putUint8 :: forall m. MonadEffect m => UInt -> PutM m Unit
104+putUint8 :: forall m. (MonadEffect m) => UInt -> PutM m Unit
104putUint8 = putArrayBuffer <=< Internal.encodeUint8
105putUint8 = putArrayBuffer <=< Internal.encodeUint8
105
106
106-- | Append an 8-bit two’s-complement signed integer (char) to the builder.
107-- | Append an 8-bit two’s-complement signed integer (char) to the builder.
107−putInt8 :: forall m. MonadEffect m => Int -> PutM m Unit
108+putInt8 :: forall m. (MonadEffect m) => Int -> PutM m Unit
108putInt8 = putArrayBuffer <=< Internal.encodeInt8
109putInt8 = putArrayBuffer <=< Internal.encodeInt8
109
110
110-- | Append a 16-bit big-endian unsigned integer to the builder.
111-- | Append a 16-bit big-endian unsigned integer to the builder.
111−putUint16be :: forall m. MonadEffect m => UInt -> PutM m Unit
112+putUint16be :: forall m. (MonadEffect m) => UInt -> PutM m Unit
112putUint16be = putArrayBuffer <=< Internal.encodeUint16be
113putUint16be = putArrayBuffer <=< Internal.encodeUint16be
113
114
114-- | Append a 16-bit little-endian unsigned integer to the builder.
115-- | Append a 16-bit little-endian unsigned integer to the builder.
115−putUint16le :: forall m. MonadEffect m => UInt -> PutM m Unit
116+putUint16le :: forall m. (MonadEffect m) => UInt -> PutM m Unit
116putUint16le = putArrayBuffer <=< Internal.encodeUint16le
117putUint16le = putArrayBuffer <=< Internal.encodeUint16le
117
118
118-- | Append a 16-bit big-endian two’s-complement signed integer to the builder.
119-- | Append a 16-bit big-endian two’s-complement signed integer to the builder.
119−putInt16be :: forall m. MonadEffect m => Int -> PutM m Unit
120+putInt16be :: forall m. (MonadEffect m) => Int -> PutM m Unit
120putInt16be = putArrayBuffer <=< Internal.encodeInt16be
121putInt16be = putArrayBuffer <=< Internal.encodeInt16be
121
122
122-- | Append a 16-bit little-endian two’s-complement signed integer to the builder.
123-- | Append a 16-bit little-endian two’s-complement signed integer to the builder.
123−putInt16le :: forall m. MonadEffect m => Int -> PutM m Unit
124+putInt16le :: forall m. (MonadEffect m) => Int -> PutM m Unit
124putInt16le = putArrayBuffer <=< Internal.encodeInt16le
125putInt16le = putArrayBuffer <=< Internal.encodeInt16le
125
126
126-- | Append a 32-bit big-endian unsigned integer to the builder.
127-- | Append a 32-bit big-endian unsigned integer to the builder.
127−putUint32be :: forall m. MonadEffect m => UInt -> PutM m Unit
128+putUint32be :: forall m. (MonadEffect m) => UInt -> PutM m Unit
128putUint32be = putArrayBuffer <=< Internal.encodeUint32be
129putUint32be = putArrayBuffer <=< Internal.encodeUint32be
129
130
130-- | Append a 32-bit little-endian unsigned integer to the builder.
131-- | Append a 32-bit little-endian unsigned integer to the builder.
131−putUint32le :: forall m. MonadEffect m => UInt -> PutM m Unit
132+putUint32le :: forall m. (MonadEffect m) => UInt -> PutM m Unit
132putUint32le = putArrayBuffer <=< Internal.encodeUint32le
133putUint32le = putArrayBuffer <=< Internal.encodeUint32le
133
134
134-- | Append a 32-bit big-endian two’s-complement signed integer to the builder.
135-- | Append a 32-bit big-endian two’s-complement signed integer to the builder.
135−putInt32be :: forall m. MonadEffect m => Int -> PutM m Unit
136+putInt32be :: forall m. (MonadEffect m) => Int -> PutM m Unit
136putInt32be = putArrayBuffer <=< Internal.encodeInt32be
137putInt32be = putArrayBuffer <=< Internal.encodeInt32be
137
138
138-- | Append a 32-bit little-endian two’s-complement signed integer to the builder.
139-- | Append a 32-bit little-endian two’s-complement signed integer to the builder.
139−putInt32le :: forall m. MonadEffect m => Int -> PutM m Unit
140+putInt32le :: forall m. (MonadEffect m) => Int -> PutM m Unit
140putInt32le = putArrayBuffer <=< Internal.encodeInt32le
141putInt32le = putArrayBuffer <=< Internal.encodeInt32le
141
142
142-- | Append a 32-bit big-endian IEEE single-precision float to the builder.
143-- | Append a 32-bit big-endian IEEE single-precision float to the builder.
143−putFloat32be :: forall m. MonadEffect m => Float32 -> PutM m Unit
144+putFloat32be :: forall m. (MonadEffect m) => Float32 -> PutM m Unit
144putFloat32be = putArrayBuffer <=< Internal.encodeFloat32be
145putFloat32be = putArrayBuffer <=< Internal.encodeFloat32be
145
146
146-- | Append a 32-bit little-endian IEEE single-precision float to the builder.
147-- | Append a 32-bit little-endian IEEE single-precision float to the builder.
147−putFloat32le :: forall m. MonadEffect m => Float32 -> PutM m Unit
148+putFloat32le :: forall m. (MonadEffect m) => Float32 -> PutM m Unit
148putFloat32le = putArrayBuffer <=< Internal.encodeFloat32le
149putFloat32le = putArrayBuffer <=< Internal.encodeFloat32le
149
150
150-- | Append a 64-bit big-endian IEEE double-precision float to the builder.
151-- | Append a 64-bit big-endian IEEE double-precision float to the builder.
151−putFloat64be :: forall m. MonadEffect m => Number -> PutM m Unit
152+putFloat64be :: forall m. (MonadEffect m) => Number -> PutM m Unit
152putFloat64be = putArrayBuffer <=< Internal.encodeFloat64be
153putFloat64be = putArrayBuffer <=< Internal.encodeFloat64be
153
154
154-- | Append a 64-bit little-endian IEEE double-precision float to the builder.
155-- | Append a 64-bit little-endian IEEE double-precision float to the builder.
155−putFloat64le :: forall m. MonadEffect m => Number -> PutM m Unit
156+putFloat64le :: forall m. (MonadEffect m) => Number -> PutM m Unit
156putFloat64le = putArrayBuffer <=< Internal.encodeFloat64le
157putFloat64le = putArrayBuffer <=< Internal.encodeFloat64le
src/Data/ArrayBuffer/Internal.purs+96−97
@@ -2,7 +2,7 @@
2-- |
2-- |
3-- | You probably don’t want to import anything from this module.
3-- | You probably don’t want to import anything from this module.
4-- |
4-- |
5−-- | ## Implementation Details
5+-- | # Implementation Details
6-- |
6-- |
7-- | We want our `Builder` to be a data structure with
7-- | We want our `Builder` to be a data structure with
8-- | * *O(1)* monoid append
8-- | * *O(1)* monoid append
@@ -57,20 +57,19 @@
57-- | __bytestring-tree-builder__
57-- | __bytestring-tree-builder__
58-- | which “according to the benchmarks … beats all the alternatives.”
58-- | which “according to the benchmarks … beats all the alternatives.”
59-- | However, we
59-- | However, we
60−-- | haven’t chosen this implementation because it’s fast, we've chosen
60+-- | haven't chosen this implementation because it's fast, we've chosen
61−-- | this implementation because it’s simple.
61+-- | this implementation because it's simple.
62−-- | If someone wants to create a fast PureScript `ArrayBuffer` serialization
62+-- | If someone wants to create a fast PureScript ArrayBuffer serialization
63-- | library, then they can benchmark against this one to prove that the new
63-- | library, then they can benchmark against this one to prove that the new
64-- | one is fast.
64-- | one is fast.
65-- |
65-- |
66-- | One relatively cheap and simple performance improvement for this library would be to
66-- | One relatively cheap and simple performance improvement for this library would be to
67−-- | remove the `Null` constructor of `Builder` and instead use Javascript nulls?
67+-- | remove the Null constructor of `Builder` and instead use Javascript nulls.
68+-- | __UPDATE__ Actually no, we need the Null constructor for the Monoid instance.
68-- |
69-- |
69-- | In the longer term, it might make sense to try to change the `Builder` so
70-- | In the longer term, it might make sense to try to change the `Builder` so
70-- | that it works like the
71-- | that it works like the
71−-- | https://hackage.haskell.org/package/bytestring/docs/Data-ByteString-Builder.html .
72+-- | https://hackage.haskell.org/package/bytestring/docs/Data-ByteString-Builder.html
72−-- | That’s the approach taken by
73−-- | https://pursuit.purescript.org/packages/purescript-dynamic-buffers .
74-- |
73-- |
75-- | Here are some benchmarks of different Haskell ByteString builders
74-- | Here are some benchmarks of different Haskell ByteString builders
76-- | https://github.com/haskell-perf/strict-bytestring-builders
75-- | https://github.com/haskell-perf/strict-bytestring-builders
@@ -78,63 +77,56 @@
78-- | We've tried to design the API for this library with minimal assumptions,
77-- | We've tried to design the API for this library with minimal assumptions,
79-- | so that if we want to change the `Builder` implementation later then we can.
78-- | so that if we want to change the `Builder` implementation later then we can.
80-- |
79-- |
80+-- | Another way this could go:
81+-- | https://kodimensional.dev/posts/2019-03-25-comonadic-builders
82+-- |
83+-- | Our convention is that functions which add `DataView`s to
84+-- | the `Builder` are suffixed with underscore (`_`).
85+-- |
81module Data.ArrayBuffer.Builder.Internal
86module Data.ArrayBuffer.Builder.Internal
82− ( Builder(..)
87+( Builder(..)
83− , (<>>)
88+, (<>>)
84− , DataBuff(..)
89+, Bytes(..)
85− , toView
90+, toView
86− , execBuilder
91+, execBuilder
87− , length
92+, length
88− , foldl
93+, foldl
89− , foldM
94+, foldM
90− , singleton
95+, singleton
96+, singleton_
91− , cons
97+, cons
98+, cons_
92− , snoc
99+, snoc
100+, snoc_
93− , encodeUint8
101+, encodeUint8
94− , encodeInt8
102+, encodeInt8
95− , encodeUint16be
103+, encodeUint16be
96− , encodeUint16le
104+, encodeUint16le
97− , encodeInt16be
105+, encodeInt16be
98− , encodeInt16le
106+, encodeInt16le
99− , encodeUint32be
107+, encodeUint32be
100− , encodeUint32le
108+, encodeUint32le
101− , encodeInt32be
109+, encodeInt32be
102− , encodeInt32le
110+, encodeInt32le
103− , encodeFloat32be
111+, encodeFloat32be
104− , encodeFloat32le
112+, encodeFloat32le
105− , encodeFloat64be
113+, encodeFloat64be
106− , encodeFloat64le
114+, encodeFloat64le
115+)
107− ) where
116+where
108
117
109import Prelude
118import Prelude
110
119
111−import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM)
112import Data.ArrayBuffer.ArrayBuffer as AB
120import Data.ArrayBuffer.ArrayBuffer as AB
113import Data.ArrayBuffer.DataView as DV
121import Data.ArrayBuffer.DataView as DV
114import Data.ArrayBuffer.Typed as AT
122import Data.ArrayBuffer.Typed as AT
115import Data.ArrayBuffer.Types (ArrayBuffer, ByteLength, DataView, Uint8Array)
123import Data.ArrayBuffer.Types (ArrayBuffer, ByteLength, DataView, Uint8Array)
116import Data.Float32 (Float32)
124import Data.Float32 (Float32)
117−import Data.Identity (Identity)
118−import Data.List (List(..), uncons, (:))
119import Data.Maybe (Maybe(..))
125import Data.Maybe (Maybe(..))
120−import Data.Newtype (unwrap)
121import Data.UInt (UInt)
126import Data.UInt (UInt)
122import Effect (Effect)
127import Effect (Effect)
123import Effect.Class (class MonadEffect, liftEffect)
128import Effect.Class (class MonadEffect, liftEffect)
124
129
125−-- | For distinguishing between `ArrayBuffer` and `DataView`.
126−data DataBuff
127− = Buff ArrayBuffer
128− | View DataView
129−
130−-- Concerning DataViews.
131−-- https://v8.dev/blog/dataview
132−
133−-- | View the contents of `DataBuff` as a `DataView`.
134−toView :: DataBuff -> DataView
135−toView (Buff ab) = DV.whole ab
136−toView (View dv) = dv
137−
138-- | Monoidal builder for `ArrayBuffer`s.
130-- | Monoidal builder for `ArrayBuffer`s.
139-- |
131-- |
140-- | We can add two types of things to the `Builder`:
132-- | We can add two types of things to the `Builder`:
@@ -146,7 +138,7 @@ toView (View dv) = dv
146-- | from some other `ArrayBuffer`, so that we don’t
138-- | from some other `ArrayBuffer`, so that we don’t
147-- | need an extra intermediate copy of the slice.
139-- | need an extra intermediate copy of the slice.
148data Builder
140data Builder
149− = Node Builder DataBuff Builder
141+ = Node Builder Bytes Builder
150 | Null
142 | Null
151
143
152-- | ### Left-associative `<>>` append operator
144-- | ### Left-associative `<>>` append operator
@@ -190,62 +182,71 @@ instance semigroupBuilder :: Semigroup Builder where
190 append Null r = r
182 append Null r = r
191 append l (Node Null rx rr) = Node l rx rr -- this is the snoc case
183 append l (Node Null rx rr) = Node l rx rr -- this is the snoc case
192 append (Node ll lx Null) r = Node ll lx r -- found the rightmost Null
184 append (Node ll lx Null) r = Node ll lx r -- found the rightmost Null
193− -- of the left tree
185+ -- of the left tree
194 append (Node ll lx lr) r = Node ll lx $ append lr r -- search down the right
186 append (Node ll lx lr) r = Node ll lx $ append lr r -- search down the right
195−
196−-- side of the left tree
187+ -- side of the left tree
197−-- to find the rightmost
188+ -- to find the rightmost
198−-- Null
189+ -- Null
199
190
200infixl 5 append as <>>
191infixl 5 append as <>>
201
192
202instance monoidBuilder :: Monoid Builder where
193instance monoidBuilder :: Monoid Builder where
203 mempty = Null
194 mempty = Null
204
195
205−-- | Stack-safe `foldl` over a `Builder`. *O(n)*
196+-- | For distinguishing between `ArrayBuffer` and `DataView`.
197+data Bytes
198+ = ByteBuff ArrayBuffer
199+ | ByteView DataView
200+
201+-- | `Builder` is not an instance of `Foldable` because `Builder` is monomorphic.
206−foldl :: forall a. (a -> DataBuff -> a) -> a -> Builder -> a
202+foldl :: forall b. (b -> Bytes -> b) -> b -> Builder -> b
207−foldl f a0 b = (unwrap :: Identity a -> a) $ foldM (\a' b' -> pure (f a' b')) a0 b
203+foldl _ a Null = a
204+foldl f a (Node l x r) = foldl f (f (foldl f a l) x) r
208
205
209−-- | Stack-safe `foldM` over a `Builder`. *O(n)*.
206+-- | Monomorphic foldM copied from
210−foldM :: forall m a. MonadRec m => (a -> DataBuff -> m a) -> a -> Builder -> m a
207+-- | [`Data.Foldable.foldM`](https://pursuit.purescript.org/packages/purescript-foldable-traversable/4.1.1/docs/Data.Foldable#v:foldM)
211−-- The Art of Computer Programming 2.3.1
208+foldM :: forall b m. (Monad m) => (b -> Bytes -> m b) -> b -> Builder -> m b
212−-- Inorder traversal using a stack
209+foldM f a0 = foldl (\ma b -> ma >>= flip f b) (pure a0)
213−-- https://yuyuan.org/MorrisAlgorithm/
210+
214−foldM f a0 b = tailRecM outer { p: b, stack: Nil, accum: a0 }
211+-- | Construct a `Builder` with a single `ArrayBuffer`. *O(1)*
215− where
212+singleton :: ArrayBuffer -> Builder
216− outer { p, stack, accum } = do
213+singleton buf = Node Null (ByteBuff buf) Null
217− stack' <- tailRecM inner { p_: p, stack_: stack }
214+
218− case uncons stack' of
219− Nothing -> pure $ Done accum
220− Just { head: Node _ x r, tail } -> do
221− accum' <- f accum x
222− pure $ Loop { p: r, stack: tail, accum: accum' }
223− Just { head: Null } -> pure $ Done accum
224− inner { p_: Null, stack_ } = pure $ Done stack_
225− inner { p_: n@(Node l _ _), stack_ } = pure $ Loop { p_: l, stack_: n : stack_ }
226−
227−-- | Construct a `Builder` with a single `DataBuff`. *O(1)*
215+-- | Construct a `Builder` with a single `DataView`. *O(1)*
228−singleton :: DataBuff -> Builder
216+singleton_ :: DataView -> Builder
229−singleton buf = Node Null buf Null
217+singleton_ buf = Node Null (ByteView buf) Null
230
218
231-- | Calculate the total byte length of the `Builder`, without actually
219-- | Calculate the total byte length of the `Builder`, without actually
232-- | building it yet. *O(n)*
220-- | building it yet. *O(n)*
233length :: Builder -> ByteLength
221length :: Builder -> ByteLength
234length bldr = foldl (\b a -> b + len a) 0 bldr
222length bldr = foldl (\b a -> b + len a) 0 bldr
235 where
223 where
236− len (Buff ab) = AB.byteLength ab
224+ len (ByteBuff ab) = AB.byteLength ab
237− len (View dv) = DV.byteLength dv
225+ len (ByteView dv) = DV.byteLength dv
238
226
239−-- | Prepend a `DataBuff` to the beginning of the `Builder`. *O(1)*
227+ -- | View the contents of `Bytes` as a `DataView`.
240−cons :: DataBuff -> Builder -> Builder
228+toView :: Bytes -> DataView
241−cons x bs = Node Null x bs
229+toView (ByteBuff ab) = DV.whole ab
230+toView (ByteView dv) = dv
242
231
232+-- | Prepend an `ArrayBuffer` to the beginning of the `Builder`. *O(1)*
233+cons :: ArrayBuffer -> Builder -> Builder
234+cons x bs = Node Null (ByteBuff x) bs
235+
236+-- | Prepend a `DataView` to the beginning of the `Builder`. *O(1)*
237+cons_ :: DataView -> Builder -> Builder
238+cons_ x bs = Node Null (ByteView x) bs
239+
243−-- | Append a `DataBuff` to the end of the `Builder`. *O(1)*
240+-- | Append an `ArrayBuffer` to the end of the `Builder`. *O(1)*
244−snoc :: Builder -> DataBuff -> Builder
241+snoc :: Builder -> ArrayBuffer -> Builder
245−snoc bs x = Node bs x Null
242+snoc bs x = Node bs (ByteBuff x) Null
243+
244+-- | Append a `DataView` to the end of the `Builder`. *O(1)*
245+snoc_ :: Builder -> DataView -> Builder
246+snoc_ bs x = Node bs (ByteView x) Null
246
247
247-- | Build a single `ArrayBuffer` from a `Builder`. *O(n)*
248-- | Build a single `ArrayBuffer` from a `Builder`. *O(n)*
248−execBuilder :: forall m. MonadEffect m => MonadRec m => Builder -> m ArrayBuffer
249+execBuilder :: forall m. (MonadEffect m) => Builder -> m ArrayBuffer
249execBuilder bldr = do
250execBuilder bldr = do
250 let buflen = length bldr
251 let buflen = length bldr
251 -- Allocate the final ArrayBuffer
252 -- Allocate the final ArrayBuffer
@@ -259,14 +260,12 @@ execBuilder bldr = do
259 aview <- liftEffect $ toUint8Array a
260 aview <- liftEffect $ toUint8Array a
260 _ <- liftEffect $ AT.setTyped newview (Just offset) aview
261 _ <- liftEffect $ AT.setTyped newview (Just offset) aview
261 pure $ offset + AT.byteLength aview
262 pure $ offset + AT.byteLength aview
262− )
263− 0
264− bldr
263+ ) 0 bldr
265 pure buf
264 pure buf
266− where
265+ where
267− toUint8Array :: DataBuff -> Effect Uint8Array
266+ toUint8Array :: Bytes -> Effect Uint8Array
268− toUint8Array (Buff ab) = AT.whole ab
267+ toUint8Array (ByteBuff ab) = AT.whole ab
269− toUint8Array (View dv) =
268+ toUint8Array (ByteView dv) =
270 AT.part (DV.buffer dv) (DV.byteOffset dv) (DV.byteLength dv)
269 AT.part (DV.buffer dv) (DV.byteOffset dv) (DV.byteLength dv)
271
270
272-- | Serialize an 8-bit unsigned integer (byte) into a new `ArrayBuffer`.
271-- | Serialize an 8-bit unsigned integer (byte) into a new `ArrayBuffer`.
spago-dev.dhall → test.dhallrenamed+2−6
@@ -12,9 +12,5 @@ let conf = ./spago.dhall
12
12
13in conf //
13in conf //
14 { sources = conf.sources # [ "test/**/*.purs" ]
14 { sources = conf.sources # [ "test/**/*.purs" ]
15− , dependencies = conf.dependencies #
15+ , dependencies = conf.dependencies # [ "assert" ]
16− [ "assert"
17− , "arrays"
18− , "web-encoding"
19− ]
20− }
16+ }
test/Main.purs+64−95
@@ -1,24 +1,16 @@
1module Test.Main where
1module Test.Main where
2
2
3−import Prelude
3+import Data.ArrayBuffer.Builder
4
4
5import Control.Monad.Writer.Trans (tell)
5import Control.Monad.Writer.Trans (tell)
6−import Data.Array (foldRecM)
7−import Data.Array as Array
8−import Data.ArrayBuffer.ArrayBuffer (byteLength)
9−import Data.ArrayBuffer.Builder (Builder, DataBuff(..), PutM, execPut, putArrayBuffer, putInt16be, putInt32be, putInt32le, putInt8, subBuilder)
10−import Data.ArrayBuffer.Builder.Internal (cons, encodeInt8, execBuilder, length, singleton, (<>>))
6+import Data.ArrayBuffer.Builder.Internal (cons, encodeInt8, execBuilder, length, singleton, singleton_, (<>>))
11import Data.ArrayBuffer.DataView as DV
7import Data.ArrayBuffer.DataView as DV
12−import Data.ArrayBuffer.Typed (buffer)
13import Data.ArrayBuffer.Typed as AT
8import Data.ArrayBuffer.Typed as AT
14−import Data.ArrayBuffer.Typed as AV
9+import Data.ArrayBuffer.Types (ArrayBuffer, Uint8Array)
15−import Data.ArrayBuffer.Types (ArrayBuffer, Uint8Array, Int8Array)
16import Data.UInt as UInt
10import Data.UInt as UInt
17import Effect (Effect)
11import Effect (Effect)
18−import Effect.Class (class MonadEffect, liftEffect)
12+import Prelude (Unit, bind, pure, discard, map, negate, ($), (<$>), (=<<), (<>))
19import Test.Assert (assertEqual')
13import Test.Assert (assertEqual')
20−import Web.Encoding.TextEncoder (encode)
21−import Web.Encoding.TextEncoder as TextEncoder
22
14
23asBytes :: ArrayBuffer -> Effect (Array Int)
15asBytes :: ArrayBuffer -> Effect (Array Int)
24asBytes x = do
16asBytes x = do
@@ -28,82 +20,80 @@ asBytes x = do
28putTest :: String -> Array Int -> PutM Effect Unit -> Effect Unit
20putTest :: String -> Array Int -> PutM Effect Unit -> Effect Unit
29putTest label expected put = do
21putTest label expected put = do
30 actual <- asBytes =<< execPut put
22 actual <- asBytes =<< execPut put
31− assertEqual' label { actual, expected }
23+ assertEqual' label {actual,expected}
32
24
33buildTest :: String -> Array Int -> Effect Builder -> Effect Unit
25buildTest :: String -> Array Int -> Effect Builder -> Effect Unit
34buildTest label expected bldr = do
26buildTest label expected bldr = do
35 actual <- asBytes =<< execBuilder =<< bldr
27 actual <- asBytes =<< execBuilder =<< bldr
36− assertEqual' label { actual, expected }
28+ assertEqual' label {actual,expected}
37
29
38main :: Effect Unit
30main :: Effect Unit
39main = do
31main = do
40− putTest "Test 0" [ 6, 7, 8 ] do
32+ putTest "Test 0" [6,7,8] $ do
41 putInt8 6
33 putInt8 6
42 putInt8 7
34 putInt8 7
43 putInt8 8
35 putInt8 8
44
36
45− putTest "Test 1" [ 255, 254 ] do
37+ putTest "Test 1" [255,254] $ do
46 putInt16be (-2)
38 putInt16be (-2)
47
39
48− putTest "Test 3" [ 3, 0, 0, 0 ] do
40+ putTest "Test 3" [3,0,0,0] $ do
49 putInt32le 3
41 putInt32le 3
50
42
51− buildTest "Test 4" [ 1, 2, 3, 4 ] do
43+ buildTest "Test 4" [1,2,3,4] $ do
52− b1 <- Buff <$> encodeInt8 1
44+ b1 <- encodeInt8 1
53− b2 <- Buff <$> encodeInt8 2
45+ b2 <- encodeInt8 2
54− b3 <- Buff <$> encodeInt8 3
46+ b3 <- encodeInt8 3
55− b4 <- Buff <$> encodeInt8 4
47+ b4 <- encodeInt8 4
56 pure $ singleton b1 <> singleton b2 <> singleton b3 <> singleton b4
48 pure $ singleton b1 <> singleton b2 <> singleton b3 <> singleton b4
57
49
58− buildTest "Test 5" [ 1, 2, 3, 4 ] do
50+ buildTest "Test 5" [1,2,3,4] $ do
59− b1 <- Buff <$> encodeInt8 1
51+ b1 <- encodeInt8 1
60− b2 <- Buff <$> encodeInt8 2
52+ b2 <- encodeInt8 2
61− b3 <- Buff <$> encodeInt8 3
53+ b3 <- encodeInt8 3
62− b4 <- Buff <$> encodeInt8 4
54+ b4 <- encodeInt8 4
63 pure $ singleton b1 <>> singleton b2 <>> singleton b3 <>> singleton b4
55 pure $ singleton b1 <>> singleton b2 <>> singleton b3 <>> singleton b4
64
56
65− buildTest "Test 6" [ 1, 2, 3, 4 ] do
57+ buildTest "Test 6" [1,2,3,4] $ do
66− b1 <- Buff <$> encodeInt8 1
58+ b1 <- encodeInt8 1
67− b2 <- Buff <$> encodeInt8 2
59+ b2 <- encodeInt8 2
68− b3 <- Buff <$> encodeInt8 3
60+ b3 <- encodeInt8 3
69− b4 <- Buff <$> encodeInt8 4
61+ b4 <- encodeInt8 4
70 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
62 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
71
63
72− buildTest "Test 6" [ 1, 2, 3, 4, 5, 6, 7, 8 ] do
64+ buildTest "Test 6" [1,2,3,4,5,6,7,8] $ do
73− b1 <- Buff <$> encodeInt8 1
65+ b1 <- encodeInt8 1
74− b2 <- Buff <$> encodeInt8 2
66+ b2 <- encodeInt8 2
75− b3 <- Buff <$> encodeInt8 3
67+ b3 <- encodeInt8 3
76− b4 <- Buff <$> encodeInt8 4
68+ b4 <- encodeInt8 4
77− b5 <- Buff <$> encodeInt8 5
69+ b5 <- encodeInt8 5
78− b6 <- Buff <$> encodeInt8 6
70+ b6 <- encodeInt8 6
79− b7 <- Buff <$> encodeInt8 7
71+ b7 <- encodeInt8 7
80− b8 <- Buff <$> encodeInt8 8
72+ b8 <- encodeInt8 8
81 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
73 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
82− <> singleton b5
83− <> (singleton b6 <> singleton b7)
74+ <> singleton b5 <> (singleton b6 <> singleton b7) <> singleton b8
84− <> singleton b8
75+
85−
86− buildTest "Test 7" [ 1, 2, 3, 4, 5, 6, 7, 8 ] do
76+ buildTest "Test 7" [1,2,3,4,5,6,7,8] $ do
87− b1 <- Buff <$> encodeInt8 1
77+ b1 <- encodeInt8 1
88− b2 <- Buff <$> encodeInt8 2
78+ b2 <- encodeInt8 2
89− b3 <- Buff <$> encodeInt8 3
79+ b3 <- encodeInt8 3
90− b4 <- Buff <$> encodeInt8 4
80+ b4 <- encodeInt8 4
91− b5 <- Buff <$> encodeInt8 5
81+ b5 <- encodeInt8 5
92− b6 <- Buff <$> encodeInt8 6
82+ b6 <- encodeInt8 6
93− b7 <- Buff <$> encodeInt8 7
83+ b7 <- encodeInt8 7
94− b8 <- Buff <$> encodeInt8 8
84+ b8 <- encodeInt8 8
95 pure $ ((singleton b1 <> singleton b2) <> (singleton b3 <> singleton b4))
85 pure $ ((singleton b1 <> singleton b2) <> (singleton b3 <> singleton b4))
96− <> ((singleton b5 <> singleton b6) <> (singleton b7 <> singleton b8))
86+ <> ((singleton b5 <> singleton b6) <> (singleton b7 <> singleton b8))
97
87
98− buildTest "Test 8" [ 1, 2, 3, 4 ] do
88+ buildTest "Test 8" [1,2,3,4] $ do
99− b1 <- Buff <$> encodeInt8 1
89+ b1 <- encodeInt8 1
100− b2 <- Buff <$> encodeInt8 2
90+ b2 <- encodeInt8 2
101− b3 <- Buff <$> encodeInt8 3
91+ b3 <- encodeInt8 3
102− b4 <- Buff <$> encodeInt8 4
92+ b4 <- encodeInt8 4
103 pure $ (cons b1 (singleton b2)) <> (cons b3 (singleton b4))
93 pure $ (cons b1 (singleton b2)) <> (cons b3 (singleton b4))
104
94
105− putTest "Test 9" [ 1, 2, 2, 3, 4 ] do
95+ putTest "Test 9" [1,2,2,3,4] $ do
106− x <- subBuilder do
96+ x <- subBuilder $ do
107 putInt8 3
97 putInt8 3
108 putInt8 4
98 putInt8 4
109 putInt8 1
99 putInt8 1
@@ -111,36 +101,15 @@ main = do
111 putInt8 $ length x
101 putInt8 $ length x
112 tell x
102 tell x
113
103
114− buildTest "Test 10" [ 1, 2, 3, 4, 5, 6, 7, 8 ] do
104+ buildTest "Test 10" [1,2,3,4,5,6,7,8] $ do
115− b1 <- View <$> DV.whole <$> encodeInt8 1
105+ b1 <- DV.whole <$> encodeInt8 1
116− b2 <- View <$> DV.whole <$> encodeInt8 2
106+ b2 <- DV.whole <$> encodeInt8 2
117− b3 <- View <$> DV.whole <$> encodeInt8 3
107+ b3 <- DV.whole <$> encodeInt8 3
118− b4 <- View <$> DV.whole <$> encodeInt8 4
108+ b4 <- DV.whole <$> encodeInt8 4
119− b5 <- View <$> DV.whole <$> encodeInt8 5
109+ b5 <- DV.whole <$> encodeInt8 5
120− b6 <- View <$> DV.whole <$> encodeInt8 6
110+ b6 <- DV.whole <$> encodeInt8 6
121− b7 <- View <$> DV.whole <$> encodeInt8 7
111+ b7 <- DV.whole <$> encodeInt8 7
122− b8 <- View <$> DV.whole <$> encodeInt8 8
112+ b8 <- DV.whole <$> encodeInt8 8
123− pure $ ((singleton b1 <> singleton b2) <> (singleton b3 <> singleton b4))
113+ pure $ ((singleton_ b1 <> singleton_ b2) <> (singleton_ b3 <> singleton_ b4))
124− <> ((singleton b5 <> singleton b6) <> (singleton b7 <> singleton b8))
114+ <> ((singleton_ b5 <> singleton_ b6) <> (singleton_ b7 <> singleton_ b8))
125−
115+
126− let stackblower = Array.replicate 20000 2
127− putTest "Stack test" stackblower do
128− foldRecM (\_ x -> putInt8 x) unit stackblower
129−
130− do
131− let
132− putStringUtf8 :: forall m. MonadEffect m => String -> PutM m Unit
133− putStringUtf8 s = do
134− textEncoder <- liftEffect TextEncoder.new
135− let stringbuf = buffer $ encode s textEncoder
136− -- Put a 32-bit big-endian length prefix for the length of the utf8 string, in bytes.
137− putInt32be $ byteLength stringbuf
138− putArrayBuffer stringbuf
139−
140− arraybuffer :: ArrayBuffer <- execPut $ putStringUtf8 "🦝"
141− view :: Int8Array <- AV.whole arraybuffer
142− viewarray <- AV.toArray view
143− assertEqual' "utf-8 test"
144− { actual: viewarray
145− , expected: [ 0, 0, 0, 4, -16, -97, -90, -99 ]
146− }