{-# language BangPatterns #-}
{-# language TypeApplications #-}
module Data.Bytes
(
Bytes
, null
, length
, takeWhile
, dropWhile
, unsafeTake
, unsafeDrop
, toByteArray
, toByteArrayClone
, fromAsciiString
, fromByteArray
) where
import Prelude hiding (length,takeWhile,dropWhile,null)
import Data.Bytes.Types (Bytes(Bytes))
import Data.Primitive (ByteArray)
import Data.Word (Word8)
import Data.Char (ord)
import Control.Monad.ST.Run (runByteArrayST)
import qualified Data.Primitive as PM
import qualified GHC.Exts as Exts
null :: Bytes -> Bool
null (Bytes _ _ len) = len == 0
length :: Bytes -> Int
length (Bytes _ _ len) = len
takeWhile :: (Word8 -> Bool) -> Bytes -> Bytes
{-# inline takeWhile #-}
takeWhile k b = unsafeTake (countWhile k b) b
dropWhile :: (Word8 -> Bool) -> Bytes -> Bytes
{-# inline dropWhile #-}
dropWhile k b = unsafeDrop (countWhile k b) b
unsafeTake :: Int -> Bytes -> Bytes
{-# inline unsafeTake #-}
unsafeTake n (Bytes arr off _) =
Bytes arr off n
unsafeDrop :: Int -> Bytes -> Bytes
{-# inline unsafeDrop #-}
unsafeDrop n (Bytes arr off len) =
Bytes arr (off + n) (len - n)
countWhile :: (Word8 -> Bool) -> Bytes -> Int
{-# inline countWhile #-}
countWhile k (Bytes arr off0 len0) = go off0 len0 0 where
go !off !len !n = if len > 0
then if k (PM.indexByteArray arr off)
then go (off + 1) (len - 1) (n + 1)
else n
else n
toByteArray :: Bytes -> ByteArray
toByteArray b@(Bytes arr off len)
| off /= 0 = toByteArrayClone b
| PM.sizeofByteArray arr /= len = toByteArrayClone b
| otherwise = arr
toByteArrayClone :: Bytes -> ByteArray
toByteArrayClone (Bytes arr off len) = runByteArrayST $ do
m <- PM.newByteArray len
PM.copyByteArray m 0 arr off len
PM.unsafeFreezeByteArray m
fromAsciiString :: String -> Bytes
fromAsciiString = fromByteArray . Exts.fromList . map (fromIntegral @Int @Word8 . ord)
fromByteArray :: ByteArray -> Bytes
fromByteArray b = Bytes b 0 (PM.sizeofByteArray b)