@@ -12,12 +12,17 @@
1212-- Portability : GHC
1313--
1414module Streamly.Internal.Data.Unbox
15− ( Unbox(..)
16− , PinnedState(..)
17− , MutableByteArray(..)
18− , touch
15+ (
16+ -- ** MutableByteArray
17+ MutableByteArray(..)
1918 , getMutableByteArray#
2019 , sizeOfMutableByteArray
20+ , touch
21+ , nil
22+ , putSliceUnsafe
23+
24+ -- ** Allocation
25+ , PinnedState(..)
2126 , isPinned
2227 , pin
2328 , unpin
@@ -25,30 +30,29 @@ module Streamly.Internal.Data.Unbox
2530 , newBytes
2631 , pinnedNewBytes
2732 , pinnedNewAlignedBytes
28− , nil
29− , putSliceUnsafe
3033
31− -- * Type Parser and Builder
32− , BoundedPtr (..)
34+ -- ** Unbox type class
35+ , Unbox(..)
3336
37+ -- ** Peek and poke utilities
38+ , BoundedPtr (..)
39+ -- Peek
3440 , Peeker (..)
3541 , read
3642 , readUnsafe
3743 , skipByte
3844 , runPeeker
39−
45+ -- Poke
4046 , pokeBoundedPtrUnsafe
4147 , pokeBoundedPtr
4248
43− -- * Generic Unbox instances
44− , genericSizeOf
45− , genericPeekByteIndex
46− , genericPokeByteIndex
47−
48− -- Classess used for generic deriving.
49+ -- ** Generic Deriving
4950 , PeekRep(..)
5051 , PokeRep(..)
5152 , SizeOfRep(..)
53+ , genericSizeOf
54+ , genericPeekByteIndex
55+ , genericPokeByteIndex
5256 ) where
5357
5458#include "MachDeps.h"
@@ -92,6 +96,10 @@ data PinnedState
9296 | Unpinned
9397
9498-- XXX can use UnliftedNewtypes
99+
100+-- | A lifted mutable byte array type wrapping @MutableByteArray# RealWorld@.
101+-- This is a low level array used to back high level unboxed arrays and
102+-- serialized data.
95103data MutableByteArray = MutableByteArray (MutableByteArray# RealWorld)
96104
97105{-# INLINE getMutableByteArray# #-}
@@ -327,23 +335,37 @@ unpin arr@(MutableByteArray marr#) =
327335-- size fields at each nesting level, aggregating the size upwards.
328336
329337-- | The 'Unbox' type class provides operations for serialization (unboxing)
330−-- and deserialization (boxing) of a fixed-length, non-recursive Haskell data
331−-- type to and from its unboxed byte representation in a mutable byte array.
338+-- and deserialization (boxing) of fixed-length, non-recursive Haskell data
339+-- types to and from their byte stream representation.
340+--
332341-- Unbox uses fixed size encoding, therefore, size is independent of the value,
333−-- it can be determined solely by the type. This makes types with 'Unbox'
334−-- instances suitable for storing in arrays. Note that sum types may have
335−-- multiple constructors of different sizes, the size of the sum type is
342+-- it must be determined solely by the type. This restriction makes types with
343+-- 'Unbox' instances suitable for storing in arrays. Note that sum types may
344+-- have multiple constructors of different sizes, the size of a sum type is
336345-- computed as the maximum required by any constructor.
337346--
338−-- The 'peekByteIndex' read operation converts a Haskell type from its unboxed
339−-- representation stored in a mutable byte array, while the 'pokeByteIndex'
340−-- write operation serializes a Haskell data type to its byte representation in
341−-- the mutable byte array. These operations do not check the bounds of the
342−-- array, the user of the type class is expected to check the bounds before
343−-- peeking or poking.
347+-- The 'peekByteIndex' operation reads as many bytes from the mutable byte
348+-- array as the @size@ of the data type and builds a Haskell data type from
349+-- these bytes. 'pokeByteIndex' operation converts a Haskell data type to its
350+-- binary representation which consists of @size@ bytes and then stores
351+-- these bytes into the mutable byte array. These operations do not check the
352+-- bounds of the array, the user of the type class is expected to check the
353+-- bounds before peeking or poking.
354+--
355+-- IMPORTANT: The serialized data's byte ordering remains the same as the host
356+-- machine's byte order. Therefore, it can not be deserialized from host
357+-- machines with a different byte ordering.
344358--
345−-- Instances can be derived via Generics or Template Haskell. Note that the
346−-- data type must be non-recursive.
359+-- Instances can be derived via Generics, Template Haskell, or written
360+-- manually. Note that the data type must be non-recursive. WARNING! Generic
361+-- and Template Haskell deriving, both hang for recursive data types. Deriving
362+-- via Generics is more convenient but Template Haskell should be preferred
363+-- over Generics for the following reasons:
364+--
365+-- 1. Instances derived via Template Haskell provide better and more reliable
366+-- performance.
367+-- 2. Generic deriving allows only 256 fields or constructor tags whereas
368+-- template Haskell has no limit.
347369--
348370-- Here is an example, for deriving an instance of this type class using
349371-- generics:
@@ -356,28 +378,20 @@ unpin arr@(MutableByteArray marr#) =
356378-- } deriving Generic
357379-- :}
358380--
381+-- >>> import Streamly.Data.Serialize (Unbox(..))
382+-- >>> instance Unbox Object
383+--
359384-- To derive the instance via Template Haskell:
360385--
361386-- @
362387-- import Streamly.Data.Serialize (deriveUnbox)
363−-- $(deriveUnbox ''Object)
388+-- \$(deriveUnbox ''Object)
364389-- @
365390--
366391-- See 'Streamly.Data.Serialize.deriveUnbox' and
367392-- 'Streamly.Data.Serialize.deriveUnboxWith' for more information on deriving
368393-- using Template Haskell.
369394--
370−-- Deriving via Template Haskell should be preferred for the following reasons:
371−-- 1. Instances derived via Template Haskell have more performant routines.
372−-- 2. Template Haskell deriving can handle (maxBound :: Word64) number of
373−-- constructors whereas the Generic deriving can only handle 256.
374−--
375−-- WARNING! Generic and Template Haskell deriving, both hang for recursive data
376−-- types.
377−--
378−-- >>> import Streamly.Data.Array (Unbox(..))
379−-- >>> instance Unbox Object
380−--
381395-- If you want to write the instance manually:
382396--
383397-- >>> :{
@@ -395,15 +409,15 @@ unpin arr@(MutableByteArray marr#) =
395409-- :}
396410--
397411class Unbox a where
398− -- | Get the size. Size cannot be zero.
412+ -- | Get the size. Size cannot be zero, should be at least 1 byte.
399413 sizeOf :: Proxy a -> Int
400414
401415 {-# INLINE sizeOf #-}
402416 default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
403417 sizeOf = genericSizeOf
404418
405− -- | Read an element of type "a" from a MutableByteArray given the byte
406− -- index.
419+ -- | @peekByteIndex byte-index array@ reads an element of type @a@ from the
420+ -- the given the byte index in the array.
407421 --
408422 -- IMPORTANT: The implementation of this interface may not check the bounds
409423 -- of the array, the caller must not assume that.
@@ -414,8 +428,8 @@ class Unbox a where
414428 Int -> MutableByteArray -> IO a
415429 peekByteIndex i arr = genericPeekByteIndex arr i
416430
417− -- | Write an element of type "a" to a MutableByteArray given the byte
418− -- index.
431+ -- | @pokeByteIndex byte-index array@ writes an element of type @a@ to the
432+ -- the given the byte index in the array.
419433 --
420434 -- IMPORTANT: The implementation of this interface may not check the bounds
421435 -- of the array, the caller must not assume that.