有效地将Foreign.Ptr Word8(或ByteString)转换为UArray Int Word8

tre*_*ook 5 parsing haskell packet pcap

我正在使用Network.Pcap(pcap)进行一些网络捕获,并计划使用Net.PacketParsing(网络中心)进行一些检查.为此,看起来我必须将我的数据包解析

Pcap.Callback :: PktHdr -> Ptr Word8 -> IO ()
Run Code Online (Sandbox Code Playgroud)

要么

Pcap.CallbackBS :: PktHdr -> ByteString -> IO ().
Run Code Online (Sandbox Code Playgroud)

并将数据包作为'Ptr Word8'或'ByteString'处理.在数据包解析方面,我有:

Net.Packet.toInPack :: UArray Int Word8 -> InPacket
Run Code Online (Sandbox Code Playgroud)

获得InPacket解析所需的类型.那么,剩下的就是将'Ptr'或'ByteString'转换为'UArray' - 无论是纯粹还是IO.我想我可以拆开ByteString[Word8],并从那里到UArray,但好像必须有一个更好的办法.

我也很关心我选择的库.我过去曾经使用过网络设备并发现它非常好,但它已经老了并且使用了UArray,它本身看起来有点陈旧.因此欢迎提出更好的起点建议.

And*_*ács 1

ByteStringPtr 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 #-}
Run Code Online (Sandbox Code Playgroud)

但总的来说,你是对的,它array已经过时了,现在很少使用。