Blame Data/ByteArray/Types.hs

Packit c1c4f9
-- |
Packit c1c4f9
-- Module      : Data.ByteArray.Types
Packit c1c4f9
-- License     : BSD-style
Packit c1c4f9
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
Packit c1c4f9
-- Stability   : stable
Packit c1c4f9
-- Portability : Good
Packit c1c4f9
--
Packit c1c4f9
{-# LANGUAGE CPP #-}
Packit c1c4f9
{-# LANGUAGE BangPatterns #-}
Packit c1c4f9
module Data.ByteArray.Types
Packit c1c4f9
    ( ByteArrayAccess(..)
Packit c1c4f9
    , ByteArray(..)
Packit c1c4f9
    ) where
Packit c1c4f9
Packit c1c4f9
import           Foreign.Ptr
Packit c1c4f9
import           Data.Monoid
Packit c1c4f9
Packit c1c4f9
#ifdef WITH_BYTESTRING_SUPPORT
Packit c1c4f9
import qualified Data.ByteString as Bytestring (length)
Packit c1c4f9
import qualified Data.ByteString.Internal as Bytestring
Packit c1c4f9
import           Foreign.ForeignPtr (withForeignPtr)
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
#ifdef WITH_FOUNDATION_SUPPORT
Packit c1c4f9
Packit c1c4f9
#if MIN_VERSION_foundation(0,0,14) && MIN_VERSION_basement(0,0,0)
Packit c1c4f9
# define NO_LEGACY_FOUNDATION_SUPPORT
Packit c1c4f9
#else
Packit c1c4f9
# define LEGACY_FOUNDATION_SUPPORT
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
import           Data.Proxy (Proxy(..))
Packit c1c4f9
import           Data.Word (Word8)
Packit c1c4f9
Packit c1c4f9
import qualified Basement.Types.OffsetSize as Base
Packit c1c4f9
import qualified Basement.UArray as Base
Packit c1c4f9
import qualified Basement.String as Base (String, toBytes, Encoding(UTF8))
Packit c1c4f9
import qualified Basement.PrimType as Base (primSizeInBytes)
Packit c1c4f9
Packit c1c4f9
#ifdef LEGACY_FOUNDATION_SUPPORT
Packit c1c4f9
Packit c1c4f9
import qualified Foundation as F
Packit c1c4f9
import qualified Foundation.Collection as F
Packit c1c4f9
import qualified Foundation.String as F (toBytes, Encoding(UTF8))
Packit c1c4f9
import qualified Foundation.Array.Internal as F
Packit c1c4f9
import qualified Foundation.Primitive as F (primSizeInBytes)
Packit c1c4f9
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
-- | Class to Access size properties and data of a ByteArray
Packit c1c4f9
class ByteArrayAccess ba where
Packit c1c4f9
    -- | Return the length in bytes of a bytearray
Packit c1c4f9
    length        :: ba -> Int
Packit c1c4f9
    -- | Allow to use using a pointer
Packit c1c4f9
    withByteArray :: ba -> (Ptr p -> IO a) -> IO a
Packit c1c4f9
Packit c1c4f9
-- | Class to allocate new ByteArray of specific size
Packit c1c4f9
class (Eq ba, Ord ba, Monoid ba, ByteArrayAccess ba) => ByteArray ba where
Packit c1c4f9
    -- | allocate `n` bytes and perform the given operation
Packit c1c4f9
    allocRet  :: Int
Packit c1c4f9
                -- ^ number of bytes to allocate. i.e. might not match the
Packit c1c4f9
                -- size of the given type `ba`.
Packit c1c4f9
              -> (Ptr p -> IO a)
Packit c1c4f9
              -> IO (a, ba)
Packit c1c4f9
Packit c1c4f9
#ifdef WITH_BYTESTRING_SUPPORT
Packit c1c4f9
instance ByteArrayAccess Bytestring.ByteString where
Packit c1c4f9
    length = Bytestring.length
Packit c1c4f9
    withByteArray (Bytestring.PS fptr off _) f = withForeignPtr fptr $ \ptr -> f $! (ptr `plusPtr` off)
Packit c1c4f9
Packit c1c4f9
instance ByteArray Bytestring.ByteString where
Packit c1c4f9
    allocRet sz f = do
Packit c1c4f9
        fptr <- Bytestring.mallocByteString sz
Packit c1c4f9
        r    <- withForeignPtr fptr (f . castPtr)
Packit c1c4f9
        return (r, Bytestring.PS fptr 0 sz)
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
#ifdef WITH_FOUNDATION_SUPPORT
Packit c1c4f9
Packit c1c4f9
baseUarrayRecastW8 :: Base.PrimType ty => Base.UArray ty -> Base.UArray Word8
Packit c1c4f9
baseUarrayRecastW8 = Base.recast
Packit c1c4f9
Packit c1c4f9
instance Base.PrimType ty => ByteArrayAccess (Base.UArray ty) where
Packit c1c4f9
    length a = let Base.CountOf i = Base.length (baseUarrayRecastW8 a) in i
Packit c1c4f9
    withByteArray a f = Base.withPtr (baseUarrayRecastW8 a) (f . castPtr)
Packit c1c4f9
Packit c1c4f9
instance ByteArrayAccess Base.String where
Packit c1c4f9
    length str = let Base.CountOf i = Base.length bytes in i
Packit c1c4f9
      where
Packit c1c4f9
        -- the Foundation's length return a number of elements not a number of
Packit c1c4f9
        -- bytes. For @ByteArrayAccess@, because we are using an @Int@, we
Packit c1c4f9
        -- didn't see that we were returning the wrong @CountOf@.
Packit c1c4f9
        bytes = Base.toBytes Base.UTF8 str
Packit c1c4f9
    withByteArray s f = withByteArray (Base.toBytes Base.UTF8 s) f
Packit c1c4f9
Packit c1c4f9
instance (Ord ty, Base.PrimType ty) => ByteArray (Base.UArray ty) where
Packit c1c4f9
    allocRet sz f = do
Packit c1c4f9
        mba <- Base.new $ sizeRecastBytes sz Proxy
Packit c1c4f9
        a   <- Base.withMutablePtr mba (f . castPtr)
Packit c1c4f9
        ba  <- Base.unsafeFreeze mba
Packit c1c4f9
        return (a, ba)
Packit c1c4f9
      where
Packit c1c4f9
        sizeRecastBytes :: Base.PrimType ty => Int -> Proxy ty -> Base.CountOf ty
Packit c1c4f9
        sizeRecastBytes w p = Base.CountOf $
Packit c1c4f9
            let (q,r) = w `Prelude.quotRem` szTy
Packit c1c4f9
             in q + (if r == 0 then 0 else 1)
Packit c1c4f9
          where !(Base.CountOf szTy) = Base.primSizeInBytes p
Packit c1c4f9
        {-# INLINE [1] sizeRecastBytes #-}
Packit c1c4f9
Packit c1c4f9
#ifdef LEGACY_FOUNDATION_SUPPORT
Packit c1c4f9
Packit c1c4f9
uarrayRecastW8 :: F.PrimType ty => F.UArray ty -> F.UArray Word8
Packit c1c4f9
uarrayRecastW8 = F.recast
Packit c1c4f9
Packit c1c4f9
instance F.PrimType ty => ByteArrayAccess (F.UArray ty) where
Packit c1c4f9
#if MIN_VERSION_foundation(0,0,10)
Packit c1c4f9
    length a = let F.CountOf i = F.length (uarrayRecastW8 a) in i
Packit c1c4f9
#else
Packit c1c4f9
    length = F.length . uarrayRecastW8
Packit c1c4f9
#endif
Packit c1c4f9
    withByteArray a f = F.withPtr (uarrayRecastW8 a) (f . castPtr)
Packit c1c4f9
Packit c1c4f9
instance ByteArrayAccess F.String where
Packit c1c4f9
#if MIN_VERSION_foundation(0,0,10)
Packit c1c4f9
    length str = let F.CountOf i = F.length bytes in i
Packit c1c4f9
#else
Packit c1c4f9
    length str = F.length bytes
Packit c1c4f9
#endif
Packit c1c4f9
      where
Packit c1c4f9
        -- the Foundation's length return a number of elements not a number of
Packit c1c4f9
        -- bytes. For @ByteArrayAccess@, because we are using an @Int@, we
Packit c1c4f9
        -- didn't see that we were returning the wrong @CountOf@.
Packit c1c4f9
        bytes = F.toBytes F.UTF8 str
Packit c1c4f9
    withByteArray s f = withByteArray (F.toBytes F.UTF8 s) f
Packit c1c4f9
Packit c1c4f9
instance (Ord ty, F.PrimType ty) => ByteArray (F.UArray ty) where
Packit c1c4f9
    allocRet sz f = do
Packit c1c4f9
        mba <- F.new $ sizeRecastBytes sz Proxy
Packit c1c4f9
        a   <- F.withMutablePtr mba (f . castPtr)
Packit c1c4f9
        ba  <- F.unsafeFreeze mba
Packit c1c4f9
        return (a, ba)
Packit c1c4f9
      where
Packit c1c4f9
#if MIN_VERSION_foundation(0,0,10)
Packit c1c4f9
        sizeRecastBytes :: F.PrimType ty => Int -> Proxy ty -> F.CountOf ty
Packit c1c4f9
        sizeRecastBytes w p = F.CountOf $
Packit c1c4f9
            let (q,r) = w `Prelude.quotRem` szTy
Packit c1c4f9
             in q + (if r == 0 then 0 else 1)
Packit c1c4f9
          where !(F.CountOf szTy) = F.primSizeInBytes p
Packit c1c4f9
        {-# INLINE [1] sizeRecastBytes #-}
Packit c1c4f9
#else
Packit c1c4f9
        sizeRecastBytes :: F.PrimType ty => Int -> Proxy ty -> F.Size ty
Packit c1c4f9
        sizeRecastBytes w p = F.Size $
Packit c1c4f9
            let (q,r) = w `Prelude.quotRem` szTy
Packit c1c4f9
             in q + (if r == 0 then 0 else 1)
Packit c1c4f9
          where !(F.Size szTy) = F.primSizeInBytes p
Packit c1c4f9
        {-# INLINE [1] sizeRecastBytes #-}
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
#endif
Packit c1c4f9
Packit c1c4f9
Packit c1c4f9
#endif