@@ -76,13 +76,19 @@ module Streamly.Internal.Data.Array
7676 -- ** Folding
7777 , streamFold
7878 , fold
79+
80+ -- ** Serialization
81+ , encodeAs
82+ , serialize
83+ , pinnedSerialize
84+ , deserialize
7985 )
8086where
8187
88+#include "assert.hs"
8289#include "inline.hs"
8390#include "ArrayMacros.h"
8491
85−import Control.Exception (assert)
8692import Control.Monad (when)
8793import Control.Monad.IO.Class (MonadIO(..))
8894import Data.Functor.Identity (Identity)
@@ -94,6 +100,8 @@ import Foreign.Storable (Storable)
94100import Streamly.Internal.Data.Unbox (Unbox(..))
95101import Prelude hiding (length, null, last, map, (!!), read, concat)
96102
103+import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
104+import Streamly.Internal.Data.Serialize.Type (Serialize)
97105import Streamly.Internal.Data.Fold.Type (Fold(..))
98106import Streamly.Internal.Data.Producer.Type (Producer(..))
99107import Streamly.Internal.Data.Stream (Stream)
@@ -101,7 +109,8 @@ import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
101109import Streamly.Internal.Data.Unfold.Type (Unfold(..))
102110import Streamly.Internal.System.IO (unsafeInlineIO)
103111
104−import qualified Streamly.Internal.Data.MutArray.Type as MA
112+import qualified Streamly.Internal.Data.Serialize.Type as Serialize
113+import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
105114import qualified Streamly.Internal.Data.MutArray as MA
106115import qualified Streamly.Internal.Data.Array.Type as A
107116import qualified Streamly.Internal.Data.Fold as FL
@@ -543,3 +552,38 @@ fold f arr = Stream.fold f (A.read arr)
543552{-# INLINE streamFold #-}
544553streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
545554streamFold f arr = f (A.read arr)
555+
556+--------------------------------------------------------------------------------
557+-- Serialization
558+--------------------------------------------------------------------------------
559+
560+{-# INLINE encodeAs #-}
561+encodeAs :: forall a. Serialize a => PinnedState -> a -> Array Word8
562+encodeAs ps a =
563+ unsafeInlineIO $ do
564+ let len = Serialize.size 0 a
565+ mbarr <- MBA.newBytesAs ps len
566+ off <- Serialize.serialize 0 mbarr a
567+ assertM(len == off)
568+ pure $ Array mbarr 0 off
569+
570+{-# INLINE serialize #-}
571+serialize :: Serialize a => a -> Array Word8
572+serialize = encodeAs Unpinned
573+
574+-- | Serialize a Haskell type to a pinned byte array. The array is allocated
575+-- using pinned memory so that it can be used directly in OS APIs for writing
576+-- to file or sending over the network.
577+{-# INLINE pinnedSerialize #-}
578+pinnedSerialize :: Serialize a => a -> Array Word8
579+pinnedSerialize = encodeAs Pinned
580+
581+-- | Decode a Haskell type from a byte array containing its serialized
582+-- representation.
583+{-# INLINE deserialize #-}
584+deserialize :: Serialize a => Array Word8 -> a
585+deserialize arr@(Array {..}) = unsafeInlineIO $ do
586+ let lenArr = length arr
587+ (off, val) <- Serialize.deserialize arrStart arrContents (arrStart + lenArr)
588+ assertM(off == arrStart + lenArr)
589+ pure val