@@ -1,454 +1,156 @@
1−-- | `ArrayBuffer` serialization in the “builder monoid” style.
1+-- | This module provides a `Builder` monoid and a `PutM` monad
2+-- | for serializing `Data.ArrayBuffer.Types.ArrayBuffer`s.
3+-- | See the package README for usage examples.
24-- |
3−-- | This module provides a `Builder` monoid and a `PutM` monad which are roughly
4−-- | equivalent to types of the same name in the Haskell
5−-- | [`Data.Binary.Put`](https://hackage.haskell.org/package/binary/docs/Data-Binary-Put.html)
6−-- | module.
5+-- | Writing to an `ArrayBuffer` is an `Effect`ful activity, so most
6+-- | functions in this module must be run in a `MonadEffect` context.
77-- |
8−-- | This library defines no typeclasses.
9−-- |
10−-- | ## Deserialization
11−-- |
12−-- | See
13−-- | [__purescript-parsing-dataview__](https://pursuit.purescript.org/packages/purescript-parsing-dataview/)
14−-- | for a way to deserialize from `ArrayBuffer` back to Purescript data.
15−-- |
16−-- | ## Usage Examples
17−-- |
18−-- | All `ArrayBuffer` building must occur in `Effect`.
19−-- |
20−-- | ### Serialize an integer
21−-- |
22−-- | Create a two-byte `arraybuffer :: ArrayBuffer` which contains the number *-2* encoded as big-endian 16-bit two’s-complement.
23−-- | ```purescript
24−-- | do
25−-- | arraybuffer <- execPut $ putInt16be (-2)
26−-- | ```
27−-- |
28−-- | ### Serialize a `String` as UTF8
29−-- |
30−-- | A function which encodes a `String` as UTF8 with a length prefix in a
31−-- | way that's compatible with the
32−-- | [`Binary.Put.putStringUtf8`](https://hackage.haskell.org/package/binary/docs/Data-Binary-Put.html#v:putStringUtf8)
33−-- | function from the Haskell
34−-- | [__binary__](https://hackage.haskell.org/package/binary)
35−-- | library.
36−-- | Uses [`Data.TextEncoding.encodeUtf8`](https://pursuit.purescript.org/packages/purescript-text-encoding/docs/Data.TextEncoding#v:encodeUtf8).
37−-- | ```purescript
38−-- | putStringUtf8 :: forall m. (MonadEffect m) => String -> PutM m Unit
39−-- | putStringUtf8 s = do
40−-- | let stringbuf = Data.ArrayBuffer.Typed.buffer $
41−-- | Data.TextEncoding.encodeUtf8 s
42−-- | -- Put a 64-bit big-endian length prefix for the length of the utf8
43−-- | -- string, in bytes.
44−-- | putUint32be 0
45−-- | putUint32be $ Data.Uint.fromInt $ Data.ArrayBuffer.byteLength stringbuf
46−-- | putArrayBuffer stringbuf
47−-- | ```
48−-- |
49−-- | ### Serialize an `Array Int`
50−-- |
51−-- | A function which encodes an `Array Int` with a length prefix in a
52−-- | way that's compatible with the
53−-- | [`Binary` instance for `[Int32]`](https://hackage.haskell.org/package/binary/docs/Data-Binary.html#t:Binary)
54−-- | from the Haskell
55−-- | [__binary__](https://hackage.haskell.org/package/binary)
56−-- | library.
57−-- | ```purescript
58−-- | putArrayInt32 :: forall m. (MonadEffect m) => Array Int -> PutM m Unit
59−-- | putArrayInt32 xs = do
60−-- | -- Put a 64-bit big-endian length prefix for the length of the
61−-- | -- array, in bytes.
62−-- | putUint32be 0
63−-- | putUint32be $ Data.Uint.fromInt $ Data.Array.length xs
64−-- | traverse_ putInt32be xs
65−-- | ```
8+-- | For other operations for working with `ArrayBuffer`, see
9+-- | module
10+-- | [`Data.ArrayBuffer.ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer/docs/Data.ArrayBuffer.ArrayBuffer)
11+-- | in package __arraybuffer__.
6612module Data.ArrayBuffer.Builder
67−( PutM
68−, Put
69−, execPutM
70−, execPut
71−, putArrayBuffer
72−, putUint8
73−, putInt8
74−, putUint16be
75−, putUint16le
76−, putInt16be
77−, putInt16le
78−, putUint32be
79−, putUint32le
80−, putInt32be
81−, putInt32le
82−, putFloat32be
83−, putFloat32le
84−, putFloat64be
85−, putFloat64le
86−, Builder
87−, (<>>)
88−, execBuilder
89−, singleton
90−, snoc
91−, encodeUint8
92−, encodeInt8
93−, encodeUint16be
94−, encodeUint16le
95−, encodeInt16be
96−, encodeInt16le
97−, encodeUint32be
98−, encodeUint32le
99−, encodeInt32be
100−, encodeInt32le
101−, encodeFloat32be
102−, encodeFloat32le
103−, encodeFloat64be
104−, encodeFloat64le
105−)
106−where
13+ ( PutM
14+ , Put
15+ , execPutM
16+ , execPut
17+ , subBuilder
18+ , putArrayBuffer
19+ , putDataView
20+ , putDataBuff
21+ , putUint8
22+ , putInt8
23+ , putUint16be
24+ , putUint16le
25+ , putInt16be
26+ , putInt16le
27+ , putUint32be
28+ , putUint32le
29+ , putInt32be
30+ , putInt32le
31+ , putFloat32be
32+ , putFloat32le
33+ , putFloat64be
34+ , putFloat64le
35+ , module Data.ArrayBuffer.Builder.Internal
36+ ) where
10737
10838import Prelude
10939
110−import Control.Monad.Writer.Trans (WriterT, execWriterT, tell)
111−import Data.ArrayBuffer.ArrayBuffer as AB
112−import Data.ArrayBuffer.DataView as DV
113−import Data.ArrayBuffer.Typed as AT
114−import Data.ArrayBuffer.Types (ArrayBuffer, Uint8Array)
40+import Control.Monad.Rec.Class (class MonadRec)
41+import 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
44+import Data.ArrayBuffer.Types (ArrayBuffer, DataView)
11545import Data.Float32 (Float32)
116−import Data.Maybe (Maybe(..))
11746import Data.UInt (UInt)
11847import Effect (Effect)
119−import Effect.Class (class MonadEffect, liftEffect)
48+import Effect.Class (class MonadEffect)
12049
121−-- | The `PutM` monad is a Writer transformer monad which
122−-- | [gives us access to do-notation](https://wiki.haskell.org/Do_notation_considered_harmful#Library_design)
123−-- | for building `ArrayBuffer`s.
50+-- | The `PutM` monad is a `WriterT Builder` transformer monad which
51+-- | gives us do-notation for the `Builder` monoid. The base monad must be
52+-- | a `MonadEffect`.
53+-- |
54+-- | To append `Builder`s in this monad call `tell`, or any of the `put*`
55+-- | functions in this module.
12456type PutM = WriterT Builder
12557
126−-- | `Put` monad is the non-transformer version of `PutM`.
58+-- | The `PutM` type reified to `Effect`, in other words `WriterT Builder Effect`.
12759type Put = PutM Effect
12860
129−-- | Monoidal builder for `ArrayBuffer`s.
130−-- |
131−-- | ### Left-associative `<>>` append operator
61+-- | Build an `ArrayBuffer` with do-notation in any `MonadEffect`. *O(n)* Stack-safe.
62+execPutM :: forall m. MonadEffect m => MonadRec m => PutM m Unit -> m ArrayBuffer
63+execPutM = Internal.execBuilder <=< execWriterT
64+
65+-- | Build an `ArrayBuffer` with do-notation in `Effect`. *O(n)* Stack-safe.
66+execPut :: Put Unit -> Effect ArrayBuffer
67+execPut = execPutM
68+
69+-- | Build up a sub-`Builder` without `tell`ing it to the `Writer` yet.
13270-- |
133−-- | __TL;DR__ You probably don't want to use the `Builder` monoid directly
134−-- | in your code, it’s better to use the `PutM` monad with do-notation instead.
71+-- | One case where we might want to call a `subBuilder` is when
72+-- | serializing length-prefixed messages in some protocol. In that case,
73+-- | we must serialize the message first, calculate the message length,
74+-- | append the message length, and then append the message.
13575-- |
136−-- | The `Builder` monoid in this library is efficient when we `snoc` single
137−-- | items onto the end of it, or when we only `cons` single items to the
138−-- | beginning, but it can be less efficient when we are mixing `cons` and
139−-- | `snoc`.
140−-- | This matters when we're appending three or more `Builder`s
141−-- | in one associative expression, because the
142−-- | `Semigroup` append operator `<>` is right-associative.
76+-- | In a `PutM` monad do-block, we can
14377-- |
144−-- | To solve this, we provide an operator `<>>` for appending `Builders`.
145−-- | `<>>` is exactly the same as `<>`, but left-associative.
146−-- | This only matters when we're chaining together three
147−-- | or more `Builder`s in a single associative expression.
148−-- | Instead of
149−-- | ```
150−-- | builder₁ <> builder₂ <> builder₃
151−-- | ```
152−-- | we should always prefer to
153−-- | write
154−-- | ```
155−-- | builder₁ <>> builder₂ <>> builder₃
15678-- | ```
157−-- | so that we get the efficient
158−-- | `snoc`ing of `Builder`s.
159−-- |
160−-- | If we build our `ArrayBuffer`s with the `PutM` monad instead of appending by
161−-- | using the `Semigroup` instance of `Builder`, then we always get the efficient
162−-- | `snoc` case.
79+-- | do
80+-- | messageBuilder <- subBuilder $ do
81+-- | putField1
82+-- | putField2
16383-- |
164−data Builder
165− = Node Builder ArrayBuffer Builder
166− | Null
167−
168−instance semigroupBuilder :: Semigroup Builder where
169− append Null Null = Null
170− append l Null = l
171− append Null r = r
172− append l (Node Null rx rr) = Node l rx rr -- this is the snoc case
173− append (Node ll lx Null) r = Node ll lx r -- found the rightmost Null
174− -- of the left tree
175− append (Node ll lx lr) r = Node ll lx $ append lr r -- search down the right
176− -- side of the left tree
177− -- to find the rightmost
178− -- Null
179−
180−infixl 5 append as <>>
181−
182−instance monoidBuilder :: Monoid Builder where
183− mempty = Null
184−
185−-- | `Builder` is not an instance of `Foldable` because `Builder` is monomorphic.
186−foldl :: forall b. (b -> ArrayBuffer -> b) -> b -> Builder -> b
187−foldl f a Null = a
188−foldl f a (Node l x r) = foldl f (f (foldl f a l) x) r
189−
190−-- | Monomorphic foldM copied from
191−-- | [`Data.Foldable.foldM`](https://pursuit.purescript.org/packages/purescript-foldable-traversable/4.1.1/docs/Data.Foldable#v:foldM)
192−foldM :: forall b m. (Monad m) => (b -> ArrayBuffer -> m b) -> b -> Builder -> m b
193−foldM f a0 = foldl (\ma b -> ma >>= flip f b) (pure a0)
194−
195−-- | Construct a `Builder` with a single `ArrayBuffer`. *O(1)*
196−singleton :: ArrayBuffer -> Builder
197−singleton buf = Node Null buf Null
198−
199−-- | Add an `ArrayBuffer` to the end of the `Builder`. *O(1)*
200−snoc :: Builder -> ArrayBuffer -> Builder
201−snoc bs x = Node bs x Null
202−
203−-- | Build a single `ArrayBuffer` from a `Builder`. *O(n)*
204−execBuilder :: forall m. (MonadEffect m) => Builder -> m ArrayBuffer
205−execBuilder bldr = do
206− let buflen = foldl (\b a -> b + AB.byteLength a) 0 bldr
207− -- Allocate the final ArrayBuffer
208− buf <- liftEffect $ AB.empty buflen
209− -- Then copy each ArrayBuffer into the final ArrayBuffer.
210− -- To memcpy from one ArrayBuffer to another, apparently we have to first view
211− -- both ArrayBuffers as ArrayView (Typed Array).
212− newview <- liftEffect (AT.whole buf :: Effect Uint8Array)
213− _ <- foldM
214− ( \offset a -> do
215− let offset' = offset + AB.byteLength a
216− aview <- liftEffect (AT.whole a :: Effect Uint8Array)
217− _ <- liftEffect $ AT.setTyped newview (Just offset') aview
218− pure offset'
219− ) 0 bldr
220− pure buf
221−
222−-- | Build an `ArrayBuffer` with do-notation in any `MonadEffect`. *O(n)*
223−execPutM :: forall m. (MonadEffect m) => PutM m Unit -> m ArrayBuffer
224−execPutM = execBuilder <=< execWriterT
225−
226−-- | Build an `ArrayBuffer` with do-notation. *O(n)*
227−execPut :: Put Unit -> Effect ArrayBuffer
228−execPut = execPutM
84+-- | putInt32be $ length messageBuilder
85+-- | tell messageBuilder
86+-- | ```
87+subBuilder :: forall m. Monad m => PutM m Unit -> PutM m Builder
88+subBuilder = lift <<< execWriterT
22989
23090-- | Append an `ArrayBuffer` to the builder.
231−putArrayBuffer :: forall m. (MonadEffect m) => ArrayBuffer -> PutM m Unit
232−putArrayBuffer = tell <<< singleton
91+putArrayBuffer :: forall m. Monad m => ArrayBuffer -> PutM m Unit
92+putArrayBuffer = tell <<< Internal.singleton <<< Internal.Buff
23393
234−-- | Serialize an 8-bit unsigned integer (byte) into a new `ArrayBuffer`.
235−encodeUint8 :: forall m. (MonadEffect m) => UInt -> m ArrayBuffer
236−encodeUint8 x = do
237− buf <- liftEffect $ AB.empty 1
238− _ <- liftEffect $ DV.setUint8 (DV.whole buf) 0 x
239− pure buf
94+-- | Append a `DataView` to the builder.
95+putDataView :: forall m. Monad m => DataView -> PutM m Unit
96+putDataView = tell <<< Internal.singleton <<< Internal.View
24097
241−-- | Append an 8-bit unsigned integer (byte) to the builder.
242−putUint8 :: forall m. (MonadEffect m) => UInt -> PutM m Unit
243−putUint8 = putArrayBuffer <=< encodeUint8
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
244101
245−-- | Serialize an 8-bit two’s-complement signed integer (char) into a new `ArrayBuffer`.
246−encodeInt8 :: forall m. (MonadEffect m) => Int -> m ArrayBuffer
247−encodeInt8 x = do
248− buf <- liftEffect $ AB.empty 1
249− _ <- liftEffect $ DV.setInt8 (DV.whole buf) 0 x
250− pure buf
102+-- | Append an 8-bit unsigned integer (byte) to the builder.
103+putUint8 :: forall m. MonadEffect m => UInt -> PutM m Unit
104+putUint8 = putArrayBuffer <=< Internal.encodeUint8
251105
252106-- | Append an 8-bit two’s-complement signed integer (char) to the builder.
253−putInt8 :: forall m. (MonadEffect m) => Int -> PutM m Unit
254−putInt8 = putArrayBuffer <=< encodeInt8
255−
256−-- | Serialize a 16-bit big-endian unsigned integer into a new `ArrayBuffer`.
257−encodeUint16be :: forall m. (MonadEffect m) => UInt -> m ArrayBuffer
258−encodeUint16be x = do
259− buf <- liftEffect $ AB.empty 2
260− _ <- liftEffect $ DV.setUint16be (DV.whole buf) 0 x
261− pure buf
107+putInt8 :: forall m. MonadEffect m => Int -> PutM m Unit
108+putInt8 = putArrayBuffer <=< Internal.encodeInt8
262109
263110-- | Append a 16-bit big-endian unsigned integer to the builder.
264−putUint16be :: forall m. (MonadEffect m) => UInt -> PutM m Unit
265−putUint16be = putArrayBuffer <=< encodeUint16be
266−
267−-- | Serialize a 16-bit little-endian unsigned integer into a new `ArrayBuffer`.
268−encodeUint16le :: forall m. (MonadEffect m) => UInt -> m ArrayBuffer
269−encodeUint16le x = do
270− buf <- liftEffect $ AB.empty 2
271− _ <- liftEffect $ DV.setUint16le (DV.whole buf) 0 x
272− pure buf
111+putUint16be :: forall m. MonadEffect m => UInt -> PutM m Unit
112+putUint16be = putArrayBuffer <=< Internal.encodeUint16be
273113
274114-- | Append a 16-bit little-endian unsigned integer to the builder.
275−putUint16le :: forall m. (MonadEffect m) => UInt -> PutM m Unit
276−putUint16le = putArrayBuffer <=< encodeUint16le
277−
278−-- | Serialize a 16-bit big-endian two’s-complement signed integer into a new `ArrayBuffer`.
279−encodeInt16be :: forall m. (MonadEffect m) => Int -> m ArrayBuffer
280−encodeInt16be x = do
281− buf <- liftEffect $ AB.empty 2
282− _ <- liftEffect $ DV.setInt16be (DV.whole buf) 0 x
283− pure buf
115+putUint16le :: forall m. MonadEffect m => UInt -> PutM m Unit
116+putUint16le = putArrayBuffer <=< Internal.encodeUint16le
284117
285118-- | Append a 16-bit big-endian two’s-complement signed integer to the builder.
286−putInt16be :: forall m. (MonadEffect m) => Int -> PutM m Unit
287−putInt16be = putArrayBuffer <=< encodeInt16be
288−
289−-- | Serialize a 16-bit little-endian two’s-complement signed integer into a new `ArrayBuffer`.
290−encodeInt16le :: forall m. (MonadEffect m) => Int -> m ArrayBuffer
291−encodeInt16le x = do
292− buf <- liftEffect $ AB.empty 2
293− _ <- liftEffect $ DV.setInt16le (DV.whole buf) 0 x
294− pure buf
119+putInt16be :: forall m. MonadEffect m => Int -> PutM m Unit
120+putInt16be = putArrayBuffer <=< Internal.encodeInt16be
295121
296122-- | Append a 16-bit little-endian two’s-complement signed integer to the builder.
297−putInt16le :: forall m. (MonadEffect m) => Int -> PutM m Unit
298−putInt16le = putArrayBuffer <=< encodeInt16le
299−
300−-- | Serialize a 32-bit big-endian unsigned integer into a new `ArrayBuffer`.
301−encodeUint32be :: forall m. (MonadEffect m) => UInt -> m ArrayBuffer
302−encodeUint32be x = do
303− buf <- liftEffect $ AB.empty 4
304− _ <- liftEffect $ DV.setUint32be (DV.whole buf) 0 x
305− pure buf
123+putInt16le :: forall m. MonadEffect m => Int -> PutM m Unit
124+putInt16le = putArrayBuffer <=< Internal.encodeInt16le
306125
307126-- | Append a 32-bit big-endian unsigned integer to the builder.
308−putUint32be :: forall m. (MonadEffect m) => UInt -> PutM m Unit
309−putUint32be = putArrayBuffer <=< encodeUint32be
310−
311−-- | Serialize a 32-bit little-endian unsigned integer into a new `ArrayBuffer`.
312−encodeUint32le :: forall m. (MonadEffect m) => UInt -> m ArrayBuffer
313−encodeUint32le x = do
314− buf <- liftEffect $ AB.empty 4
315− _ <- liftEffect $ DV.setUint32le (DV.whole buf) 0 x
316− pure buf
127+putUint32be :: forall m. MonadEffect m => UInt -> PutM m Unit
128+putUint32be = putArrayBuffer <=< Internal.encodeUint32be
317129
318130-- | Append a 32-bit little-endian unsigned integer to the builder.
319−putUint32le :: forall m. (MonadEffect m) => UInt -> PutM m Unit
320−putUint32le = putArrayBuffer <=< encodeUint32le
321−
322−-- | Serialize a 32-bit big-endian two’s-complement signed integer into a new `ArrayBuffer`.
323−encodeInt32be :: forall m. (MonadEffect m) => Int -> m ArrayBuffer
324−encodeInt32be x = do
325− buf <- liftEffect $ AB.empty 4
326− _ <- liftEffect $ DV.setInt32be (DV.whole buf) 0 x
327− pure buf
131+putUint32le :: forall m. MonadEffect m => UInt -> PutM m Unit
132+putUint32le = putArrayBuffer <=< Internal.encodeUint32le
328133
329134-- | Append a 32-bit big-endian two’s-complement signed integer to the builder.
330−putInt32be :: forall m. (MonadEffect m) => Int -> PutM m Unit
331−putInt32be = putArrayBuffer <=< encodeInt32be
332−
333−-- | Serialize a 32-bit little-endian two’s-complement signed integer into a new `ArrayBuffer`.
334−encodeInt32le :: forall m. (MonadEffect m) => Int -> m ArrayBuffer
335−encodeInt32le x = do
336− buf <- liftEffect $ AB.empty 4
337− _ <- liftEffect $ DV.setInt32le (DV.whole buf) 0 x
338− pure buf
135+putInt32be :: forall m. MonadEffect m => Int -> PutM m Unit
136+putInt32be = putArrayBuffer <=< Internal.encodeInt32be
339137
340138-- | Append a 32-bit little-endian two’s-complement signed integer to the builder.
341−putInt32le :: forall m. (MonadEffect m) => Int -> PutM m Unit
342−putInt32le = putArrayBuffer <=< encodeInt32le
343−
344−-- | Serialize a 32-bit big-endian IEEE single-precision float into a new `ArrayBuffer`.
345−encodeFloat32be :: forall m. (MonadEffect m) => Float32 -> m ArrayBuffer
346−encodeFloat32be x = do
347− buf <- liftEffect $ AB.empty 4
348− _ <- liftEffect $ DV.setFloat32be (DV.whole buf) 0 x
349− pure buf
139+putInt32le :: forall m. MonadEffect m => Int -> PutM m Unit
140+putInt32le = putArrayBuffer <=< Internal.encodeInt32le
350141
351142-- | Append a 32-bit big-endian IEEE single-precision float to the builder.
352−putFloat32be :: forall m. (MonadEffect m) => Float32 -> PutM m Unit
353−putFloat32be = putArrayBuffer <=< encodeFloat32be
354−
355−-- | Serialize a 32-bit little-endian IEEE single-precision float into a new `ArrayBuffer`.
356−encodeFloat32le :: forall m. (MonadEffect m) => Float32 -> m ArrayBuffer
357−encodeFloat32le x = do
358− buf <- liftEffect $ AB.empty 4
359− _ <- liftEffect $ DV.setFloat32le (DV.whole buf) 0 x
360− pure buf
143+putFloat32be :: forall m. MonadEffect m => Float32 -> PutM m Unit
144+putFloat32be = putArrayBuffer <=< Internal.encodeFloat32be
361145
362146-- | Append a 32-bit little-endian IEEE single-precision float to the builder.
363−putFloat32le :: forall m. (MonadEffect m) => Float32 -> PutM m Unit
364−putFloat32le = putArrayBuffer <=< encodeFloat32le
365−
366−-- | Serialize a 64-bit big-endian IEEE double-precision float into a new `ArrayBuffer`.
367−encodeFloat64be :: forall m. (MonadEffect m) => Number -> m ArrayBuffer
368−encodeFloat64be x = do
369− buf <- liftEffect $ AB.empty 8
370− _ <- liftEffect $ DV.setFloat64be (DV.whole buf) 0 x
371− pure buf
147+putFloat32le :: forall m. MonadEffect m => Float32 -> PutM m Unit
148+putFloat32le = putArrayBuffer <=< Internal.encodeFloat32le
372149
373150-- | Append a 64-bit big-endian IEEE double-precision float to the builder.
374−putFloat64be :: forall m. (MonadEffect m) => Number -> PutM m Unit
375−putFloat64be = putArrayBuffer <=< encodeFloat64be
376−
377−-- | Serialize a 64-bit little-endian IEEE double-precision float into a new `ArrayBuffer`.
378−encodeFloat64le :: forall m. (MonadEffect m) => Number -> m ArrayBuffer
379−encodeFloat64le x = do
380− buf <- liftEffect $ AB.empty 8
381− _ <- liftEffect $ DV.setFloat64le (DV.whole buf) 0 x
382− pure buf
151+putFloat64be :: forall m. MonadEffect m => Number -> PutM m Unit
152+putFloat64be = putArrayBuffer <=< Internal.encodeFloat64be
383153
384154-- | Append a 64-bit little-endian IEEE double-precision float to the builder.
385−putFloat64le :: forall m. (MonadEffect m) => Number -> PutM m Unit
386−putFloat64le = putArrayBuffer <=< encodeFloat64le
387−
388−
389−-- | ## Implementation Details
390−-- |
391−-- | We want our `Builder` to be a data structure with
392−-- | * *O(1)* monoid append
393−-- | * *O(n)* fold
394−-- |
395−-- | Our `Builder` monoid implementation is an unbalanced binary tree.
396−-- |
397−-- | For monoid `append`, what we actually get is *O(1)* when either the
398−-- | left or right tree is a singleton. If that's not true, then in the
399−-- | unlikely worst case `append` might be *O(n)*.
400−-- |
401−-- | `Builder` is optimized what we consider to be normal usage, that is,
402−-- | `snoc`ing singleton elements to the end of the `Builder`.
403−-- |
404−-- | If a Builder is built entirely by `snoc`ing, it will look like a
405−-- | left-only binary tree, a.k.a. a linked list.
406−-- |
407−-- | ```
408−-- | ④
409−-- | ╱
410−-- | ③
411−-- | ╱
412−-- | ②
413−-- | ╱
414−-- | ①
415−-- | ```
416−-- |
417−-- | If two of these `snoc`-built trees are `append`ed, then the new tree
418−-- | will look like
419−-- |
420−-- | ```
421−-- | ④
422−-- | ╱ ╲
423−-- | ③ ⑧
424−-- | ╱ ╱
425−-- | ② ⑦
426−-- | ╱ ╱
427−-- | ① ⑥
428−-- | ╱
429−-- | ⑤
430−-- | ```
431−-- |
432−-- | This is all similar to
433−-- | [__bytestring-tree-builder__](https://hackage.haskell.org/package/bytestring-tree-builder)
434−-- | , except that the
435−-- | [`Tree`](https://hackage.haskell.org/package/bytestring-tree-builder-0.2.7.3/docs/src/ByteString.TreeBuilder.Tree.html#Tree)
436−-- | structure in __bytestring-tree-builder__ only carries values in its
437−-- | leaves, which is how it achieves *O(1)* appending, at the cost of
438−-- | a higher coefficient time factor on the fold.
439−-- |
440−-- | We hope that this implementation is fairly fast, but we
441−-- | haven't chosen this implementation because it's fast, we've chosen
442−-- | this implementation because it's simple. This library provides basic
443−-- | ArrayBuffer serialization with the familar “put monad” style.
444−-- | The only currently existing Purescript libary which does ArrayBuffer
445−-- | serialization is
446−-- | https://pursuit.purescript.org/packages/purescript-arraybuffer-class
447−-- | , and that library is heavily typeclass-based and designed
448−-- | for compatibility with the Haskell cereal library.
449−-- | If someone wants to create a fast Purescript ArrayBuffer serialization
450−-- | library, then they can benchmark against this one to prove that the new
451−-- | one is fast.
452−-- |
453−-- | One relatively cheap and simple performance improvement for this library would be to
454−-- | remove the Null constructor of `Builder` and instead use Javascript nulls.
155+putFloat64le :: forall m. MonadEffect m => Number -> PutM m Unit
156+putFloat64le = putArrayBuffer <=< Internal.encodeFloat64le