packages feed

streamly-bytestring-0.1.4: src/Streamly/External/ByteString.hs

{-# LANGUAGE CPP             #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE MagicHash #-}

module Streamly.External.ByteString
  ( toArray
  , fromArray

  , read
  , writeN
  , write
  )
where

import Control.Monad.IO.Class (MonadIO)
import Data.Word (Word8)
import GHC.ForeignPtr (ForeignPtr(..))
import GHC.Ptr (Ptr(..), minusPtr, nullPtr, plusPtr)
import Streamly.Data.Unfold (Unfold, lmap)
import Streamly.Data.Fold (Fold)

-- Internal imports
import Data.ByteString.Internal (ByteString(..))
import Streamly.Internal.Data.Array.Foreign.Type (Array(..))
import Streamly.Internal.Data.Array.Foreign.Mut.Type
    (ArrayContents, arrayToFptrContents, fptrToArrayContents, nilArrayContents)

import qualified Streamly.Data.Array.Foreign as A

import Prelude hiding (read)

-- | Helper function that creates a ForeignPtr
makeForeignPtr :: ArrayContents -> Ptr a -> ForeignPtr a
makeForeignPtr contents (Ptr addr#) =
    ForeignPtr addr# (arrayToFptrContents contents)

-- | Convert a 'ByteString' to an array of 'Word8'. This function unwraps the
-- 'ByteString' and wraps it with 'Array' constructors and hence the operation
-- is performed in constant time.
{-# INLINE toArray #-}
toArray :: ByteString -> Array Word8
toArray (PS (ForeignPtr addr# _) _ _)
    | Ptr addr# == nullPtr = Array nilArrayContents nullPtr nullPtr
toArray (PS (ForeignPtr addr# fpcontents) off len) =
    Array (fptrToArrayContents fpcontents) startPtr endPtr
  where
    startPtr = Ptr addr# `plusPtr` off
    endPtr = startPtr `plusPtr` len

-- | Convert an array of 'Word8' to a 'ByteString'. This function unwraps the
-- 'Array' and wraps it with 'ByteString' constructors and hence the operation
-- is performed in constant time.
{-# INLINE fromArray #-}
fromArray :: Array Word8 -> ByteString
fromArray Array {..}
    | aLen == 0 = mempty
    | otherwise = PS (makeForeignPtr arrContents arrStart) 0 aLen
  where
    aLen = aEnd `minusPtr` arrStart

-- | Unfold a strict ByteString to a stream of Word8.
{-# INLINE read #-}
read :: Monad m => Unfold m ByteString Word8
read = lmap toArray A.read

-- | Fold a stream of Word8 to a strict ByteString of given size in bytes.
{-# INLINE writeN #-}
writeN :: MonadIO m => Int -> Fold m Word8 ByteString
writeN i = fromArray <$> A.writeN i

-- | Fold a stream of Word8 to a strict ByteString of appropriate size.
{-# INLINE write #-}
write :: MonadIO m => Fold m Word8 ByteString
write = fromArray <$> A.write