    {-# LANGUAGE CPP                 #-}
    {-# LANGUAGE MagicHash           #-}
    {-# LANGUAGE RankNTypes          #-}
    {-# LANGUAGE TypeFamilies        #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    -- |
    -- Module      : Codec.CBOR.ByteArray
    -- Copyright   : (c) Ben Gamari 2017-2018
    -- License     : BSD3-style (see LICENSE.txt)
    --
    -- Maintainer  : duncan@community.haskell.org
    -- Stability   : experimental
    -- Portability : non-portable (GHC extensions)
    --
    -- A ByteArray with more instances than 'Data.Primitive.ByteArray.ByteArray'.
    -- Some day when these instances are reliably available from @primitive@ we can
    -- likely replace this with 'Data.Primitive.ByteArray.ByteArray'.
    --
    module Codec.CBOR.ByteArray
      ( -- * Simple byte arrays
        ByteArray(..)
      , sizeofByteArray
        -- * Conversions
      , fromShortByteString
      , toShortByteString
      , fromByteString
      , toBuilder
      , toSliced
      ) where

    import Data.Char (ord)
    import Data.Word
    import GHC.Exts (IsList(..), IsString(..))

    import qualified Data.Primitive.ByteArray as Prim
    import qualified Data.ByteString as BS
    import qualified Data.ByteString.Short as BSS
    import qualified Data.ByteString.Short.Internal as BSS
    import qualified Data.ByteString.Builder as BSB

    import qualified Codec.CBOR.ByteArray.Sliced as Sliced
    import           Codec.CBOR.ByteArray.Internal

    newtype ByteArray = BA {ByteArray -> ByteArray
    unBA :: Prim.ByteArray}

    sizeofByteArray :: ByteArray -> Int
    {-# INLINE sizeofByteArray #-}
    sizeofByteArray :: ByteArray -> Int
    sizeofByteArray (BA ByteArray
    ba) = ByteArray -> Int
    Prim.sizeofByteArray ByteArray
    ba

    fromShortByteString :: BSS.ShortByteString -> ByteArray
    fromShortByteString :: ShortByteString -> ByteArray
    fromShortByteString (BSS.SBS ByteArray#
    ba) = ByteArray -> ByteArray
    BA (ByteArray# -> ByteArray
    Prim.ByteArray ByteArray#
    ba)

    toShortByteString :: ByteArray -> BSS.ShortByteString
    toShortByteString :: ByteArray -> ShortByteString
    toShortByteString (BA (Prim.ByteArray ByteArray#
    ba)) = ByteArray# -> ShortByteString
    BSS.SBS ByteArray#
    ba

    fromByteString :: BS.ByteString -> ByteArray
    fromByteString :: ByteString -> ByteArray
    fromByteString = ShortByteString -> ByteArray
    fromShortByteString (ShortByteString -> ByteArray)
    -> (ByteString -> ShortByteString) -> ByteString -> ByteArray
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> ShortByteString
    BSS.toShort

    toBuilder :: ByteArray -> BSB.Builder
    toBuilder :: ByteArray -> Builder
    toBuilder = SlicedByteArray -> Builder
    Sliced.toBuilder (SlicedByteArray -> Builder)
    -> (ByteArray -> SlicedByteArray) -> ByteArray -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteArray -> SlicedByteArray
    toSliced

    toSliced :: ByteArray -> Sliced.SlicedByteArray
    toSliced :: ByteArray -> SlicedByteArray
    toSliced ba :: ByteArray
    ba@(BA ByteArray
    arr) = ByteArray -> Int -> Int -> SlicedByteArray
    Sliced.SBA ByteArray
    arr Int
    0 (ByteArray -> Int
    sizeofByteArray ByteArray
    ba)

    instance Show ByteArray where
      showsPrec :: Int -> ByteArray -> ShowS
    showsPrec Int
    _ = SlicedByteArray -> ShowS
    forall a. Show a => a -> ShowS
    shows (SlicedByteArray -> ShowS)
    -> (ByteArray -> SlicedByteArray) -> ByteArray -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteArray -> SlicedByteArray
    toSliced

    instance Eq ByteArray where
      ByteArray
    ba1 == :: ByteArray -> ByteArray -> Bool
    == ByteArray
    ba2 = ByteArray -> SlicedByteArray
    toSliced ByteArray
    ba1 SlicedByteArray -> SlicedByteArray -> Bool
    forall a. Eq a => a -> a -> Bool
    == ByteArray -> SlicedByteArray
    toSliced ByteArray
    ba2

    instance Ord ByteArray where
      ByteArray
    ba1 compare :: ByteArray -> ByteArray -> Ordering
    `compare` ByteArray
    ba2 = ByteArray -> SlicedByteArray
    toSliced ByteArray
    ba1 SlicedByteArray -> SlicedByteArray -> Ordering
    forall a. Ord a => a -> a -> Ordering
    `compare` ByteArray -> SlicedByteArray
    toSliced ByteArray
    ba2

    instance IsString ByteArray where
      fromString :: String -> ByteArray
    fromString = [Word8] -> ByteArray
    [Item ByteArray] -> ByteArray
    forall l. IsList l => [Item l] -> l
    fromList ([Word8] -> ByteArray)
    -> (String -> [Word8]) -> String -> ByteArray
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Word8) -> String -> [Word8]
    forall a b. (a -> b) -> [a] -> [b]
    map Char -> Word8
    forall {a}. Num a => Char -> a
    checkedOrd
        where
          checkedOrd :: Char -> a
    checkedOrd Char
    c
            | Char
    c Char -> Char -> Bool
    forall a. Ord a => a -> a -> Bool
    > Char
    '\xff' = String -> a
    forall a. HasCallStack => String -> a
    error String
    "IsString(Codec.CBOR.ByteArray): Non-ASCII character"
            | Bool
    otherwise  = Int -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int -> a) -> Int -> a
    forall a b. (a -> b) -> a -> b
    $ Char -> Int
    ord Char
    c

    instance IsList ByteArray where
      type Item ByteArray = Word8
      fromList :: [Item ByteArray] -> ByteArray
    fromList [Item ByteArray]
    xs = Int -> [Item ByteArray] -> ByteArray
    forall l. IsList l => Int -> [Item l] -> l
    fromListN ([Word8] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    Prelude.length [Word8]
    [Item ByteArray]
    xs) [Item ByteArray]
    xs
      fromListN :: Int -> [Item ByteArray] -> ByteArray
    fromListN Int
    n [Item ByteArray]
    xs =
          let arr :: ByteArray
    arr = Int -> [Word8] -> ByteArray
    mkByteArray Int
    n [Word8]
    [Item ByteArray]
    xs
          in ByteArray -> ByteArray
    BA ByteArray
    arr
      toList :: ByteArray -> [Item ByteArray]
    toList ba :: ByteArray
    ba@(BA ByteArray
    arr) =
          (Word8 -> [Word8] -> [Word8])
    -> [Word8] -> Int -> Int -> ByteArray -> [Word8]
    forall a. (Word8 -> a -> a) -> a -> Int -> Int -> ByteArray -> a
    foldrByteArray (:) [] Int
    0 (ByteArray -> Int
    sizeofByteArray ByteArray
    ba) ByteArray
    arr