Как конвертировать между ByteString и Storable Vector?

Каков наилучший способ преобразования между Storable.Vector Word8 и строгим ByteString?

Конечно, наиболее ценным был бы метод non-copy (no-op).

Должен ли я просто unsafeCoerce или есть библиотека для этого (я не мог найти его)?

Кроме того, будет ли подход одинаковым для Unboxed.Vector Word8?

Ответ 1

Простой unsafeCoerce не будет работать, поскольку компоновка конструкторов данных отличается:

data StorableArray i e = StorableArray !i !i Int !(ForeignPtr e)

против.

data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                     {-# UNPACK #-} !Int                -- offset
                     {-# UNPACK #-} !Int                -- length

Вы можете импортировать Data.Array.Storable.Internals и Data.ByteString.Internal, чтобы получить доступ к исходным конструкторам, а затем построить один из них без копирования данных:

> 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))

(Я удалил довольно длинное приглашение Prelude Data.Array.Storable.Internals Data.ByteString.Internal Data.ByteString>).

Это не будет работать для Data.Vector.Unboxed, потому что здесь данные находятся в куче Haskell и управляются средой выполнения GHC, в то время как другие два управляют данными вне кучи Haskell.