    {-|

    Module      :  Data.Array.BitArray.ByteString
    Copyright   :  (c) Claude Heiland-Allen 2012,2018
    License     :  BSD3

    Maintainer  :  claude@mathr.co.uk
    Stability   :  unstable
    Portability :  portable

    Copy bit array data to and from ByteStrings.

    -}
    module Data.Array.BitArray.ByteString
      (
      -- * Immutable copying.
        toByteString
      , fromByteString
      -- * Mutable copying.
      , toByteStringIO
      , fromByteStringIO
      ) where

    import Data.Bits (shiftR, (.&.))
    import Data.ByteString (ByteString, packCStringLen)
    import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
    import Data.Ix (Ix, rangeSize)
    import Data.Word (Word8)
    import Control.Monad (when)
    import Foreign.ForeignPtr (withForeignPtr)
    import Foreign.Marshal.Utils (copyBytes)
    import Foreign.Ptr (castPtr)
    import Foreign.Storable (peekByteOff, pokeByteOff)
    import System.IO.Unsafe (unsafePerformIO)

    import Data.Bits.Bitwise (mask)
    import Data.Array.BitArray (BitArray)
    import Data.Array.BitArray.IO (IOBitArray)
    import qualified Data.Array.BitArray.IO as IO
    import Data.Array.BitArray.Internal (iobData)

    -- | Copy to a ByteString.  The most significant bits of the last byte
    --   are padded with 0 unless the array was a multiple of 8 bits in size.
    toByteString :: Ix i => BitArray i -> ByteString
    toByteString :: forall i. Ix i => BitArray i -> ByteString
    toByteString BitArray i
    a = IO ByteString -> ByteString
    forall a. IO a -> a
    unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ IOBitArray i -> IO ByteString
    forall i. Ix i => IOBitArray i -> IO ByteString
    toByteStringIO (IOBitArray i -> IO ByteString)
    -> IO (IOBitArray i) -> IO ByteString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< BitArray i -> IO (IOBitArray i)
    forall i. Ix i => BitArray i -> IO (IOBitArray i)
    IO.unsafeThaw BitArray i
    a

    -- | Copy from a ByteString.  Much like 'listArray' but with packed bits.
    fromByteString :: Ix i => (i, i) {- ^ bounds -} -> ByteString {- ^ packed elems -} -> BitArray i
    fromByteString :: forall i. Ix i => (i, i) -> ByteString -> BitArray i
    fromByteString (i, i)
    bs ByteString
    s = IO (BitArray i) -> BitArray i
    forall a. IO a -> a
    unsafePerformIO (IO (BitArray i) -> BitArray i) -> IO (BitArray i) -> BitArray i
    forall a b. (a -> b) -> a -> b
    $ IOBitArray i -> IO (BitArray i)
    forall i. Ix i => IOBitArray i -> IO (BitArray i)
    IO.unsafeFreeze (IOBitArray i -> IO (BitArray i))
    -> IO (IOBitArray i) -> IO (BitArray i)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (i, i) -> ByteString -> IO (IOBitArray i)
    forall i. Ix i => (i, i) -> ByteString -> IO (IOBitArray i)
    fromByteStringIO (i, i)
    bs ByteString
    s

    -- | Copy to a ByteString.  The most significant bits of the last byte
    --   are padded with 0 unless the array was a multiple of 8 bits in size.
    toByteStringIO :: Ix i => IOBitArray i -> IO ByteString
    toByteStringIO :: forall i. Ix i => IOBitArray i -> IO ByteString
    toByteStringIO IOBitArray i
    a = do
      bs <- IOBitArray i -> IO (i, i)
    forall i. Ix i => IOBitArray i -> IO (i, i)
    IO.getBounds IOBitArray i
    a
      let rs = (i, i) -> Int
    forall a. Ix a => (a, a) -> Int
    rangeSize (i, i)
    bs
          bytes = (Int
    rs Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    7) Int -> Int -> Int
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    3
          bits = Int
    rs Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    7
          lastByte = Int
    bytes Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1
      withForeignPtr (iobData a) $ \Ptr Word64
    p -> do
        Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Int
    bits Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    0) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do
          b <- Ptr Word64 -> Int -> IO Word8
    forall b. Ptr b -> Int -> IO Word8
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr Word64
    p Int
    lastByte
          pokeByteOff p lastByte (b .&. mask bits :: Word8)
        CStringLen -> IO ByteString
    packCStringLen (Ptr Word64 -> Ptr CChar
    forall a b. Ptr a -> Ptr b
    castPtr Ptr Word64
    p, Int
    bytes)

    -- | Copy from a ByteString.  Much like 'newListArray' but with packed bits.
    fromByteStringIO :: Ix i => (i, i) {- ^ bounds -} -> ByteString {- ^ packed elems -} -> IO (IOBitArray i)
    fromByteStringIO :: forall i. Ix i => (i, i) -> ByteString -> IO (IOBitArray i)
    fromByteStringIO (i, i)
    bs ByteString
    s = do
      a <- (i, i) -> Bool -> IO (IOBitArray i)
    forall i. Ix i => (i, i) -> Bool -> IO (IOBitArray i)
    IO.newArray (i, i)
    bs Bool
    False
      let rs = (i, i) -> Int
    forall a. Ix a => (a, a) -> Int
    rangeSize (i, i)
    bs
          bytes = (Int
    rs Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    7) Int -> Int -> Int
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    3
      unsafeUseAsCStringLen s $ \(Ptr CChar
    src, Int
    len) ->
        ForeignPtr Word64 -> (Ptr Word64 -> IO ()) -> IO ()
    forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
    withForeignPtr (IOBitArray i -> ForeignPtr Word64
    forall i. IOBitArray i -> ForeignPtr Word64
    iobData IOBitArray i
    a) ((Ptr Word64 -> IO ()) -> IO ()) -> (Ptr Word64 -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word64
    dst ->
          Ptr Word64 -> Ptr Word64 -> Int -> IO ()
    forall a. Ptr a -> Ptr a -> Int -> IO ()
    copyBytes Ptr Word64
    dst (Ptr CChar -> Ptr Word64
    forall a b. Ptr a -> Ptr b
    castPtr Ptr CChar
    src) (Int
    bytes Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    `min` Int
    len)
      return a