• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lehins / mempack / 1

06 Sep 2025 04:49PM UTC coverage: 86.262% (+0.3%) from 85.987%
1

push

github

web-flow
Merge f1c7cfad1 into 072e28fea

39 of 41 new or added lines in 2 files covered. (95.12%)

60 existing lines in 3 files now uncovered.

697 of 808 relevant lines covered (86.26%)

1.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.42
/src/Data/MemPack.hs
1
{-# LANGUAGE AllowAmbiguousTypes #-}
2
{-# LANGUAGE BangPatterns #-}
3
{-# LANGUAGE BinaryLiterals #-}
4
{-# LANGUAGE CPP #-}
5
{-# LANGUAGE DefaultSignatures #-}
6
{-# LANGUAGE FlexibleInstances #-}
7
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8
{-# LANGUAGE LambdaCase #-}
9
{-# LANGUAGE MagicHash #-}
10
{-# LANGUAGE MultiParamTypeClasses #-}
11
{-# LANGUAGE NumericUnderscores #-}
12
{-# LANGUAGE RankNTypes #-}
13
{-# LANGUAGE ScopedTypeVariables #-}
14
{-# LANGUAGE TypeApplications #-}
15
{-# LANGUAGE UnboxedTuples #-}
16

17
-- |
18
-- Module      : Data.MemPack
19
-- Copyright   : (c) Alexey Kuleshevich 2024-2025
20
-- License     : BSD3
21
-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
22
-- Stability   : experimental
23
-- Portability : non-portable
24
module Data.MemPack (
25
  Pack (..),
26
  Unpack (..),
27
  MemPack (..),
28

29
  -- * Packing
30
  pack,
31
  packByteString,
32
  packShortByteString,
33

34
  -- ** Generalized
35
  packByteArray,
36
  packWithByteArray,
37
  packMutableByteArray,
38
  packWithMutableByteArray,
39

40
  -- ** Helpers
41
  packIncrement,
42
  guardAdvanceUnpack,
43

44
  -- * Unpacking
45
  unpack,
46
  unpackFail,
47
  unpackMonadFail,
48
  unpackError,
49
  unpackLeftOver,
50

51
  -- ** Helpers
52
  failUnpack,
53
  unpackByteArray,
54
  unpackByteArrayLen,
55
  packByteStringM,
56
  unpackByteStringM,
57

58
  -- * Helper packers
59
  VarLen (..),
60
  Length (..),
61
  Tag (..),
62
  packTagM,
63
  unpackTagM,
64
  unknownTagM,
65
  packedTagByteCount,
66

67
  -- * Internal utilities
68
  replicateTailM,
69
  lift_#,
70
  st_,
71

72
  -- * Re-exports for @GeneralizedNewtypeDeriving@
73
  StateT (..),
74
  FailT (..),
75
) where
76

77
#include "MachDeps.h"
78

79
import Control.Applicative (Alternative (..))
80
import Control.Monad (join, unless, when)
81
import qualified Control.Monad.Fail as F
82
import Control.Monad.Reader (MonadReader (..), lift)
83
import Control.Monad.State.Strict (MonadState (..), StateT (..), execStateT)
84
import Control.Monad.Trans.Fail (Fail, FailT (..), errorFail, failT, runFailAgg)
85
import Data.Array.Byte (ByteArray (..), MutableByteArray (..))
86
import Data.Bifunctor (first)
87
import Data.Bits (Bits (..), FiniteBits (..))
88
import Data.ByteString (ByteString)
89
import qualified Data.ByteString.Lazy as BSL
90
import qualified Data.ByteString.Lazy.Internal as BSL
91
import Data.ByteString.Short (ShortByteString)
92
import Data.Char (ord)
93
import Data.Complex (Complex (..))
94
import Data.List (intercalate)
95
import Data.MemPack.Buffer
96
import Data.MemPack.Error
97
import Data.Primitive.Array (Array (..), arrayFromListN, sizeofArray)
98
import Data.Primitive.PrimArray (PrimArray (..), sizeofPrimArray)
99
import Data.Primitive.Types (Prim (sizeOf#))
100
import Data.Ratio
101
import Data.Semigroup (Sum (..))
102
#if MIN_VERSION_text(2,0,0)
103
import qualified Data.Text.Array as T
104
#endif
105
import qualified Data.Text.Encoding as T
106
import Data.Text.Internal (Text (..))
107
import Data.Typeable
108
import Data.Void (Void, absurd)
109
import GHC.Exts
110
import GHC.Int
111
import GHC.ST (ST (..), runST)
112
import GHC.Stable (StablePtr (..))
113
import GHC.Stack (HasCallStack)
114
import GHC.Word
115
import Numeric (showHex)
116
import Prelude hiding (fail)
117
#if __GLASGOW_HASKELL__ >= 900
118
import GHC.Num.Integer (Integer (..), integerCheck)
119
import GHC.Num.Natural (Natural (..), naturalCheck)
120
#elif defined(MIN_VERSION_integer_gmp)
121
import GHC.Integer.GMP.Internals (Integer (..), BigNat(BN#), isValidInteger#)
122
import GHC.Natural (Natural (..), isValidNatural)
123
#else
124
#error "Only integer-gmp is supported for now for older compilers"
125
#endif
126
#if !(MIN_VERSION_base(4,13,0))
127
import Prelude (fail)
128
#endif
129
#if !MIN_VERSION_primitive(0,8,0)
130
import qualified Data.Primitive.ByteArray as Prim (ByteArray(..))
131
#endif
132

133
-- | Monad that is used for serializing data into a `MutableByteArray`. It is based on
134
-- `StateT` that tracks the current index into the `MutableByteArray` where next write is
135
-- expected to happen.
136
newtype Pack s a = Pack
137
  { runPack :: MutableByteArray s -> StateT Int (ST s) a
2✔
138
  }
139

UNCOV
140
instance Functor (Pack s) where
×
141
  fmap f (Pack p) = Pack $ \buf -> fmap f (p buf)
×
142
  {-# INLINE fmap #-}
UNCOV
143
instance Applicative (Pack s) where
×
144
  pure = Pack . const . pure
2✔
145
  {-# INLINE pure #-}
UNCOV
146
  Pack a1 <*> Pack a2 =
×
147
    Pack $ \buf -> a1 buf <*> a2 buf
×
148
  {-# INLINE (<*>) #-}
UNCOV
149
  Pack a1 *> Pack a2 =
×
150
    Pack $ \buf -> a1 buf *> a2 buf
×
151
  {-# INLINE (*>) #-}
152
instance Monad (Pack s) where
2✔
153
  Pack m1 >>= p =
2✔
154
    Pack $ \buf -> m1 buf >>= \res -> runPack (p res) buf
2✔
155
  {-# INLINE (>>=) #-}
156
instance MonadReader (MutableByteArray s) (Pack s) where
157
  ask = Pack pure
2✔
158
  {-# INLINE ask #-}
UNCOV
159
  local f (Pack p) = Pack (p . f)
×
160
  {-# INLINE local #-}
UNCOV
161
  reader f = Pack (pure . f)
×
162
  {-# INLINE reader #-}
163
instance MonadState Int (Pack s) where
UNCOV
164
  get = Pack $ const get
×
165
  {-# INLINE get #-}
UNCOV
166
  put = Pack . const . put
×
167
  {-# INLINE put #-}
168
  state = Pack . const . state
2✔
169
  {-# INLINE state #-}
170

171
-- | Monad that is used for deserializing data from a memory `Buffer`. It is based on
172
-- `StateT` that tracks the current index into the @`Buffer` a@, from where the next read
173
-- suppose to happen. Unpacking can `F.fail` with `F.MonadFail` instance or with
174
-- `failUnpack` that provides a more type safe way of failing using `Error` interface.
175
newtype Unpack b a = Unpack
176
  { runUnpack :: b -> StateT Int (Fail SomeError) a
2✔
177
  }
178

UNCOV
179
instance Functor (Unpack s) where
×
180
  fmap f (Unpack p) = Unpack $ \buf -> fmap f (p buf)
2✔
181
  {-# INLINE fmap #-}
UNCOV
182
instance Applicative (Unpack b) where
×
183
  pure = Unpack . const . pure
2✔
184
  {-# INLINE pure #-}
185
  Unpack a1 <*> Unpack a2 =
2✔
186
    Unpack $ \buf -> a1 buf <*> a2 buf
1✔
187
  {-# INLINE (<*>) #-}
UNCOV
188
  Unpack a1 *> Unpack a2 =
×
189
    Unpack $ \buf -> a1 buf *> a2 buf
×
190
  {-# INLINE (*>) #-}
UNCOV
191
instance Monad (Unpack b) where
×
192
  Unpack m1 >>= p =
2✔
193
    Unpack $ \buf -> m1 buf >>= \res -> runUnpack (p res) buf
2✔
194
  {-# INLINE (>>=) #-}
195
#if !(MIN_VERSION_base(4,13,0))
196
  fail = Unpack . const . F.fail
197
#endif
198
instance F.MonadFail (Unpack b) where
199
  fail = Unpack . const . F.fail
2✔
200
instance MonadReader b (Unpack b) where
201
  ask = Unpack pure
2✔
202
  {-# INLINE ask #-}
UNCOV
203
  local f (Unpack p) = Unpack (p . f)
×
204
  {-# INLINE local #-}
UNCOV
205
  reader f = Unpack (pure . f)
×
206
  {-# INLINE reader #-}
207
instance MonadState Int (Unpack b) where
UNCOV
208
  get = Unpack $ const get
×
209
  {-# INLINE get #-}
UNCOV
210
  put = Unpack . const . put
×
211
  {-# INLINE put #-}
212
  state = Unpack . const . state
2✔
213
  {-# INLINE state #-}
214

UNCOV
215
instance Alternative (Unpack b) where
×
216
  empty = Unpack $ \_ -> lift empty
×
217
  {-# INLINE empty #-}
218
  Unpack r1 <|> Unpack r2 =
2✔
219
    Unpack $ \buf ->
2✔
220
      case r1 buf of
2✔
221
        StateT m1 ->
222
          case r2 buf of
2✔
223
            StateT m2 -> StateT $ \s -> m1 s <|> m2 s
2✔
224
  {-# INLINE (<|>) #-}
225

226
-- | Failing unpacking with an `Error`.
227
failUnpack :: Error e => e -> Unpack b a
228
failUnpack e = Unpack $ \_ -> lift $ failT (toSomeError e)
2✔
229

230
-- | Efficient serialization interface that operates directly on memory buffers.
231
class MemPack a where
232
  -- | Name of the type that is being deserialized for error reporting. Default
233
  -- implementation relies on `Typeable`.
234
  typeName :: String
235
  default typeName :: Typeable a => String
236
  typeName = show (typeRep (Proxy @a))
1✔
237

238
  -- | Report the exact size in number of bytes that packed version of this type will
239
  -- occupy. It is very important to get this right, otherwise `packM` will result in a
240
  -- runtime exception. Another words this is the expected property that it should hold:
241
  --
242
  -- prop> packedByteCount a == bufferByteCount (pack a)
243
  packedByteCount :: a -> Int
244

245
  -- | Write binary representation of a type into the `MutableByteArray` which can be
246
  -- accessed with `ask`, whenever direct operations on it are necessary.
247
  packM :: a -> Pack s ()
248

249
  -- | Read binary representation of the type directly from the buffer, which can be
250
  -- accessed with `ask` when necessary. Direct reads from the buffer should be preceded
251
  -- with advancing the buffer offset with `MonadState` by the number of bytes that will
252
  -- be consumed from the buffer and making sure that no reads outside of the buffer can
253
  -- happen. Violation of these rules will lead to segfaults.
254
  unpackM :: Buffer b => Unpack b a
255

UNCOV
256
instance MemPack () where
×
257
  packedByteCount _ = 0
2✔
258
  {-# INLINE packedByteCount #-}
259
  packM () = pure ()
1✔
260
  {-# INLINE packM #-}
261
  unpackM = pure ()
2✔
262
  {-# INLINE unpackM #-}
263

UNCOV
264
instance MemPack Void where
×
265
  packedByteCount _ = 0
×
266
  packM = absurd
×
267
  unpackM = F.fail "Void is unpackable"
×
268

269
instance MemPack Bool where
2✔
270
  packedByteCount _ = packedTagByteCount
2✔
271
  {-# INLINE packedByteCount #-}
272
  packM x = packTagM $ if x then 1 else 0
2✔
273
  {-# INLINE packM #-}
274
  unpackM =
2✔
275
    unpackTagM >>= \case
2✔
276
      0 -> pure False
2✔
277
      1 -> pure True
2✔
UNCOV
278
      n -> F.fail $ "Invalid value detected for Bool: " ++ show n
×
279
  {-# INLINE unpackM #-}
280

281
instance MemPack a => MemPack (Maybe a) where
282
  typeName = "Maybe " ++ typeName @a
2✔
283
  packedByteCount = \case
2✔
284
    Nothing -> packedTagByteCount
2✔
285
    Just a -> packedTagByteCount + packedByteCount a
2✔
286
  {-# INLINE packedByteCount #-}
287
  packM = \case
2✔
288
    Nothing -> packTagM 0
2✔
289
    Just a -> packTagM 1 >> packM a
2✔
290
  {-# INLINE packM #-}
291
  unpackM =
2✔
292
    unpackTagM >>= \case
2✔
293
      0 -> pure Nothing
2✔
294
      1 -> Just <$> unpackM
2✔
UNCOV
295
      n -> unknownTagM @(Maybe a) n
×
296
  {-# INLINE unpackM #-}
297

298
instance (MemPack a, MemPack b) => MemPack (Either a b) where
299
  typeName = "Either " ++ typeName @a ++ " " ++ typeName @b
2✔
300
  packedByteCount = \case
2✔
301
    Left a -> packedTagByteCount + packedByteCount a
1✔
302
    Right b -> packedTagByteCount + packedByteCount b
1✔
303
  {-# INLINE packedByteCount #-}
304
  packM = \case
2✔
305
    Left a -> packTagM 0 >> packM a
2✔
306
    Right b -> packTagM 1 >> packM b
2✔
307
  {-# INLINE packM #-}
308
  unpackM =
2✔
309
    unpackTagM >>= \case
2✔
310
      0 -> Left <$> unpackM
2✔
311
      1 -> Right <$> unpackM
2✔
UNCOV
312
      n -> unknownTagM @(Either a b) n
×
313
  {-# INLINE unpackM #-}
314

315
instance MemPack Char where
2✔
316
  packedByteCount _ = SIZEOF_HSCHAR
2✔
317
  {-# INLINE packedByteCount #-}
318
  packM a@(C# a#) = do
2✔
319
    MutableByteArray mba# <- ask
2✔
320
    I# i# <- packIncrement a
1✔
321
    lift_# (writeWord8ArrayAsWideChar# mba# i# a#)
2✔
322
  {-# INLINE packM #-}
323
  unpackM = do
2✔
324
    I# i# <- guardAdvanceUnpack SIZEOF_HSCHAR
2✔
325
    buf <- ask
2✔
326
    let c =
2✔
327
          buffer
2✔
328
            buf
2✔
329
            (\ba# off# -> C# (indexWord8ArrayAsWideChar# ba# (i# +# off#)))
2✔
330
            (\addr# -> C# (indexWideCharOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
331
        ordc :: Word32
332
        ordc = fromIntegral (ord c)
2✔
333
    when (ordc > 0x10FFFF) $
2✔
334
      F.fail $
2✔
UNCOV
335
        "Out of bounds Char was detected: '\\x" ++ showHex ordc "'"
×
336
    pure c
2✔
337
  {-# INLINE unpackM #-}
338

339
instance MemPack Float where
2✔
340
  packedByteCount _ = SIZEOF_FLOAT
2✔
341
  {-# INLINE packedByteCount #-}
342
  packM a@(F# a#) = do
2✔
343
    MutableByteArray mba# <- ask
2✔
344
    I# i# <- packIncrement a
1✔
345
    lift_# (writeWord8ArrayAsFloat# mba# i# a#)
2✔
346
  {-# INLINE packM #-}
347
  unpackM = do
2✔
348
    I# i# <- guardAdvanceUnpack SIZEOF_FLOAT
2✔
349
    buf <- ask
2✔
350
    pure $!
2✔
351
      buffer
2✔
352
        buf
2✔
353
        (\ba# off# -> F# (indexWord8ArrayAsFloat# ba# (i# +# off#)))
2✔
354
        (\addr# -> F# (indexFloatOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
355
  {-# INLINE unpackM #-}
356

357
instance MemPack Double where
2✔
358
  packedByteCount _ = SIZEOF_DOUBLE
2✔
359
  {-# INLINE packedByteCount #-}
360
  packM a@(D# a#) = do
2✔
361
    MutableByteArray mba# <- ask
2✔
362
    I# i# <- packIncrement a
1✔
363
    lift_# (writeWord8ArrayAsDouble# mba# i# a#)
2✔
364
  {-# INLINE packM #-}
365
  unpackM = do
2✔
366
    I# i# <- guardAdvanceUnpack SIZEOF_DOUBLE
2✔
367
    buf <- ask
2✔
368
    pure $!
2✔
369
      buffer
2✔
370
        buf
2✔
371
        (\ba# off# -> D# (indexWord8ArrayAsDouble# ba# (i# +# off#)))
2✔
372
        (\addr# -> D# (indexDoubleOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
373
  {-# INLINE unpackM #-}
374

375
instance MemPack (Ptr a) where
376
  typeName = "Ptr"
2✔
377
  packedByteCount _ = SIZEOF_HSPTR
2✔
378
  {-# INLINE packedByteCount #-}
379
  packM a@(Ptr a#) = do
2✔
380
    MutableByteArray mba# <- ask
2✔
381
    I# i# <- packIncrement a
1✔
382
    lift_# (writeWord8ArrayAsAddr# mba# i# a#)
2✔
383
  {-# INLINE packM #-}
384
  unpackM = do
2✔
385
    I# i# <- guardAdvanceUnpack SIZEOF_HSPTR
2✔
386
    buf <- ask
2✔
387
    pure $!
2✔
388
      buffer
2✔
389
        buf
2✔
390
        (\ba# off# -> Ptr (indexWord8ArrayAsAddr# ba# (i# +# off#)))
2✔
391
        (\addr# -> Ptr (indexAddrOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
392
  {-# INLINE unpackM #-}
393

394
instance MemPack (StablePtr a) where
395
  typeName = "StablePtr"
2✔
396
  packedByteCount _ = SIZEOF_HSSTABLEPTR
2✔
397
  {-# INLINE packedByteCount #-}
398
  packM a@(StablePtr a#) = do
2✔
399
    MutableByteArray mba# <- ask
2✔
400
    I# i# <- packIncrement a
1✔
401
    lift_# (writeWord8ArrayAsStablePtr# mba# i# a#)
2✔
402
  {-# INLINE packM #-}
403
  unpackM = do
2✔
404
    I# i# <- guardAdvanceUnpack SIZEOF_HSSTABLEPTR
2✔
405
    buf <- ask
2✔
406
    pure $!
2✔
407
      buffer
2✔
408
        buf
2✔
409
        (\ba# off# -> StablePtr (indexWord8ArrayAsStablePtr# ba# (i# +# off#)))
2✔
410
        (\addr# -> StablePtr (indexStablePtrOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
411
  {-# INLINE unpackM #-}
412

413
instance MemPack Int where
2✔
414
  packedByteCount _ = SIZEOF_HSINT
2✔
415
  {-# INLINE packedByteCount #-}
416
  packM a@(I# a#) = do
2✔
417
    MutableByteArray mba# <- ask
2✔
418
    I# i# <- packIncrement a
1✔
419
    lift_# (writeWord8ArrayAsInt# mba# i# a#)
2✔
420
  {-# INLINE packM #-}
421
  unpackM = do
2✔
422
    I# i# <- guardAdvanceUnpack SIZEOF_HSINT
2✔
423
    buf <- ask
2✔
424
    pure $!
2✔
425
      buffer
2✔
426
        buf
2✔
427
        (\ba# off# -> I# (indexWord8ArrayAsInt# ba# (i# +# off#)))
2✔
428
        (\addr# -> I# (indexIntOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
429
  {-# INLINE unpackM #-}
430

431
instance MemPack Int8 where
2✔
432
  packedByteCount _ = SIZEOF_INT8
2✔
433
  {-# INLINE packedByteCount #-}
434
  packM a@(I8# a#) = do
2✔
435
    MutableByteArray mba# <- ask
2✔
436
    I# i# <- packIncrement a
1✔
437
    lift_# (writeInt8Array# mba# i# a#)
2✔
438
  {-# INLINE packM #-}
439
  unpackM = do
2✔
440
    I# i# <- guardAdvanceUnpack SIZEOF_INT8
2✔
441
    buf <- ask
2✔
442
    pure $!
2✔
443
      buffer
2✔
444
        buf
2✔
445
        (\ba# off# -> I8# (indexInt8Array# ba# (i# +# off#)))
2✔
446
        (\addr# -> I8# (indexInt8OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
447
  {-# INLINE unpackM #-}
448

449
instance MemPack Int16 where
2✔
450
  packedByteCount _ = SIZEOF_INT16
2✔
451
  {-# INLINE packedByteCount #-}
452
  packM a@(I16# a#) = do
2✔
453
    MutableByteArray mba# <- ask
2✔
454
    I# i# <- packIncrement a
1✔
455
    lift_# (writeWord8ArrayAsInt16# mba# i# a#)
2✔
456
  {-# INLINE packM #-}
457
  unpackM = do
2✔
458
    buf <- ask
2✔
459
    I# i# <- guardAdvanceUnpack SIZEOF_INT16
2✔
460
    pure $!
2✔
461
      buffer
2✔
462
        buf
2✔
463
        (\ba# off# -> I16# (indexWord8ArrayAsInt16# ba# (i# +# off#)))
2✔
464
        (\addr# -> I16# (indexInt16OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
465
  {-# INLINE unpackM #-}
466

467
instance MemPack Int32 where
2✔
468
  packedByteCount _ = SIZEOF_INT32
2✔
469
  {-# INLINE packedByteCount #-}
470
  packM a@(I32# a#) = do
2✔
471
    MutableByteArray mba# <- ask
2✔
472
    I# i# <- packIncrement a
1✔
473
    lift_# (writeWord8ArrayAsInt32# mba# i# a#)
2✔
474
  {-# INLINE packM #-}
475
  unpackM = do
2✔
476
    buf <- ask
2✔
477
    I# i# <- guardAdvanceUnpack SIZEOF_INT32
2✔
478
    pure $!
2✔
479
      buffer
2✔
480
        buf
2✔
481
        (\ba# off# -> I32# (indexWord8ArrayAsInt32# ba# (i# +# off#)))
2✔
482
        (\addr# -> I32# (indexInt32OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
483
  {-# INLINE unpackM #-}
484

485
instance MemPack Int64 where
2✔
486
  packedByteCount _ = SIZEOF_INT64
2✔
487
  {-# INLINE packedByteCount #-}
488
  packM a@(I64# a#) = do
2✔
489
    MutableByteArray mba# <- ask
2✔
490
    I# i# <- packIncrement a
1✔
491
    lift_# (writeWord8ArrayAsInt64# mba# i# a#)
2✔
492
  {-# INLINE packM #-}
493
  unpackM = do
2✔
494
    buf <- ask
2✔
495
    I# i# <- guardAdvanceUnpack SIZEOF_INT64
2✔
496
    pure $!
2✔
497
      buffer
2✔
498
        buf
2✔
499
        (\ba# off# -> I64# (indexWord8ArrayAsInt64# ba# (i# +# off#)))
2✔
500
        (\addr# -> I64# (indexInt64OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
501
  {-# INLINE unpackM #-}
502

503
instance MemPack Word where
2✔
504
  packedByteCount _ = SIZEOF_HSWORD
2✔
505
  {-# INLINE packedByteCount #-}
506
  packM a@(W# a#) = do
2✔
507
    MutableByteArray mba# <- ask
2✔
508
    I# i# <- packIncrement a
1✔
509
    lift_# (writeWord8ArrayAsWord# mba# i# a#)
2✔
510
  {-# INLINE packM #-}
511
  unpackM = do
2✔
512
    I# i# <- guardAdvanceUnpack SIZEOF_HSWORD
2✔
513
    buf <- ask
2✔
514
    pure $!
2✔
515
      buffer
2✔
516
        buf
2✔
517
        (\ba# off# -> W# (indexWord8ArrayAsWord# ba# (i# +# off#)))
2✔
518
        (\addr# -> W# (indexWordOffAddr# (addr# `plusAddr#` i#) 0#))
2✔
519
  {-# INLINE unpackM #-}
520

521
instance MemPack Word8 where
2✔
522
  packedByteCount _ = SIZEOF_WORD8
2✔
523
  {-# INLINE packedByteCount #-}
524
  packM a@(W8# a#) = do
2✔
525
    MutableByteArray mba# <- ask
2✔
526
    I# i# <- packIncrement a
1✔
527
    lift_# (writeWord8Array# mba# i# a#)
2✔
528
  {-# INLINE packM #-}
529
  unpackM = do
2✔
530
    I# i# <- guardAdvanceUnpack SIZEOF_WORD8
2✔
531
    buf <- ask
2✔
532
    pure $!
2✔
533
      buffer
2✔
534
        buf
2✔
535
        (\ba# off# -> W8# (indexWord8Array# ba# (i# +# off#)))
2✔
536
        (\addr# -> W8# (indexWord8OffAddr# addr# i#))
2✔
537
  {-# INLINE unpackM #-}
538

539
instance MemPack Word16 where
2✔
540
  packedByteCount _ = SIZEOF_WORD16
2✔
541
  {-# INLINE packedByteCount #-}
542
  packM a@(W16# a#) = do
2✔
543
    MutableByteArray mba# <- ask
2✔
544
    I# i# <- packIncrement a
1✔
545
    lift_# (writeWord8ArrayAsWord16# mba# i# a#)
2✔
546
  {-# INLINE packM #-}
547
  unpackM = do
2✔
548
    buf <- ask
2✔
549
    I# i# <- guardAdvanceUnpack SIZEOF_WORD16
2✔
550
    pure $!
2✔
551
      buffer
2✔
552
        buf
2✔
553
        (\ba# off# -> W16# (indexWord8ArrayAsWord16# ba# (i# +# off#)))
2✔
554
        (\addr# -> W16# (indexWord16OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
555
  {-# INLINE unpackM #-}
556

557
instance MemPack Word32 where
2✔
558
  packedByteCount _ = SIZEOF_WORD32
2✔
559
  {-# INLINE packedByteCount #-}
560
  packM a@(W32# a#) = do
2✔
561
    MutableByteArray mba# <- ask
2✔
562
    I# i# <- packIncrement a
1✔
563
    lift_# (writeWord8ArrayAsWord32# mba# i# a#)
2✔
564
  {-# INLINE packM #-}
565
  unpackM = do
2✔
566
    I# i# <- guardAdvanceUnpack SIZEOF_WORD32
2✔
567
    buf <- ask
2✔
568
    pure $!
2✔
569
      buffer
2✔
570
        buf
2✔
571
        (\ba# off# -> W32# (indexWord8ArrayAsWord32# ba# (i# +# off#)))
2✔
572
        (\addr# -> W32# (indexWord32OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
573
  {-# INLINE unpackM #-}
574

575
instance MemPack Word64 where
2✔
576
  packedByteCount _ = SIZEOF_WORD64
2✔
577
  {-# INLINE packedByteCount #-}
578
  packM a@(W64# a#) = do
2✔
579
    MutableByteArray mba# <- ask
2✔
580
    I# i# <- packIncrement a
1✔
581
    lift_# (writeWord8ArrayAsWord64# mba# i# a#)
2✔
582
  {-# INLINE packM #-}
583
  unpackM = do
2✔
584
    I# i# <- guardAdvanceUnpack SIZEOF_WORD64
2✔
585
    buf <- ask
2✔
586
    pure $!
2✔
587
      buffer
2✔
588
        buf
2✔
589
        (\ba# off# -> W64# (indexWord8ArrayAsWord64# ba# (i# +# off#)))
2✔
590
        (\addr# -> W64# (indexWord64OffAddr# (addr# `plusAddr#` i#) 0#))
2✔
591
  {-# INLINE unpackM #-}
592

593
#if __GLASGOW_HASKELL__ >= 900
594
instance MemPack Integer where
2✔
595
  packedByteCount =
2✔
596
    (+ packedTagByteCount) . \case
2✔
597
      IS i# -> packedByteCount (I# i#)
1✔
598
      IP ba# -> packedByteCount (ByteArray ba#)
2✔
599
      IN ba# -> packedByteCount (ByteArray ba#)
2✔
600
  {-# INLINE packedByteCount #-}
601
  packM = \case
2✔
602
    IS i# -> packTagM 0 >> packM (I# i#)
2✔
603
    IP ba# -> packTagM 1 >> packM (ByteArray ba#)
2✔
604
    IN ba# -> packTagM 2 >> packM (ByteArray ba#)
2✔
605
  {-# INLINE packM #-}
606
  unpackM = do
2✔
607
    i <-
608
      unpackTagM >>= \case
2✔
609
        0 -> do
2✔
610
          I# i# <- unpackM
2✔
611
          pure $ IS i#
2✔
612
        1 -> do
2✔
613
          ByteArray ba# <- unpackM
2✔
614
          pure $ IP ba#
2✔
615
        2 -> do
2✔
616
          ByteArray ba# <- unpackM
2✔
617
          pure $ IN ba#
2✔
UNCOV
618
        t -> unknownTagM @Integer t
×
619
    unless (integerCheck i) $ F.fail $ "Invalid Integer decoded " ++ showInteger i
1✔
620
    pure i
2✔
621
    where
UNCOV
622
      showInteger = \case
×
623
        IS i# -> "IS " ++ show (I# i#)
×
624
        IP ba# -> "IP " ++ show (ByteArray ba#)
×
625
        IN ba# -> "IN " ++ show (ByteArray ba#)
×
626
  {-# INLINE unpackM #-}
627

628
instance MemPack Natural where
2✔
629
  packedByteCount =
2✔
630
    (+ packedTagByteCount) . \case
2✔
631
      NS w# -> packedByteCount (W# w#)
1✔
632
      NB ba# -> packedByteCount (ByteArray ba#)
2✔
633
  {-# INLINE packedByteCount #-}
634
  packM = \case
2✔
635
    NS w# -> packTagM 0 >> packM (W# w#)
2✔
636
    NB ba# -> packTagM 1 >> packM (ByteArray ba#)
2✔
637
  {-# INLINE packM #-}
638
  unpackM = do
2✔
639
    n <-
640
      unpackTagM >>= \case
2✔
641
        0 -> do
2✔
642
          W# w# <- unpackM
2✔
643
          pure $ NS w#
2✔
644
        1 -> do
2✔
645
          ByteArray ba# <- unpackM
2✔
646
          pure $ NB ba#
2✔
UNCOV
647
        t -> unknownTagM @Natural t
×
648
    unless (naturalCheck n) $ F.fail $ "Invalid Natural decoded " ++ showNatural n
1✔
649
    pure n
2✔
650
    where
UNCOV
651
      showNatural = \case
×
652
        NS w# -> "NS " ++ show (W# w#)
×
653
        NB ba# -> "NB " ++ show (ByteArray ba#)
×
654
  {-# INLINE unpackM #-}
655

656
#elif defined(MIN_VERSION_integer_gmp)
657

658
instance MemPack Integer where
659
  packedByteCount =
660
    (+ packedTagByteCount) . \case
661
      S# i# -> packedByteCount (I# i#)
662
      Jp# (BN# ba#) -> packedByteCount (ByteArray ba#)
663
      Jn# (BN# ba#) -> packedByteCount (ByteArray ba#)
664
  {-# INLINE packedByteCount #-}
665
  packM = \case
666
    S# i# -> packTagM 0 >> packM (I# i#)
667
    Jp# (BN# ba#) -> packTagM 1 >> packM (ByteArray ba#)
668
    Jn# (BN# ba#) -> packTagM 2 >> packM (ByteArray ba#)
669
  {-# INLINE packM #-}
670
  unpackM = do
671
    i <-
672
      unpackTagM >>= \case
673
        0 -> do
674
          I# i# <- unpackM
675
          pure $ S# i#
676
        1 -> do
677
          ByteArray ba# <- unpackM
678
          pure $ Jp# (BN# ba#)
679
        2 -> do
680
          ByteArray ba# <- unpackM
681
          pure $ Jn# (BN# ba#)
682
        t -> unknownTagM @Integer t
683
    unless (isTrue# (isValidInteger# i)) $ F.fail $ "Invalid Integer decoded " ++ showInteger i
684
    pure i
685
    where
686
      showInteger = \case
687
        S# i# -> "S# " ++ show (I# i#)
688
        Jp# (BN# ba#) -> "Jp# " ++ show (ByteArray ba#)
689
        Jn# (BN# ba#) -> "Jn# " ++ show (ByteArray ba#)
690
  {-# INLINE unpackM #-}
691

692
instance MemPack Natural where
693
  packedByteCount =
694
    (+ packedTagByteCount) . \case
695
      NatS# w# -> packedByteCount (W# w#)
696
      NatJ# (BN# ba#) -> packedByteCount (ByteArray ba#)
697
  {-# INLINE packedByteCount #-}
698
  packM = \case
699
    NatS# w# -> packTagM 0 >> packM (W# w#)
700
    NatJ# (BN# ba#) -> packTagM 1 >> packM (ByteArray ba#)
701
  {-# INLINE packM #-}
702
  unpackM = do
703
    n <-
704
      unpackTagM >>= \case
705
        0 -> do
706
          W# w# <- unpackM
707
          pure $ NatS# w#
708
        1 -> do
709
          ByteArray ba# <- unpackM
710
          pure $ NatJ# (BN# ba#)
711
        t -> unknownTagM @Natural t
712
    unless (isValidNatural n) $ F.fail $ "Invalid Natural decoded " ++ showNatural n
713
    pure n
714
    where
715
      showNatural = \case
716
        NatS# w# -> "NatS# " ++ show (W# w#)
717
        NatJ# (BN#  ba#) -> "NatJ# " ++ show (ByteArray ba#)
718
  {-# INLINE unpackM #-}
719

720
#endif
721

722
instance MemPack a => MemPack (Complex a) where
723
  typeName = "Complex " ++ typeName @a
2✔
724
  packedByteCount (a :+ b) = packedByteCount a + packedByteCount b
1✔
725
  {-# INLINE packedByteCount #-}
726
  packM (a :+ b) = packM a >> packM b
2✔
727
  {-# INLINE packM #-}
728
  unpackM = do
2✔
729
    !a <- unpackM
2✔
730
    !b <- unpackM
2✔
731
    pure (a :+ b)
2✔
732
  {-# INLINE unpackM #-}
733

734
instance (MemPack a, Integral a) => MemPack (Ratio a) where
735
  typeName = "Ratio " ++ typeName @a
2✔
736
  packedByteCount r = packedByteCount (numerator r) + packedByteCount (denominator r)
1✔
737
  {-# INLINE packedByteCount #-}
738
  packM r = packM (numerator r) >> packM (denominator r)
2✔
739
  {-# INLINE packM #-}
740
  unpackM = do
2✔
741
    !a <- unpackM
2✔
742
    !b <- unpackM
2✔
743
    when (b == 0) $ F.fail $ "Zero denominator was detected when unpacking " ++ typeName @(Ratio a)
1✔
744
    pure (a % b)
2✔
745
  {-# INLINE unpackM #-}
746

747
instance (MemPack a, MemPack b) => MemPack (a, b) where
748
  typeName = "(" ++ typeName @a ++ "," ++ typeName @b ++ ")"
2✔
749
  packedByteCount (a, b) = packedByteCount a + packedByteCount b
1✔
750
  {-# INLINE packedByteCount #-}
751
  packM (a, b) = packM a >> packM b
2✔
752
  {-# INLINEABLE packM #-}
753
  unpackM = do
2✔
754
    !a <- unpackM
2✔
755
    !b <- unpackM
2✔
756
    pure (a, b)
2✔
757
  {-# INLINEABLE unpackM #-}
758

759
instance (MemPack a, MemPack b, MemPack c) => MemPack (a, b, c) where
760
  typeName = "(" ++ typeName @a ++ "," ++ typeName @b ++ "," ++ typeName @c ++ ")"
2✔
761
  packedByteCount (a, b, c) = packedByteCount a + packedByteCount b + packedByteCount c
1✔
762
  {-# INLINE packedByteCount #-}
763
  packM (a, b, c) = packM a >> packM b >> packM c
2✔
764
  {-# INLINEABLE packM #-}
765
  unpackM = do
2✔
766
    !a <- unpackM
2✔
767
    !b <- unpackM
2✔
768
    !c <- unpackM
2✔
769
    pure (a, b, c)
2✔
770
  {-# INLINEABLE unpackM #-}
771

772
instance (MemPack a, MemPack b, MemPack c, MemPack d) => MemPack (a, b, c, d) where
773
  typeName = "(" ++ typeName @a ++ "," ++ typeName @b ++ "," ++ typeName @c ++ "," ++ typeName @d ++ ")"
2✔
774
  packedByteCount (a, b, c, d) = packedByteCount a + packedByteCount b + packedByteCount c + packedByteCount d
1✔
775
  {-# INLINE packedByteCount #-}
776
  packM (a, b, c, d) =
2✔
777
    packM a >> packM b >> packM c >> packM d
2✔
778
  {-# INLINEABLE packM #-}
779
  unpackM = do
2✔
780
    !a <- unpackM
2✔
781
    !b <- unpackM
2✔
782
    !c <- unpackM
2✔
783
    !d <- unpackM
2✔
784
    pure (a, b, c, d)
2✔
785
  {-# INLINEABLE unpackM #-}
786

787
instance (MemPack a, MemPack b, MemPack c, MemPack d, MemPack e) => MemPack (a, b, c, d, e) where
788
  typeName =
2✔
789
    "("
2✔
790
      ++ intercalate
2✔
791
        ","
2✔
792
        [ typeName @a
2✔
793
        , typeName @b
2✔
794
        , typeName @c
2✔
795
        , typeName @d
2✔
796
        , typeName @e
2✔
797
        ]
798
      ++ ")"
2✔
799
  packedByteCount (a, b, c, d, e) =
2✔
800
    packedByteCount a + packedByteCount b + packedByteCount c + packedByteCount d + packedByteCount e
1✔
801
  {-# INLINE packedByteCount #-}
802
  packM (a, b, c, d, e) =
2✔
803
    packM a >> packM b >> packM c >> packM d >> packM e
2✔
804
  {-# INLINEABLE packM #-}
805
  unpackM = do
2✔
806
    !a <- unpackM
2✔
807
    !b <- unpackM
2✔
808
    !c <- unpackM
2✔
809
    !d <- unpackM
2✔
810
    !e <- unpackM
2✔
811
    pure (a, b, c, d, e)
2✔
812
  {-# INLINEABLE unpackM #-}
813

814
instance (MemPack a, MemPack b, MemPack c, MemPack d, MemPack e, MemPack f) => MemPack (a, b, c, d, e, f) where
815
  typeName =
2✔
816
    "("
2✔
817
      ++ intercalate
2✔
818
        ","
2✔
819
        [ typeName @a
2✔
820
        , typeName @b
2✔
821
        , typeName @c
2✔
822
        , typeName @d
2✔
823
        , typeName @e
2✔
824
        , typeName @f
2✔
825
        ]
826
      ++ ")"
2✔
827
  packedByteCount (a, b, c, d, e, f) =
2✔
828
    packedByteCount a
1✔
829
      + packedByteCount b
1✔
830
      + packedByteCount c
2✔
831
      + packedByteCount d
2✔
832
      + packedByteCount e
1✔
833
      + packedByteCount f
2✔
834
  {-# INLINE packedByteCount #-}
835
  packM (a, b, c, d, e, f) =
2✔
836
    packM a >> packM b >> packM c >> packM d >> packM e >> packM f
2✔
837
  {-# INLINEABLE packM #-}
838
  unpackM = do
2✔
839
    !a <- unpackM
2✔
840
    !b <- unpackM
2✔
841
    !c <- unpackM
2✔
842
    !d <- unpackM
2✔
843
    !e <- unpackM
2✔
844
    !f <- unpackM
2✔
845
    pure (a, b, c, d, e, f)
2✔
846
  {-# INLINEABLE unpackM #-}
847

848
instance
849
  (MemPack a, MemPack b, MemPack c, MemPack d, MemPack e, MemPack f, MemPack g) =>
850
  MemPack (a, b, c, d, e, f, g)
851
  where
852
  typeName =
2✔
853
    "("
2✔
854
      ++ intercalate
2✔
855
        ","
2✔
856
        [ typeName @a
2✔
857
        , typeName @b
2✔
858
        , typeName @c
2✔
859
        , typeName @d
2✔
860
        , typeName @e
2✔
861
        , typeName @f
2✔
862
        , typeName @g
2✔
863
        ]
864
      ++ ")"
2✔
865
  packedByteCount (a, b, c, d, e, f, g) =
2✔
866
    packedByteCount a
1✔
867
      + packedByteCount b
1✔
868
      + packedByteCount c
1✔
869
      + packedByteCount d
1✔
870
      + packedByteCount e
1✔
871
      + packedByteCount f
1✔
872
      + packedByteCount g
2✔
873
  {-# INLINE packedByteCount #-}
874
  packM (a, b, c, d, e, f, g) =
2✔
875
    packM a >> packM b >> packM c >> packM d >> packM e >> packM f >> packM g
2✔
876
  {-# INLINEABLE packM #-}
877
  unpackM = do
2✔
878
    !a <- unpackM
2✔
879
    !b <- unpackM
2✔
880
    !c <- unpackM
2✔
881
    !d <- unpackM
2✔
882
    !e <- unpackM
2✔
883
    !f <- unpackM
2✔
884
    !g <- unpackM
2✔
885
    pure (a, b, c, d, e, f, g)
2✔
886
  {-# INLINEABLE unpackM #-}
887

888
instance MemPack a => MemPack [a] where
889
  typeName = "[" ++ typeName @a ++ "]"
2✔
890
  packedByteCount es = packedByteCount (Length (length es)) + getSum (foldMap (Sum . packedByteCount) es)
2✔
891
  {-# INLINE packedByteCount #-}
892
  packM as = do
2✔
893
    packM (Length (length as))
2✔
894
    mapM_ packM as
2✔
895
  {-# INLINE packM #-}
896
  unpackM = do
2✔
897
    Length n <- unpackM
2✔
898
    replicateTailM n unpackM
2✔
899
  {-# INLINE unpackM #-}
900

901
instance MemPack a => MemPack (Array a) where
902
  typeName = "(Array " ++ typeName @a ++ ")"
2✔
903
  packedByteCount arr =
2✔
904
    packedByteCount (Length (sizeofArray arr)) + getSum (foldMap (Sum . packedByteCount) arr)
2✔
905
  {-# INLINE packedByteCount #-}
906
  packM as = do
2✔
907
    packM (Length (length as))
2✔
908
    mapM_ packM as
2✔
909
  {-# INLINE packM #-}
910
  unpackM = do
2✔
911
    Length n <- unpackM
2✔
912
    xs <- replicateTailM n unpackM
2✔
913
    pure $ arrayFromListN n xs
2✔
914
  {-# INLINE unpackM #-}
915

916
-- | Tail recursive version of `replicateM`
917
replicateTailM :: Monad m => Int -> m a -> m [a]
918
replicateTailM n f = go n []
2✔
919
  where
920
    go i !acc
2✔
921
      | i <= 0 = pure $ reverse acc
2✔
922
      | otherwise = f >>= \x -> go (i - 1) (x : acc)
1✔
923
{-# INLINE replicateTailM #-}
924

925
instance MemPack ByteArray where
2✔
926
  packedByteCount ba =
2✔
927
    let len = bufferByteCount ba
2✔
928
     in packedByteCount (Length len) + len
2✔
929
  {-# INLINE packedByteCount #-}
930
  packM ba@(ByteArray ba#) = do
2✔
931
    let !len@(I# len#) = bufferByteCount ba
2✔
932
    packM (Length len)
2✔
933
    I# curPos# <- state $ \i -> (i, i + len)
2✔
934
    MutableByteArray mba# <- ask
2✔
935
    lift_# (copyByteArray# ba# 0# mba# curPos# len#)
2✔
936
  {-# INLINE packM #-}
937
  unpackM = unpackByteArray False
2✔
938
  {-# INLINE unpackM #-}
939

940
instance (Typeable a, Prim a) => MemPack (PrimArray a) where
2✔
941
  packedByteCount pa =
2✔
942
    let len = I# (sizeOf# (undefined :: a)) * sizeofPrimArray pa
1✔
943
     in packedByteCount (Length len) + len
2✔
944
  {-# INLINE packedByteCount #-}
945
  packM pa@(PrimArray ba#) = do
2✔
946
    let !len@(I# len#) = I# (sizeOf# (undefined :: a)) * sizeofPrimArray pa
1✔
947
    packM (Length len)
2✔
948
    I# curPos# <- state $ \i -> (i, i + len)
2✔
949
    MutableByteArray mba# <- ask
2✔
950
    lift_# (copyByteArray# ba# 0# mba# curPos# len#)
2✔
951
  {-# INLINE packM #-}
952
  unpackM = (\(ByteArray ba#) -> PrimArray ba#) <$> unpackByteArray False
2✔
953
  {-# INLINE unpackM #-}
954

955
#if !MIN_VERSION_primitive(0,8,0)
956
instance MemPack Prim.ByteArray where
957
  packedByteCount ba =
958
    let len = bufferByteCount ba
959
     in packedByteCount (Length len) + len
960
  {-# INLINE packedByteCount #-}
961
  packM ba@(Prim.ByteArray ba#) = do
962
    let !len@(I# len#) = bufferByteCount ba
963
    packM (Length len)
964
    I# curPos# <- state $ \i -> (i, i + len)
965
    MutableByteArray mba# <- ask
966
    lift_# (copyByteArray# ba# 0# mba# curPos# len#)
967
  {-# INLINE packM #-}
968
  unpackM = (\(ByteArray ba#) -> Prim.ByteArray ba#) <$> unpackByteArray False
969
  {-# INLINE unpackM #-}
970
#endif
971

972
instance MemPack ShortByteString where
×
973
  packedByteCount ba =
×
974
    let len = bufferByteCount ba
×
975
     in packedByteCount (Length len) + len
×
976
  {-# INLINE packedByteCount #-}
UNCOV
977
  packM = packM . byteArrayFromShortByteString
×
978
  {-# INLINE packM #-}
UNCOV
979
  unpackM = byteArrayToShortByteString <$> unpackByteArray False
×
980
  {-# INLINE unpackM #-}
981

982
instance MemPack ByteString where
2✔
983
  packedByteCount ba =
2✔
984
    let len = bufferByteCount ba
2✔
985
     in packedByteCount (Length len) + len
2✔
986
  {-# INLINE packedByteCount #-}
987
  packM bs = packM (Length (bufferByteCount bs)) >> packByteStringM bs
2✔
988
  {-# INLINE packM #-}
989
  unpackM = pinnedByteArrayToByteString <$> unpackByteArray True
2✔
990
  {-# INLINE unpackM #-}
991

992
{- FOURMOLU_DISABLE -}
993
instance MemPack BSL.ByteString where
2✔
994
#if WORD_SIZE_IN_BITS == 32
995
  packedByteCount bsl =
996
    let len64 = BSL.length bsl
997
        len = fromIntegral len64
998
     in if len64 <= fromIntegral (maxBound :: Int)
999
        then packedByteCount (Length len) + len
1000
        else error $ mconcat [ "Cannot pack more that '2 ^ 31 - 1' bytes on a 32bit architecture, "
1001
                             , "but tried to pack a lazy ByteString with "
1002
                             , show len64
1003
                             , " bytes"
1004
                             ]
1005
#elif WORD_SIZE_IN_BITS == 64
1006
  packedByteCount bsl =
2✔
1007
    let len = fromIntegral (BSL.length bsl)
2✔
1008
     in packedByteCount (Length len) + len
2✔
1009
#else
1010
#error "Only 32bit and 64bit systems are supported"
1011
#endif
1012
  {-# INLINE packedByteCount #-}
1013
  packM bsl = do
2✔
1014
    let !len = fromIntegral (BSL.length bsl)
2✔
1015
        go BSL.Empty = pure ()
1✔
1016
        go (BSL.Chunk bs rest) = packByteStringM bs >> go rest
2✔
1017
    packM (Length len)
2✔
1018
    go bsl
2✔
1019
  {-# INLINE packM #-}
1020
  unpackM = do
2✔
1021
    Length len <- unpackM
2✔
1022
    let c = BSL.defaultChunkSize
2✔
1023
        go n
2✔
1024
          | n == 0 = pure BSL.Empty
2✔
1025
          | n <= c = BSL.Chunk <$> unpackByteStringM n <*> pure BSL.Empty
1✔
UNCOV
1026
          | otherwise = BSL.Chunk <$> unpackByteStringM c <*> go (n - c)
×
1027
    go len
2✔
1028
  {-# INLINE unpackM #-}
1029

1030
instance MemPack Text where
2✔
1031
#if MIN_VERSION_text(2,0,0)
1032
  packedByteCount (Text _ _ byteCount) = packedByteCount (Length byteCount) + byteCount
2✔
1033
  packM (Text (T.ByteArray ba#) (I# offset#) len@(I# len#)) = do
2✔
1034
    packM (Length len)
2✔
1035
    I# curPos# <- state $ \i -> (i, i + len)
2✔
1036
    MutableByteArray mba# <- ask
2✔
1037
    lift_# (copyByteArray# ba# offset# mba# curPos# len#)
2✔
1038
#else
1039
  -- FIXME: This is very inefficient and shall be fixed in the next major version
1040
  packedByteCount = packedByteCount . T.encodeUtf8
1041
  packM = packM . T.encodeUtf8
1042
#endif
1043
  {-# INLINE packedByteCount #-}
1044
  {-# INLINE packM #-}
1045
  unpackM = do
2✔
1046
    bs <- unpackM
2✔
1047
    case T.decodeUtf8' bs of
2✔
1048
      Right txt -> pure txt
2✔
UNCOV
1049
      Left exc -> F.fail $ show exc
×
1050
  {-# INLINE unpackM #-}
1051
{- FOURMOLU_ENABLE -}
1052

1053
-- | This is the implementation of `unpackM` for `ByteArray`, `ByteString` and `ShortByteString`
1054
unpackByteArray :: Buffer b => Bool -> Unpack b ByteArray
1055
unpackByteArray isPinned = unpackByteArrayLen isPinned . unLength =<< unpackM
2✔
1056
{-# INLINE unpackByteArray #-}
1057

1058
-- | Unpack a `ByteArray` with supplied number of bytes.
1059
--
1060
-- Similar to `unpackByteArray`, except it does not unpack a length.
1061
--
1062
-- @since 0.1.1
1063
unpackByteArrayLen :: Buffer b => Bool -> Int -> Unpack b ByteArray
1064
unpackByteArrayLen isPinned len@(I# len#) = do
2✔
1065
  I# curPos# <- guardAdvanceUnpack len
2✔
1066
  buf <- ask
2✔
1067
  pure $! runST $ do
2✔
1068
    mba@(MutableByteArray mba#) <- newMutableByteArray isPinned len
2✔
1069
    buffer
2✔
1070
      buf
2✔
1071
      (\ba# off# -> st_ (copyByteArray# ba# (curPos# +# off#) mba# 0# len#))
2✔
1072
      (\addr# -> st_ (copyAddrToByteArray# (addr# `plusAddr#` curPos#) mba# 0# len#))
2✔
1073
    freezeMutableByteArray mba
2✔
1074
{-# INLINE unpackByteArrayLen #-}
1075

1076
-- | Increment the offset counter of `Pack` monad by then number of `packedByteCount` and
1077
-- return the starting offset.
1078
packIncrement :: MemPack a => a -> Pack s Int
1079
packIncrement a =
2✔
1080
  state $ \i ->
2✔
1081
    let !n = i + packedByteCount a
1✔
1082
     in (i, n)
2✔
1083
{-# INLINE packIncrement #-}
1084

1085
-- | Increment the offset counter of `Unpack` monad by the supplied number of
1086
-- bytes. Returns the original offset or fails with `RanOutOfBytesError` whenever there is
1087
-- not enough bytes in the `Buffer`.
1088
guardAdvanceUnpack :: Buffer b => Int -> Unpack b Int
1089
guardAdvanceUnpack n@(I# n#) = do
2✔
1090
  buf <- ask
2✔
1091
  let !len = bufferByteCount buf
2✔
1092
  -- Check that we still have enough bytes, while guarding against integer overflow.
1093
  join $ state $ \i@(I# i#) ->
2✔
1094
    case addIntC# i# n# of
2✔
1095
      (# adv#, 0# #)
1096
        | len >= I# adv# -> (pure i, I# adv#)
2✔
1097
      _ -> (failOutOfBytes i len n, i)
1✔
1098
{-# INLINE guardAdvanceUnpack #-}
1099

1100
failOutOfBytes :: Int -> Int -> Int -> Unpack b a
1101
failOutOfBytes i len n =
2✔
1102
  failUnpack $
2✔
1103
    toSomeError $
2✔
1104
      RanOutOfBytesError
2✔
1105
        { ranOutOfBytesRead = i
2✔
1106
        , ranOutOfBytesAvailable = len
2✔
1107
        , ranOutOfBytesRequested = n
2✔
1108
        }
1109
{-# NOINLINE failOutOfBytes #-}
1110

1111
-- | Serialize a type into an unpinned `ByteArray`
1112
--
1113
-- ====__Examples__
1114
--
1115
-- >>> :set -XTypeApplications
1116
-- >>> unpack @[Int] $ pack ([1,2,3,4,5] :: [Int])
1117
-- Right [1,2,3,4,5]
1118
pack :: forall a. (MemPack a, HasCallStack) => a -> ByteArray
1119
pack = packByteArray False
2✔
1120
{-# INLINE pack #-}
1121

1122
-- | Serialize a type into a pinned `ByteString`
1123
packByteString :: forall a. (MemPack a, HasCallStack) => a -> ByteString
1124
packByteString = pinnedByteArrayToByteString . packByteArray True
2✔
1125
{-# INLINE packByteString #-}
1126

1127
-- | Serialize a type into an unpinned `ShortByteString`
1128
packShortByteString :: forall a. (MemPack a, HasCallStack) => a -> ShortByteString
UNCOV
1129
packShortByteString = byteArrayToShortByteString . pack
×
1130
{-# INLINE packShortByteString #-}
1131

1132
-- | Same as `pack`, but allows controlling the pinnedness of allocated memory
1133
packByteArray ::
1134
  forall a.
1135
  (MemPack a, HasCallStack) =>
1136
  -- | Should the array be allocated in pinned memory?
1137
  Bool ->
1138
  a ->
1139
  ByteArray
1140
packByteArray isPinned a =
2✔
1141
  packWithByteArray isPinned (typeName @a) (packedByteCount a) (packM a)
1✔
1142
{-# INLINE packByteArray #-}
1143

1144
-- | Allocate a `MutableByteArray` and run the supplied `Pack` action on it. Freezes the
1145
-- allocated `MutableByteArray` at the end yielding the immutable `ByteArray` with
1146
-- serialization packed into it.
1147
packWithByteArray ::
1148
  HasCallStack =>
1149
  -- | Should the array be allocated in pinned memory?
1150
  Bool ->
1151
  -- | Name of the type that is being serialized. Used for error reporting
1152
  String ->
1153
  -- | Size of the array to be allocated
1154
  Int ->
1155
  (forall s. Pack s ()) ->
1156
  ByteArray
1157
packWithByteArray isPinned name len packerM =
2✔
1158
  runST $ packWithMutableByteArray isPinned name len packerM >>= freezeMutableByteArray
1✔
1159
{-# INLINE packWithByteArray #-}
1160

1161
-- | Same as `packByteArray`, but produces a mutable array instead
1162
packMutableByteArray ::
1163
  forall a s.
1164
  (MemPack a, HasCallStack) =>
1165
  -- | Should the array be allocated in pinned memory?
1166
  Bool ->
1167
  a ->
1168
  ST s (MutableByteArray s)
UNCOV
1169
packMutableByteArray isPinned a =
×
1170
  packWithMutableByteArray isPinned (typeName @a) (packedByteCount a) (packM a)
×
1171
{-# INLINE packMutableByteArray #-}
1172

1173
-- | Allocate a `MutableByteArray` and run the supplied `Pack` action on it.
1174
packWithMutableByteArray ::
1175
  forall s.
1176
  HasCallStack =>
1177
  -- | Should the array be allocated in pinned memory?
1178
  Bool ->
1179
  -- | Name of the type that is being serialized. Used for error reporting
1180
  String ->
1181
  -- | Size of the mutable array to be allocated
1182
  Int ->
1183
  -- | Packing action to be executed on the mutable buffer
1184
  Pack s () ->
1185
  ST s (MutableByteArray s)
1186
packWithMutableByteArray isPinned name len packerM = do
2✔
1187
  mba <- newMutableByteArray isPinned len
2✔
1188
  filledBytes <- execStateT (runPack packerM mba) 0
2✔
1189
  when (filledBytes /= len) $ errorFilledBytes name filledBytes len
1✔
1190
  pure mba
2✔
1191
{-# INLINEABLE packWithMutableByteArray #-}
1192

1193
-- | This is a critical error, therefore we are not gracefully failing this unpacking
1194
errorFilledBytes :: HasCallStack => [Char] -> Int -> Int -> a
UNCOV
1195
errorFilledBytes name filledBytes len =
×
1196
  if filledBytes < len
×
1197
    then
UNCOV
1198
      error $
×
1199
        "Some bug in 'packM' was detected. Buffer of length " <> showBytes len
×
1200
          ++ " was not fully filled while packing " <> name
×
1201
          ++ ". Unfilled " <> showBytes (len - filledBytes) <> "."
×
1202
    else
UNCOV
1203
      error $
×
1204
        "Potential buffer overflow. Some bug in 'packM' was detected while packing " <> name
×
1205
          ++ ". Filled " <> showBytes (filledBytes - len) <> " more than allowed into a buffer of length "
×
1206
          ++ show len
×
1207
{-# NOINLINE errorFilledBytes #-}
1208

1209
-- | Helper function for packing a `ByteString` without its length being packed first.
1210
--
1211
-- @since 0.1.1
1212
packByteStringM :: ByteString -> Pack s ()
1213
packByteStringM bs = do
2✔
1214
  let !len@(I# len#) = bufferByteCount bs
2✔
1215
  I# curPos# <- state $ \i -> (i, i + len)
2✔
1216
  Pack $ \(MutableByteArray mba#) -> lift $ withPtrByteStringST bs $ \(Ptr addr#) ->
2✔
1217
    st_ (copyAddrToByteArray# addr# mba# curPos# len#)
2✔
1218
{-# INLINE packByteStringM #-}
1219

1220
-- | Unpack a `ByteString` of a specified size.
1221
--
1222
-- @since 0.1.1
1223
unpackByteStringM ::
1224
  Buffer b =>
1225
  -- | number of bytes to unpack
1226
  Int ->
1227
  Unpack b ByteString
1228
unpackByteStringM len = pinnedByteArrayToByteString <$> unpackByteArrayLen True len
2✔
1229
{-# INLINE unpackByteStringM #-}
1230

1231
-- | Unpack a memory `Buffer` into a type using its `MemPack` instance. Besides the
1232
-- unpacked type it also returns an index into a buffer where unpacked has stopped.
1233
unpackLeftOver :: forall a b. (MemPack a, Buffer b, HasCallStack) => b -> Fail SomeError (a, Int)
1234
unpackLeftOver b = do
2✔
1235
  let len = bufferByteCount b
2✔
1236
  res@(_, consumedBytes) <- runStateT (runUnpack unpackM b) 0
2✔
1237
  when (consumedBytes > len) $ errorLeftOver (typeName @a) consumedBytes len
1✔
1238
  pure res
2✔
1239
{-# INLINEABLE unpackLeftOver #-}
1240

1241
-- | This is a critical error, therefore we are not gracefully failing this unpacking
1242
errorLeftOver :: HasCallStack => String -> Int -> Int -> a
UNCOV
1243
errorLeftOver name consumedBytes len =
×
1244
  error $
×
1245
    "Potential buffer overflow. Some bug in 'unpackM' was detected while unpacking " <> name
×
1246
      ++ ". Consumed " <> showBytes (consumedBytes - len) <> " more than allowed from a buffer of length "
×
1247
      ++ show len
×
1248
{-# NOINLINE errorLeftOver #-}
1249

1250
-- | Unpack a memory `Buffer` into a type using its `MemPack` instance. Besides potential
1251
-- unpacking failures due to a malformed buffer it will also fail the supplied `Buffer`
1252
-- was not fully consumed. Use `unpackLeftOver`, whenever a partially consumed buffer is
1253
-- possible.
1254
unpack :: forall a b. (MemPack a, Buffer b, HasCallStack) => b -> Either SomeError a
1255
unpack = first fromMultipleErrors . runFailAgg . unpackFail
2✔
1256
{-# INLINEABLE unpack #-}
1257

1258
-- | Same as `unpack` except fails in a `Fail` monad, instead of `Either`.
1259
unpackFail :: forall a b. (MemPack a, Buffer b, HasCallStack) => b -> Fail SomeError a
1260
unpackFail b = do
2✔
1261
  let len = bufferByteCount b
2✔
1262
  (a, consumedBytes) <- unpackLeftOver b
2✔
1263
  when (consumedBytes /= len) $ unpackFailNotFullyConsumed (typeName @a) consumedBytes len
2✔
1264
  pure a
2✔
1265
{-# INLINEABLE unpackFail #-}
1266

1267
unpackFailNotFullyConsumed :: Applicative m => String -> Int -> Int -> FailT SomeError m a
1268
unpackFailNotFullyConsumed name consumedBytes len =
2✔
1269
  failT $
2✔
1270
    toSomeError $
2✔
1271
      NotFullyConsumedError
2✔
1272
        { notFullyConsumedRead = consumedBytes
2✔
1273
        , notFullyConsumedAvailable = len
2✔
1274
        , notFullyConsumedTypeName = name
2✔
1275
        }
1276
{-# NOINLINE unpackFailNotFullyConsumed #-}
1277

1278
-- | Same as `unpackFail` except fails in any `MonadFail`, instead of `Fail`.
1279
unpackMonadFail :: forall a b m. (MemPack a, Buffer b, F.MonadFail m) => b -> m a
UNCOV
1280
unpackMonadFail = either (F.fail . show) pure . unpack
×
1281
{-# INLINEABLE unpackMonadFail #-}
1282

1283
-- | Same as `unpack` except throws a runtime exception upon a failure
1284
unpackError :: forall a b. (MemPack a, Buffer b, HasCallStack) => b -> a
1285
unpackError = errorFail . unpackFail
2✔
1286
{-# INLINEABLE unpackError #-}
1287

1288
-- | Variable length encoding for bounded types. This type of encoding will use less
1289
-- memory for small values, but for larger values it will consume more memory and will be
1290
-- slower during packing/unpacking.
UNCOV
1291
newtype VarLen a = VarLen {unVarLen :: a}
×
1292
  deriving (Eq, Ord, Show, Bounded, Enum, Num, Real, Integral, Bits, FiniteBits)
1✔
1293

1294
instance MemPack (VarLen Word16) where
2✔
1295
  packedByteCount = packedVarLenByteCount
2✔
1296
  {-# INLINE packedByteCount #-}
1297
  packM v@(VarLen x) = p7 (p7 (p7 (errorTooManyBits "Word16"))) (numBits - 7)
1✔
1298
    where
1299
      p7 = packIntoCont7 x
2✔
1300
      {-# INLINE p7 #-}
1301
      numBits = packedVarLenByteCount v * 7
2✔
1302
  {-# INLINE packM #-}
1303
  unpackM = do
2✔
1304
    let d7 = unpack7BitVarLen
2✔
1305
        {-# INLINE d7 #-}
1306
    VarLen <$> d7 (d7 (unpack7BitVarLenLast 0b_1111_1100)) 0 0
2✔
1307
  {-# INLINE unpackM #-}
1308

1309
instance MemPack (VarLen Word32) where
2✔
1310
  packedByteCount = packedVarLenByteCount
2✔
1311
  {-# INLINE packedByteCount #-}
1312
  packM v@(VarLen x) = p7 (p7 (p7 (p7 (p7 (errorTooManyBits "Word32"))))) (numBits - 7)
1✔
1313
    where
1314
      p7 = packIntoCont7 x
2✔
1315
      {-# INLINE p7 #-}
1316
      numBits = packedVarLenByteCount v * 7
2✔
1317
  {-# INLINE packM #-}
1318
  unpackM = do
2✔
1319
    let d7 = unpack7BitVarLen
2✔
1320
        {-# INLINE d7 #-}
1321
    VarLen <$> d7 (d7 (d7 (d7 (unpack7BitVarLenLast 0b_1111_0000)))) 0 0
2✔
1322
  {-# INLINE unpackM #-}
1323

1324
instance MemPack (VarLen Word64) where
2✔
1325
  packedByteCount = packedVarLenByteCount
2✔
1326
  {-# INLINE packedByteCount #-}
1327
  packM v@(VarLen x) =
2✔
1328
    p7 (p7 (p7 (p7 (p7 (p7 (p7 (p7 (p7 (p7 (errorTooManyBits "Word64")))))))))) (numBits - 7)
1✔
1329
    where
1330
      p7 = packIntoCont7 x
2✔
1331
      {-# INLINE p7 #-}
1332
      numBits = packedVarLenByteCount v * 7
2✔
1333
  {-# INLINE packM #-}
1334
  unpackM = do
2✔
1335
    let d7 = unpack7BitVarLen
2✔
1336
        {-# INLINE d7 #-}
1337
    VarLen <$> d7 (d7 (d7 (d7 (d7 (d7 (d7 (d7 (d7 (unpack7BitVarLenLast 0b_1111_1110))))))))) 0 0
2✔
1338
  {-# INLINE unpackM #-}
1339

1340
instance MemPack (VarLen Word) where
2✔
1341
  packedByteCount = packedVarLenByteCount
2✔
1342
  {-# INLINE packedByteCount #-}
1343
#if WORD_SIZE_IN_BITS == 32
1344
  packM v@(VarLen x) = p7 (p7 (p7 (p7 (p7 (errorTooManyBits "Word"))))) (numBits - 7)
1345
    where
1346
      p7 = packIntoCont7 x
1347
      {-# INLINE p7 #-}
1348
      numBits = packedVarLenByteCount v * 7
1349
  {-# INLINE packM #-}
1350
  unpackM = do
1351
    let d7 = unpack7BitVarLen
1352
        {-# INLINE d7 #-}
1353
    VarLen <$> d7 (d7 (d7 (d7 (unpack7BitVarLenLast 0b_1111_0000)))) 0 0
1354
  {-# INLINE unpackM #-}
1355
#elif WORD_SIZE_IN_BITS == 64
1356
  packM v@(VarLen x) =
2✔
1357
    p7 (p7 (p7 (p7 (p7 (p7 (p7 (p7 (p7 (p7 (errorTooManyBits "Word")))))))))) (numBits - 7)
1✔
1358
    where
1359
      p7 = packIntoCont7 x
2✔
1360
      {-# INLINE p7 #-}
1361
      numBits = packedVarLenByteCount v * 7
2✔
1362
  {-# INLINE packM #-}
1363
  unpackM = do
2✔
1364
    let d7 = unpack7BitVarLen
2✔
1365
        {-# INLINE d7 #-}
1366
    VarLen <$> d7 (d7 (d7 (d7 (d7 (d7 (d7 (d7 (d7 (unpack7BitVarLenLast 0b_1111_1110))))))))) 0 0
2✔
1367
  {-# INLINE unpackM #-}
1368
#else
1369
#error "Only 32bit and 64bit systems are supported"
1370
#endif
1371

1372
packedVarLenByteCount :: FiniteBits b => VarLen b -> Int
1373
packedVarLenByteCount (VarLen x) =
2✔
1374
  case (finiteBitSize x - countLeadingZeros x) `quotRem` 7 of
1✔
1375
    (0, 0) -> 1
2✔
1376
    (q, 0) -> q
2✔
1377
    (q, _) -> q + 1
2✔
1378
{-# INLINE packedVarLenByteCount #-}
1379

1380
errorTooManyBits :: HasCallStack => String -> a
UNCOV
1381
errorTooManyBits name =
×
1382
  error $ "Bug detected. Trying to pack more bits for " ++ name ++ " than it should be posssible"
×
1383
{-# NOINLINE errorTooManyBits #-}
1384

1385
packIntoCont7 ::
1386
  (Bits t, Integral t) => t -> (Int -> Pack s ()) -> Int -> Pack s ()
1387
packIntoCont7 x cont n
2✔
1388
  | n <= 0 = packM (fromIntegral @_ @Word8 x .&. complement topBit8)
2✔
1389
  | otherwise = do
1✔
1390
      packM (fromIntegral @_ @Word8 (x `shiftR` n) .|. topBit8)
2✔
1391
      cont (n - 7)
2✔
1392
  where
1393
    topBit8 :: Word8
1394
    !topBit8 = 0b_1000_0000
2✔
1395
{-# INLINE packIntoCont7 #-}
1396

1397
-- | Decode a variable length integral value that is encoded with 7 bits of data
1398
-- and the most significant bit (MSB), the 8th bit is set whenever there are
1399
-- more bits following. Continuation style allows us to avoid
1400
-- recursion. Removing loops is good for performance.
1401
unpack7BitVarLen ::
1402
  (Num a, Bits a, Buffer b) =>
1403
  -- | Continuation that will be invoked if MSB is set
1404
  (Word8 -> a -> Unpack b a) ->
1405
  -- | Will be set either to 0 initially or to the very first unmodified byte, which is
1406
  -- guaranteed to have the first bit set.
1407
  Word8 ->
1408
  -- | Accumulator
1409
  a ->
1410
  Unpack b a
1411
unpack7BitVarLen cont firstByte !acc = do
2✔
1412
  b8 :: Word8 <- unpackM
2✔
1413
  if b8 `testBit` 7
2✔
1414
    then
1415
      cont (if firstByte == 0 then b8 else firstByte) (acc `shiftL` 7 .|. fromIntegral (b8 `clearBit` 7))
2✔
1416
    else pure (acc `shiftL` 7 .|. fromIntegral b8)
2✔
1417
{-# INLINE unpack7BitVarLen #-}
1418

1419
unpack7BitVarLenLast ::
1420
  forall t b.
1421
  (Num t, Bits t, MemPack t, Buffer b) =>
1422
  Word8 ->
1423
  Word8 ->
1424
  t ->
1425
  Unpack b t
1426
unpack7BitVarLenLast mask firstByte acc = do
2✔
1427
  res <- unpack7BitVarLen (\_ _ -> F.fail "Too many bytes.") firstByte acc
1✔
1428
  -- Only while decoding the last 7bits we check if there was too many
1429
  -- bits supplied at the beginning.
1430
  unless (firstByte .&. mask == 0b_1000_0000) $ unpack7BitVarLenLastFail (typeName @t) firstByte
1✔
1431
  pure res
2✔
1432
{-# INLINE unpack7BitVarLenLast #-}
1433

1434
unpack7BitVarLenLastFail :: F.MonadFail m => String -> Word8 -> m a
UNCOV
1435
unpack7BitVarLenLastFail name firstByte =
×
1436
  F.fail $
×
1437
    "Unexpected bits for "
×
1438
      ++ name
×
1439
      ++ " were set in the first byte of 'VarLen': 0x" <> showHex firstByte ""
×
1440
{-# NOINLINE unpack7BitVarLenLastFail #-}
1441

1442
-- | This is a helper type useful for serializing number of elements in data
1443
-- structures. It uses `VarLen` underneath, since sizes of common data structures aren't
1444
-- too big. It also prevents negative values from being serialized and deserialized.
1445
newtype Length = Length {unLength :: Int}
2✔
UNCOV
1446
  deriving (Eq, Show, Num)
×
1447

1448
instance Bounded Length where
1449
  minBound = 0
2✔
1450
  maxBound = Length maxBound
2✔
1451

1452
instance Enum Length where
1✔
1453
  toEnum n
2✔
1454
    | n < 0 = error $ "toEnum: Length cannot be negative: " ++ show n
1✔
1455
    | otherwise = Length n
1✔
1456
  fromEnum = unLength
2✔
1457

1458
instance MemPack Length where
2✔
1459
  packedByteCount = packedByteCount . VarLen . fromIntegral @Int @Word . unLength
2✔
1460
  packM (Length n)
2✔
1461
    | n < 0 = packLengthError n
1✔
1462
    | otherwise = packM (VarLen (fromIntegral @Int @Word n))
1✔
1463
  {-# INLINE packM #-}
1464
  unpackM = do
2✔
1465
    VarLen (w :: Word) <- unpackM
2✔
1466
    when (testBit w (finiteBitSize w - 1)) $ upackLengthFail w
1✔
1467
    pure $ Length $ fromIntegral @Word @Int w
2✔
1468
  {-# INLINE unpackM #-}
1469

1470
packLengthError :: Int -> a
UNCOV
1471
packLengthError n = error $ "Length cannot be negative. Supplied: " ++ show n
×
1472
{-# NOINLINE packLengthError #-}
1473

1474
upackLengthFail :: F.MonadFail m => Word -> m a
1475
upackLengthFail w =
2✔
1476
  F.fail $ "Attempt to unpack negative length was detected: " ++ show (fromIntegral @Word @Int w)
1✔
1477
{-# NOINLINE upackLengthFail #-}
1478

1479
-- | This is a helper type that is useful for creating `MemPack` instances for sum types.
1480
newtype Tag = Tag {unTag :: Word8}
2✔
1481
  deriving (Eq, Ord, Show, Num, Enum, Bounded)
1✔
1482

1483
-- Manually defined instance, since ghc-8.6 has issues with deriving MemPack
1484
instance MemPack Tag where
2✔
1485
  packedByteCount _ = packedTagByteCount
2✔
1486
  {-# INLINE packedByteCount #-}
1487
  unpackM = unpackTagM
2✔
1488
  {-# INLINE unpackM #-}
1489
  packM = packTagM
2✔
1490
  {-# INLINE packM #-}
1491

1492
packedTagByteCount :: Int
1493
packedTagByteCount = SIZEOF_WORD8
2✔
1494
{-# INLINE packedTagByteCount #-}
1495

1496
unpackTagM :: Buffer b => Unpack b Tag
1497
unpackTagM = Tag <$> unpackM
2✔
1498
{-# INLINE unpackTagM #-}
1499

1500
packTagM :: Tag -> Pack s ()
1501
packTagM = packM . unTag
2✔
1502
{-# INLINE packTagM #-}
1503

1504
unknownTagM :: forall a m b. (MemPack a, F.MonadFail m) => Tag -> m b
UNCOV
1505
unknownTagM (Tag t) = F.fail $ "Unrecognized Tag: " ++ show t ++ " while decoding " ++ typeName @a
×
1506

1507
lift_# :: (State# s -> State# s) -> Pack s ()
1508
lift_# f = Pack $ \_ -> lift $ st_ f
2✔
1509
{-# INLINE lift_# #-}
1510

1511
st_ :: (State# s -> State# s) -> ST s ()
1512
st_ f = ST $ \s# -> (# f s#, () #)
2✔
1513
{-# INLINE st_ #-}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc