@@ -30,6 +30,8 @@ module Streamly.Internal.Memory.Array.Types
3030 , spliceWithDoubling
3131 , spliceTwo
3232
33+ , fromAddr#
34+ , fromString#
3335 , fromList
3436 , fromListN
3537 , fromStreamDN
@@ -355,18 +357,74 @@ shrinkToFit arr@Array{..} = do
355357 then realloc used arr
356358 else return arr
357359
358−-- XXX when converting an array of Word8 from a literal string we can simply
359−-- refer to the literal string. Is it possible to write rules such that
360−-- fromList Word8 can be rewritten so that GHC does not first convert the
361−-- literal to [Char] and then we convert it back to an Array Word8?
360+-- See also: https://gitlab.haskell.org/ghc/ghc/issues/5218 (Add
361+-- unpackCStringLen# to create Strings from string literals)
362362--
363−-- Note that the address must be a read-only address (meant to be used for
364−-- read-only string literals) because we are sharing it, any modification to
365−-- the original address would change our array. That's why this function is
366−-- unsafe.
367−{-# INLINE _fromCStringAddrUnsafe #-}
368−_fromCStringAddrUnsafe :: Addr# -> IO (Array Word8)
369−_fromCStringAddrUnsafe addr# = do
363+-- TBD: We can also add template haskell quasiquotes to specify arrays of other
364+-- literal types. TH will encode them into a string literal and we read that as
365+-- an array of the required type. With template Haskell we can provide a safe
366+-- version of fromString#.
367+--
368+-- | Create an @Array Word8@ of the given length from a machine address
369+-- 'Addr#'. This API is unsafe for the following reasons:
370+--
371+-- 1. The address must point to pinned memory or foreign memory.
372+-- 2. The address must be legally accessible upto the given length.
373+-- 3. To guarantee that the array is immutable, the contents of the address
374+-- must be guaranteed to not change.
375+--
376+-- A common use case for this API is to create an array from a static unboxed
377+-- string literal. GHC string literals are of type 'Addr#', and must contain
378+-- characters that can be encoded in a byte i.e. characters or literal bytes in
379+-- the range from 0-255.
380+--
381+-- >>> fromAddr# 5 "hello world!"#
382+-- > [104,101,108,108,111]
383+--
384+-- >>> fromAddr# 3 "\255\NUL\255"#
385+-- > [255,0,255]
386+--
387+-- /See also: 'fromString#'/
388+--
389+-- /Unsafe/
390+--
391+-- /Time complexity: O(1)/
392+--
393+{-# INLINE fromAddr# #-}
394+fromAddr# :: Int -> Addr# -> IO (Array Word8)
395+fromAddr# n addr# = do
396+ ptr <- newForeignPtr_ (castPtr $ Ptr addr#)
397+ let p = unsafeForeignPtrToPtr ptr
398+ let end = p `plusPtr` n
399+ return $ Array
400+ { aStart = ptr
401+ , aEnd = end
402+ , aBound = end
403+ }
404+
405+-- | Like 'fromAddr#' but determines the length of the array upto and excluding
406+-- the first @0@ byte. The address must be legally accessible up to the first
407+-- NUL byte.
408+--
409+-- A common use case for this API is to create an array from an unboxed string
410+-- literal. Unboxed string literals are guaranteed to be terminated by a NUL
411+-- byte.
412+--
413+-- >>> fromString# "hello world!"#
414+-- > [104,101,108,108,111,32,119,111,114,108,100,33]
415+--
416+-- >>> fromString# "\255\NUL\255"#
417+-- > [255]
418+--
419+-- /See also: 'fromAddr#', 'fromString'/
420+--
421+-- /Unsafe/
422+--
423+-- /Time complexity: O(n) (computes the length of the string)/
424+--
425+{-# INLINE fromString# #-}
426+fromString# :: Addr# -> IO (Array Word8)
427+fromString# addr# = do
370428 ptr <- newForeignPtr_ (castPtr cstr)
371429 len <- c_strlen cstr
372430 let n = fromIntegral len