git.iko.soy/rowtype-yoga/purescript-arraybuffer-builder
on master help sign in
Change name of `Bytes` to `DataBuff`.
e09961eJames Brock
CHANGELOG.md+5
@@ -1,5 +1,10 @@
1# Changelog
1# Changelog
2
2
3+## v2.1.0 2021-07-22
4+
5+Renamed `Data.ArrayBuffer.Internal.Bytes` and exported
6+it as `Data.ArrayBuffer.DataBuff`.
7+
3## v2.0.0 2021-07-19
8## v2.0.0 2021-07-19
4
9
5Build for PureScript v0.14.
10Build for PureScript v0.14.
src/Data/ArrayBuffer/Builder.purs+9−10
@@ -17,6 +17,7 @@ module Data.ArrayBuffer.Builder
17, subBuilder
17, subBuilder
18, putArrayBuffer
18, putArrayBuffer
19, putDataView
19, putDataView
20+, putDataBuff
20, putUint8
21, putUint8
21, putInt8
22, putInt8
22, putUint16be
23, putUint16be
@@ -35,17 +36,11 @@ module Data.ArrayBuffer.Builder
35)
36)
36where
37where
37
38
38−import Data.ArrayBuffer.Builder.Internal
39− ( Builder
40− , (<>>)
41− , length
42− )
43−
44−import Data.ArrayBuffer.Builder.Internal as Internal
45−
46import Prelude
39import Prelude
47
40
48import Control.Monad.Writer.Trans (WriterT, execWriterT, tell, lift)
41import 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
49import Data.ArrayBuffer.Types (ArrayBuffer, DataView)
44import Data.ArrayBuffer.Types (ArrayBuffer, DataView)
50import Data.Float32 (Float32)
45import Data.Float32 (Float32)
51import Data.UInt (UInt)
46import Data.UInt (UInt)
@@ -94,11 +89,15 @@ subBuilder = lift <<< execWriterT
94
89
95-- | Append an `ArrayBuffer` to the builder.
90-- | Append an `ArrayBuffer` to the builder.
96putArrayBuffer :: forall m. (MonadEffect m) => ArrayBuffer -> PutM m Unit
91putArrayBuffer :: forall m. (MonadEffect m) => ArrayBuffer -> PutM m Unit
97−putArrayBuffer = tell <<< Internal.singleton
92+putArrayBuffer = tell <<< Internal.singleton <<< Internal.Buff
98
93
99-- | Append a `DataView` to the builder.
94-- | Append a `DataView` to the builder.
100putDataView :: forall m. (MonadEffect m) => DataView -> PutM m Unit
95putDataView :: forall m. (MonadEffect m) => DataView -> PutM m Unit
101−putDataView = tell <<< Internal.singleton_
96+putDataView = tell <<< Internal.singleton <<< Internal.View
97+
98+-- | Append either an `ArrayBuffer` or a `DataView` to the builder.
99+putDataBuff :: forall m. (MonadEffect m) => DataBuff -> PutM m Unit
100+putDataBuff = tell <<< Internal.singleton
102
101
103-- | Append an 8-bit unsigned integer (byte) to the builder.
102-- | Append an 8-bit unsigned integer (byte) to the builder.
104putUint8 :: forall m. (MonadEffect m) => UInt -> PutM m Unit
103putUint8 :: forall m. (MonadEffect m) => UInt -> PutM m Unit
src/Data/ArrayBuffer/Internal.purs+38−55
@@ -57,19 +57,20 @@
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.
69-- |
68-- |
70-- | In the longer term, it might make sense to try to change the `Builder` so
69-- | In the longer term, it might make sense to try to change the `Builder` so
71-- | that it works like the
70-- | that it works like the
72−-- | https://hackage.haskell.org/package/bytestring/docs/Data-ByteString-Builder.html
71+-- | 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 .
73-- |
74-- |
74-- | Here are some benchmarks of different Haskell ByteString builders
75-- | Here are some benchmarks of different Haskell ByteString builders
75-- | https://github.com/haskell-perf/strict-bytestring-builders
76-- | https://github.com/haskell-perf/strict-bytestring-builders
@@ -77,27 +78,18 @@
77-- | We've tried to design the API for this library with minimal assumptions,
78-- | We've tried to design the API for this library with minimal assumptions,
78-- | so that if we want to change the `Builder` implementation later then we can.
79-- | so that if we want to change the `Builder` implementation later then we can.
79-- |
80-- |
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−-- |
86module Data.ArrayBuffer.Builder.Internal
81module Data.ArrayBuffer.Builder.Internal
87( Builder(..)
82( Builder(..)
88, (<>>)
83, (<>>)
89−, Bytes(..)
84+, DataBuff(..)
90, toView
85, toView
91, execBuilder
86, execBuilder
92, length
87, length
93, foldl
88, foldl
94, foldM
89, foldM
95, singleton
90, singleton
96−, singleton_
97, cons
91, cons
98−, cons_
99, snoc
92, snoc
100−, snoc_
101, encodeUint8
93, encodeUint8
102, encodeInt8
94, encodeInt8
103, encodeUint16be
95, encodeUint16be
@@ -127,6 +119,19 @@ import Data.UInt (UInt)
127import Effect (Effect)
119import Effect (Effect)
128import Effect.Class (class MonadEffect, liftEffect)
120import Effect.Class (class MonadEffect, liftEffect)
129
121
122+-- | For distinguishing between `ArrayBuffer` and `DataView`.
123+data DataBuff
124+ = Buff ArrayBuffer
125+ | View DataView
126+
127+-- Concerning DataViews.
128+-- https://v8.dev/blog/dataview
129+
130+ -- | View the contents of `DataBuff` as a `DataView`.
131+toView :: DataBuff -> DataView
132+toView (Buff ab) = DV.whole ab
133+toView (View dv) = dv
134+
130-- | Monoidal builder for `ArrayBuffer`s.
135-- | Monoidal builder for `ArrayBuffer`s.
131-- |
136-- |
132-- | We can add two types of things to the `Builder`:
137-- | We can add two types of things to the `Builder`:
@@ -138,7 +143,7 @@ import Effect.Class (class MonadEffect, liftEffect)
138-- | from some other `ArrayBuffer`, so that we don’t
143-- | from some other `ArrayBuffer`, so that we don’t
139-- | need an extra intermediate copy of the slice.
144-- | need an extra intermediate copy of the slice.
140data Builder
145data Builder
141− = Node Builder Bytes Builder
146+ = Node Builder DataBuff Builder
142 | Null
147 | Null
143
148
144-- | ### Left-associative `<>>` append operator
149-- | ### Left-associative `<>>` append operator
@@ -193,57 +198,35 @@ infixl 5 append as <>>
193instance monoidBuilder :: Monoid Builder where
198instance monoidBuilder :: Monoid Builder where
194 mempty = Null
199 mempty = Null
195
200
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.
201-- | `Builder` is not an instance of `Foldable` because `Builder` is monomorphic.
202−foldl :: forall b. (b -> Bytes -> b) -> b -> Builder -> b
202+foldl :: forall b. (b -> DataBuff -> b) -> b -> Builder -> b
203foldl _ a Null = a
203foldl _ a Null = a
204foldl f a (Node l x r) = foldl f (f (foldl f a l) x) r
204foldl f a (Node l x r) = foldl f (f (foldl f a l) x) r
205
205
206-- | Monomorphic foldM copied from
206-- | Monomorphic foldM copied from
207-- | [`Data.Foldable.foldM`](https://pursuit.purescript.org/packages/purescript-foldable-traversable/4.1.1/docs/Data.Foldable#v:foldM)
207-- | [`Data.Foldable.foldM`](https://pursuit.purescript.org/packages/purescript-foldable-traversable/4.1.1/docs/Data.Foldable#v:foldM)
208−foldM :: forall b m. (Monad m) => (b -> Bytes -> m b) -> b -> Builder -> m b
208+foldM :: forall b m. (Monad m) => (b -> DataBuff -> m b) -> b -> Builder -> m b
209foldM f a0 = foldl (\ma b -> ma >>= flip f b) (pure a0)
209foldM f a0 = foldl (\ma b -> ma >>= flip f b) (pure a0)
210
210
211−-- | Construct a `Builder` with a single `ArrayBuffer`. *O(1)*
211+-- | Construct a `Builder` with a single `DataBuff`. *O(1)*
212−singleton :: ArrayBuffer -> Builder
212+singleton :: DataBuff -> Builder
213−singleton buf = Node Null (ByteBuff buf) Null
213+singleton buf = Node Null buf Null
214−
215−-- | Construct a `Builder` with a single `DataView`. *O(1)*
216−singleton_ :: DataView -> Builder
217−singleton_ buf = Node Null (ByteView buf) Null
218
214
219-- | Calculate the total byte length of the `Builder`, without actually
215-- | Calculate the total byte length of the `Builder`, without actually
220-- | building it yet. *O(n)*
216-- | building it yet. *O(n)*
221length :: Builder -> ByteLength
217length :: Builder -> ByteLength
222length bldr = foldl (\b a -> b + len a) 0 bldr
218length bldr = foldl (\b a -> b + len a) 0 bldr
223 where
219 where
224− len (ByteBuff ab) = AB.byteLength ab
220+ len (Buff ab) = AB.byteLength ab
225− len (ByteView dv) = DV.byteLength dv
221+ len (View dv) = DV.byteLength dv
226−
227− -- | View the contents of `Bytes` as a `DataView`.
228−toView :: Bytes -> DataView
229−toView (ByteBuff ab) = DV.whole ab
230−toView (ByteView dv) = dv
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
222
240−-- | Append an `ArrayBuffer` to the end of the `Builder`. *O(1)*
223+-- | Prepend a `DataBuff` to the beginning of the `Builder`. *O(1)*
241−snoc :: Builder -> ArrayBuffer -> Builder
224+cons :: DataBuff -> Builder -> Builder
242−snoc bs x = Node bs (ByteBuff x) Null
225+cons x bs = Node Null x bs
243
226
244−-- | Append a `DataView` to the end of the `Builder`. *O(1)*
227+-- | Append a `DataBuff` to the end of the `Builder`. *O(1)*
245−snoc_ :: Builder -> DataView -> Builder
228+snoc :: Builder -> DataBuff -> Builder
246−snoc_ bs x = Node bs (ByteView x) Null
229+snoc bs x = Node bs x Null
247
230
248-- | Build a single `ArrayBuffer` from a `Builder`. *O(n)*
231-- | Build a single `ArrayBuffer` from a `Builder`. *O(n)*
249execBuilder :: forall m. (MonadEffect m) => Builder -> m ArrayBuffer
232execBuilder :: forall m. (MonadEffect m) => Builder -> m ArrayBuffer
@@ -263,9 +246,9 @@ execBuilder bldr = do
263 ) 0 bldr
246 ) 0 bldr
264 pure buf
247 pure buf
265 where
248 where
266− toUint8Array :: Bytes -> Effect Uint8Array
249+ toUint8Array :: DataBuff -> Effect Uint8Array
267− toUint8Array (ByteBuff ab) = AT.whole ab
250+ toUint8Array (Buff ab) = AT.whole ab
268− toUint8Array (ByteView dv) =
251+ toUint8Array (View dv) =
269 AT.part (DV.buffer dv) (DV.byteOffset dv) (DV.byteLength dv)
252 AT.part (DV.buffer dv) (DV.byteOffset dv) (DV.byteLength dv)
270
253
271-- | Serialize an 8-bit unsigned integer (byte) into a new `ArrayBuffer`.
254-- | Serialize an 8-bit unsigned integer (byte) into a new `ArrayBuffer`.
test/Main.purs+43−43
@@ -3,7 +3,7 @@ module Test.Main where
3import Data.ArrayBuffer.Builder
3import Data.ArrayBuffer.Builder
4
4
5import Control.Monad.Writer.Trans (tell)
5import Control.Monad.Writer.Trans (tell)
6−import Data.ArrayBuffer.Builder.Internal (cons, encodeInt8, execBuilder, length, singleton, singleton_, (<>>))
6+import Data.ArrayBuffer.Builder.Internal (cons, encodeInt8, execBuilder, length, singleton, (<>>))
7import Data.ArrayBuffer.DataView as DV
7import Data.ArrayBuffer.DataView as DV
8import Data.ArrayBuffer.Typed as AT
8import Data.ArrayBuffer.Typed as AT
9import Data.ArrayBuffer.Types (ArrayBuffer, Uint8Array)
9import Data.ArrayBuffer.Types (ArrayBuffer, Uint8Array)
@@ -41,55 +41,55 @@ main = do
41 putInt32le 3
41 putInt32le 3
42
42
43 buildTest "Test 4" [1,2,3,4] $ do
43 buildTest "Test 4" [1,2,3,4] $ do
44− b1 <- encodeInt8 1
44+ b1 <- Buff <$> encodeInt8 1
45− b2 <- encodeInt8 2
45+ b2 <- Buff <$> encodeInt8 2
46− b3 <- encodeInt8 3
46+ b3 <- Buff <$> encodeInt8 3
47− b4 <- encodeInt8 4
47+ b4 <- Buff <$> encodeInt8 4
48 pure $ singleton b1 <> singleton b2 <> singleton b3 <> singleton b4
48 pure $ singleton b1 <> singleton b2 <> singleton b3 <> singleton b4
49
49
50 buildTest "Test 5" [1,2,3,4] $ do
50 buildTest "Test 5" [1,2,3,4] $ do
51− b1 <- encodeInt8 1
51+ b1 <- Buff <$> encodeInt8 1
52− b2 <- encodeInt8 2
52+ b2 <- Buff <$> encodeInt8 2
53− b3 <- encodeInt8 3
53+ b3 <- Buff <$> encodeInt8 3
54− b4 <- encodeInt8 4
54+ b4 <- Buff <$> encodeInt8 4
55 pure $ singleton b1 <>> singleton b2 <>> singleton b3 <>> singleton b4
55 pure $ singleton b1 <>> singleton b2 <>> singleton b3 <>> singleton b4
56
56
57 buildTest "Test 6" [1,2,3,4] $ do
57 buildTest "Test 6" [1,2,3,4] $ do
58− b1 <- encodeInt8 1
58+ b1 <- Buff <$> encodeInt8 1
59− b2 <- encodeInt8 2
59+ b2 <- Buff <$> encodeInt8 2
60− b3 <- encodeInt8 3
60+ b3 <- Buff <$> encodeInt8 3
61− b4 <- encodeInt8 4
61+ b4 <- Buff <$> encodeInt8 4
62 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
62 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
63
63
64 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
65− b1 <- encodeInt8 1
65+ b1 <- Buff <$> encodeInt8 1
66− b2 <- encodeInt8 2
66+ b2 <- Buff <$> encodeInt8 2
67− b3 <- encodeInt8 3
67+ b3 <- Buff <$> encodeInt8 3
68− b4 <- encodeInt8 4
68+ b4 <- Buff <$> encodeInt8 4
69− b5 <- encodeInt8 5
69+ b5 <- Buff <$> encodeInt8 5
70− b6 <- encodeInt8 6
70+ b6 <- Buff <$> encodeInt8 6
71− b7 <- encodeInt8 7
71+ b7 <- Buff <$> encodeInt8 7
72− b8 <- encodeInt8 8
72+ b8 <- Buff <$> encodeInt8 8
73 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
73 pure $ singleton b1 <> (singleton b2 <> singleton b3) <> singleton b4
74 <> singleton b5 <> (singleton b6 <> singleton b7) <> singleton b8
74 <> singleton b5 <> (singleton b6 <> singleton b7) <> singleton b8
75
75
76 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
77− b1 <- encodeInt8 1
77+ b1 <- Buff <$> encodeInt8 1
78− b2 <- encodeInt8 2
78+ b2 <- Buff <$> encodeInt8 2
79− b3 <- encodeInt8 3
79+ b3 <- Buff <$> encodeInt8 3
80− b4 <- encodeInt8 4
80+ b4 <- Buff <$> encodeInt8 4
81− b5 <- encodeInt8 5
81+ b5 <- Buff <$> encodeInt8 5
82− b6 <- encodeInt8 6
82+ b6 <- Buff <$> encodeInt8 6
83− b7 <- encodeInt8 7
83+ b7 <- Buff <$> encodeInt8 7
84− b8 <- encodeInt8 8
84+ b8 <- Buff <$> encodeInt8 8
85 pure $ ((singleton b1 <> singleton b2) <> (singleton b3 <> singleton b4))
85 pure $ ((singleton b1 <> singleton b2) <> (singleton b3 <> singleton b4))
86 <> ((singleton b5 <> singleton b6) <> (singleton b7 <> singleton b8))
86 <> ((singleton b5 <> singleton b6) <> (singleton b7 <> singleton b8))
87
87
88 buildTest "Test 8" [1,2,3,4] $ do
88 buildTest "Test 8" [1,2,3,4] $ do
89− b1 <- encodeInt8 1
89+ b1 <- Buff <$> encodeInt8 1
90− b2 <- encodeInt8 2
90+ b2 <- Buff <$> encodeInt8 2
91− b3 <- encodeInt8 3
91+ b3 <- Buff <$> encodeInt8 3
92− b4 <- encodeInt8 4
92+ b4 <- Buff <$> encodeInt8 4
93 pure $ (cons b1 (singleton b2)) <> (cons b3 (singleton b4))
93 pure $ (cons b1 (singleton b2)) <> (cons b3 (singleton b4))
94
94
95 putTest "Test 9" [1,2,2,3,4] $ do
95 putTest "Test 9" [1,2,2,3,4] $ do
@@ -102,14 +102,14 @@ main = do
102 tell x
102 tell x
103
103
104 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
105− b1 <- DV.whole <$> encodeInt8 1
105+ b1 <- View <$> DV.whole <$> encodeInt8 1
106− b2 <- DV.whole <$> encodeInt8 2
106+ b2 <- View <$> DV.whole <$> encodeInt8 2
107− b3 <- DV.whole <$> encodeInt8 3
107+ b3 <- View <$> DV.whole <$> encodeInt8 3
108− b4 <- DV.whole <$> encodeInt8 4
108+ b4 <- View <$> DV.whole <$> encodeInt8 4
109− b5 <- DV.whole <$> encodeInt8 5
109+ b5 <- View <$> DV.whole <$> encodeInt8 5
110− b6 <- DV.whole <$> encodeInt8 6
110+ b6 <- View <$> DV.whole <$> encodeInt8 6
111− b7 <- DV.whole <$> encodeInt8 7
111+ b7 <- View <$> DV.whole <$> encodeInt8 7
112− b8 <- DV.whole <$> encodeInt8 8
112+ b8 <- View <$> DV.whole <$> encodeInt8 8
113− pure $ ((singleton_ b1 <> singleton_ b2) <> (singleton_ b3 <> singleton_ b4))
113+ pure $ ((singleton b1 <> singleton b2) <> (singleton b3 <> singleton b4))
114− <> ((singleton_ b5 <> singleton_ b6) <> (singleton_ b7 <> singleton_ b8))
114+ <> ((singleton b5 <> singleton b6) <> (singleton b7 <> singleton b8))
115
115