Эффективно конвертировать Foreign.Ptr Word8 (или ByteString) в UArray Int Word8 - PullRequest
0 голосов
/ 12 июня 2018

Я делаю захват сети с помощью Network.Pcap ( pcap ) и планирую провести некоторые проверки с использованием Net.PacketParsing ( network-house ).Для этого, похоже, мне нужно поместить мой пакет в

Pcap.Callback :: PktHdr -> Ptr Word8 -> IO ()

или

Pcap.CallbackBS :: PktHdr -> ByteString -> IO ().

и работать с пакетом как 'Ptr Word8' или 'ByteString».На стороне разбора пакета у меня есть:

Net.Packet.toInPack :: UArray Int Word8 -> InPacket

, чтобы получить тип InPacket, необходимый для анализа.Итак, мне осталось преобразовать Ptr или ByteString в UArray - либо чисто, либо в IO.Я полагаю, что могу распаковать ByteString в [Word8], а оттуда в UArray, но, похоже, должен быть лучший способ.

Я также обеспокоен своим выбором библиотек,В прошлом я использовал network-house и нашел его довольно хорошим, но он стареет и использует UArray, который сам по себе выглядит немного архаичным.Так что предложения о лучшей отправной точке приветствуются.

1 Ответ

0 голосов
/ 13 июня 2018

ByteString и Ptr Word8 указывают на внешнюю кучу, в то время как UArray в куче GHC, поэтому любая функция преобразования должна копировать данные.

Я не нашел никакой функции прямого преобразования в библиотеках, но, к счастью, есть примитив GHC, который делает именно то, что мы хотим, называемый copyAddrToByteArray#.Это позволяет нам конвертировать с минимальными накладными расходами:

{-# language MagicHash, UnboxedTuples #-}

import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.Array.Base as A

import GHC.Types
import GHC.Prim
import GHC.Magic (runRW#)
import GHC.ForeignPtr
import Data.Word

-- when using GHC 8.2.x or later:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
  runRW# $ \s -> case newByteArray# len s of
    (# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
      s -> case unsafeFreezeByteArray# marr s of
        (# _, arr #) -> A.UArray 0 (I# (len -# 1#)) (I# len) arr
{-# inline byteStringToUArray #-}

-- when using GHC 8.0.x:
byteStringToUArray :: B.ByteString -> A.UArray Int Word8
byteStringToUArray (B.PS (ForeignPtr addr _) (I# start) (I# len)) =
  case (runRW# $ \s -> case newByteArray# len s of
    (# s, marr #) -> case copyAddrToByteArray# (plusAddr# addr start) marr 0# len s of
      s -> case unsafeFreezeByteArray# marr s of
        (# s, arr #) -> (# s, A.UArray 0 (I# (len -# 1#)) (I# len) arr #)) of
    (# _, res #) -> res
{-# inline byteStringToUArray #-}

Но в целом вы правы, что array устарел и теперь используется редко.

...