@@ -120,6 +120,13 @@ module Streamly.Internal.Memory.Array
120120 -- * Immutable Transformations
121121 , streamTransform
122122
123+ -- * Casting
124+ , cast
125+ , castWord8
126+ , unsafeCast
127+ , withPtr
128+ , withCString
129+
123130 -- * Folding Arrays
124131 , streamFold
125132 , fold
@@ -129,11 +136,16 @@ module Streamly.Internal.Memory.Array
129136 )
130137where
131138
132−import Control.Monad (when)
139+import Control.Monad (when)
133140import Control.Monad.IO.Class (MonadIO(..))
141+#if !(MIN_VERSION_base(4,11,0))
142+import Data.Semigroup ((<>))
143+#endif
144+import Data.Word (Word8)
134145-- import Data.Functor.Identity (Identity)
135−import Foreign.ForeignPtr (withForeignPtr, touchForeignPtr)
136−import Foreign.Ptr (plusPtr)
146+import Foreign.C.String (CString)
147+import Foreign.ForeignPtr (withForeignPtr, touchForeignPtr, castForeignPtr)
148+import Foreign.Ptr (plusPtr, castPtr)
137149import Foreign.Storable (Storable(..))
138150import Prelude hiding (length, null, last, map, (!!), read, concat)
139151
@@ -488,6 +500,66 @@ streamTransform f arr =
488500 P.runFold (A.toArrayMinChunk (alignment (undefined :: a)) (length arr))
489501 $ f (toStream arr)
490502
503+-------------------------------------------------------------------------------
504+-- Casts
505+-------------------------------------------------------------------------------
506+
507+-- | Cast an array having elements of type @a@ into an array having elements of
508+-- type @b@. The array size must be a multiple of the size of type @b@
509+-- otherwise accessing the last element of the array may result into a crash or
510+-- a random value.
511+--
512+-- /Internal/
513+--
514+unsafeCast :: Array a -> Array b
515+unsafeCast (Array start end) = Array (castForeignPtr start) (castPtr end)
516+
517+-- | Cast an array into a Word8 array
518+--
519+-- /Internal/
520+--
521+castWord8 :: Array a -> Array Word8
522+castWord8 = unsafeCast
523+
524+-- | Cast an array having elements of type @a@ into an array having elements of
525+-- type @b@. The length of the array should be a multiple of the size of the
526+-- target element otherwise 'Nothing' is returned.
527+--
528+-- /Internal/
529+--
530+cast :: forall a b. (Storable b) => Array a -> Maybe (Array b)
531+cast arr =
532+ let len = A.byteLength arr
533+ r = len `mod` sizeOf (undefined :: b)
534+ in if r /= 0
535+ then Nothing
536+ else Just $ unsafeCast arr
537+
538+-- | Use the array as @Ptr a@.
539+--
540+-- /Unsafe/
541+--
542+-- /Internal/
543+--
544+withPtr :: Array a -> (Ptr b -> IO c) -> IO c
545+withPtr Array{..} act = do
546+ withForeignPtr aStart $ \ptr -> act (castPtr ptr)
547+
548+-- | Convert the array into a null terminated CString Ptr.
549+--
550+-- /Unsafe/
551+--
552+-- /Internal/
553+--
554+withCString :: Array a -> (CString -> IO b) -> IO b
555+withCString arr act = do
556+ let Array{..} = castWord8 arr <> A.fromList [0]
557+ withForeignPtr aStart $ \ptr -> act (castPtr ptr)
558+
559+-------------------------------------------------------------------------------
560+-- Folds
561+-------------------------------------------------------------------------------
562+
491563-- | Fold an array using a 'Fold'.
492564--
493565-- /Internal/