content: {-# LANGUAGE ForeignFunctionInterface #-}
  
  module Network.HPACK.Huffman.ByteString (
      unpack4bits,
      copy,
  ) where
  
  import Foreign.C.Types (CSize (..))
  import Foreign.Ptr (Ptr, plusPtr)
  import Foreign.Storable (peek)
  import System.IO.Unsafe (unsafeDupablePerformIO)
  
  import Imports
  
  -- $setup
  -- >>> import qualified Data.ByteString as BS
  
  -- |
  --
  -- >>> let bs = BS.pack [0x12,0x34,0xf3,0xab]
  -- >>> unpack4bits bs
  -- [1,2,3,4,15,3,10,11]
  -- >>> unpack4bits $ BS.tail bs
  -- [3,4,15,3,10,11]
  unpack4bits :: ByteString -> [Word8]
  unpack4bits (PS fptr off len) = unsafeDupablePerformIO $
      withForeignPtr fptr $ \ptr -> do
          let lim = ptr `plusPtr` (off - 1)
              end = ptr `plusPtr` (off + len - 1)
          go lim end []
    where
      go lim p ws
          | lim == p = return ws
          | otherwise = do
              w <- peek p
              let w0 = w `shiftR` 4
                  w1 = w .&. 0xf
              go lim (p `plusPtr` (-1)) (w0 : w1 : ws)
  
  copy :: Ptr Word8 -> ByteString -> IO ()
  copy dst (PS fptr off len) = withForeignPtr fptr $ \ptr -> do
      let beg = ptr `plusPtr` off
      memcpy dst beg (fromIntegral len)
  
  foreign import ccall unsafe "string.h memcpy"
      c_memcpy
          :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
  
  memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
  memcpy dst src s = void $ c_memcpy dst src (fromIntegral s)
  