What is the best way to convert between Storable.Vector Word8
and a strict ByteString
?
Of course a non-copying (no-op) way would be most appreciated.
Should I just unsafeCoerce
or is there a library function for that (I couldn't find one)?
Also, will the approach be the same for an Unboxed.Vector Word8
?
A simple unsafeCoerce
will not work, as the layout of the data constructors is different:
data StorableArray i e = StorableArray !i !i Int !(ForeignPtr e)
vs.
data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
{-# UNPACK #-} !Int -- offset
{-# UNPACK #-} !Int -- length
You can import Data.Array.Storable.Internals
and Data.ByteString.Internal
to get access to the raw constructors and then construct one out of the other without copying the data:
> let bs = pack [1,2,3]
> bs
"\SOH\STX\ETX"
> let sa = case bs of (PS ptr 0 n) -> StorableArray 0 (n-1) n ptr
> :t sa
sa :: StorableArray Int GHC.Word.Word8
> Data.Array.MArray.readArray sa 1
2
> Data.Array.MArray.readArray sa 0
1
> Data.Array.MArray.readArray sa 3
*** Exception: Ix{Int}.index: Index (3) out of range ((0,2))
(I removed the rather long prompt of Prelude Data.Array.Storable.Internals Data.ByteString.Internal Data.ByteString>
).
This will not work for Data.Vector.Unboxed
, because here the data is on the Haskell heap and managed by the GHC runtime, while the other two manage the data outside the Haskell heap.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With