@@ -62,6 +62,7 @@ module Streamly.Memory.Array.Types
6262 , toList
6363 , writeN
6464 , read
65+ , readU
6566
6667 -- * Utilities
6768 , defaultChunkSize
@@ -100,6 +101,7 @@ import GHC.IO (IO(IO), unsafePerformIO)
100101import GHC.Ptr (Ptr(..))
101102
102103import Streamly.Fold.Types (Fold(..))
104+import Streamly.Unfold.Types (Unfold(..))
103105import Streamly.Strict (Tuple'(..))
104106import Streamly.SVar (adaptState)
105107
@@ -388,6 +390,31 @@ byteCapacity Array{..} =
388390 len = aBound `minusPtr` p
389391 in assert (len >= 0) len
390392
393+{-# INLINE_NORMAL readU #-}
394+readU :: forall m a. (Monad m, Storable a) => Unfold m (Array a) a
395+readU = Unfold step inject
396+ where
397+
398+ -- Note we have repurposed the Array type here
399+ inject Array{..} =
400+ return $ Array aStart (unsafeForeignPtrToPtr aStart) aEnd
401+
402+ {-# INLINE_LATE step #-}
403+ step (Array _ p end) | p == end = return D.Stop
404+ step (Array start p end) = do
405+ -- unsafeInlineIO allows us to run this in Identity monad for pure
406+ -- toList/foldr case which makes them much faster due to not
407+ -- accumulating the list and fusing better with the pure consumers.
408+ --
409+ -- This should be safe as the array contents are guaranteed to be
410+ -- evaluated/written to before we peek at them.
411+ let !x = unsafeInlineIO $ do
412+ r <- peek p
413+ touchForeignPtr start
414+ return r
415+ return $ D.Yield x
416+ (Array start (p `plusPtr` (sizeOf (undefined :: a))) end)
417+
391418{-# INLINE_NORMAL toStreamD #-}
392419toStreamD :: forall m a. (Monad m, Storable a) => Array a -> D.Stream m a
393420toStreamD Array{..} =