module Data.PackStream.Internal.Code where

import Data.Binary (Word8)
import Control.Applicative (liftA2)
import Data.Bits ((.&.))

-- * Checkers
--
-- These functions check the marker bytes of 'ByteString's to
-- identify the represented datatype. There names are self-describing.

-- |Checks whether the represented data is '()'
isNull :: Word8 -> Bool
isNull :: Word8 -> Bool
isNull = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
nullCode)

isFalse, isTrue :: Word8 -> Bool
isFalse :: Word8 -> Bool
isFalse = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
falseCode)
isTrue :: Word8 -> Bool
isTrue = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
trueCode)

-- |Checks whether the represented data is 'Bool'
isBool :: Word8 -> Bool
isBool :: Word8 -> Bool
isBool = [Word8 -> Bool] -> Word8 -> Bool
forall (t :: * -> *) b.
(Foldable t, Functor t) =>
t (b -> Bool) -> b -> Bool
isSmth [Word8 -> Bool
isFalse, Word8 -> Bool
isTrue]

isTinyInt, isInt8, isInt16, isInt32, isInt64 :: Word8 -> Bool
isTinyInt :: Word8 -> Bool
isTinyInt = (Bool -> Bool -> Bool)
-> (Word8 -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(||) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0xF0) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
0x7F)
isInt8 :: Word8 -> Bool
isInt8 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
int8Code)
isInt16 :: Word8 -> Bool
isInt16 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
int16Code)
isInt32 :: Word8 -> Bool
isInt32 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
int32Code)
isInt64 :: Word8 -> Bool
isInt64 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
int64Code)

-- |Checks whether the represented data is 'Int'
isInt :: Word8 -> Bool
isInt :: Word8 -> Bool
isInt = [Word8 -> Bool] -> Word8 -> Bool
forall (t :: * -> *) b.
(Foldable t, Functor t) =>
t (b -> Bool) -> b -> Bool
isSmth [Word8 -> Bool
isTinyInt, Word8 -> Bool
isInt8, Word8 -> Bool
isInt16, Word8 -> Bool
isInt32, Word8 -> Bool
isInt64]

-- |Checks whether the represented data is 'Double'
isFloat :: Word8 -> Bool
isFloat :: Word8 -> Bool
isFloat = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
floatCode)

isBytes8, isBytes16, isBytes32 :: Word8 -> Bool
isBytes8 :: Word8 -> Bool
isBytes8  = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
bytes8Code)
isBytes16 :: Word8 -> Bool
isBytes16 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
bytes16Code)
isBytes32 :: Word8 -> Bool
isBytes32 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
bytes32Code)

-- |Checks whether the represented data is 'ByteString'
isBytes :: Word8 -> Bool
isBytes :: Word8 -> Bool
isBytes = [Word8 -> Bool] -> Word8 -> Bool
forall (t :: * -> *) b.
(Foldable t, Functor t) =>
t (b -> Bool) -> b -> Bool
isSmth [Word8 -> Bool
isBytes8, Word8 -> Bool
isBytes16, Word8 -> Bool
isBytes32]

isTinyString, isString8, isString16, isString32 :: Word8 -> Bool
isTinyString :: Word8 -> Bool
isTinyString = (Bool -> Bool -> Bool)
-> (Word8 -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(&&) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
stringTinyCode) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
stringTinyCode Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
0x0F)
isString8 :: Word8 -> Bool
isString8 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
string8Code)
isString16 :: Word8 -> Bool
isString16 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
string16Code)
isString32 :: Word8 -> Bool
isString32 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
string32Code)

-- |Checks whether the represented data is 'Text'
isString :: Word8 -> Bool
isString :: Word8 -> Bool
isString = [Word8 -> Bool] -> Word8 -> Bool
forall (t :: * -> *) b.
(Foldable t, Functor t) =>
t (b -> Bool) -> b -> Bool
isSmth [Word8 -> Bool
isTinyString, Word8 -> Bool
isString8, Word8 -> Bool
isString16, Word8 -> Bool
isString32]

isTinyList, isList8, isList16, isList32 :: Word8 -> Bool
isTinyList :: Word8 -> Bool
isTinyList = (Bool -> Bool -> Bool)
-> (Word8 -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(&&) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
listTinyCode) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
listTinyCode Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
0x0F)
isList8 :: Word8 -> Bool
isList8 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
list8Code)
isList16 :: Word8 -> Bool
isList16 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
list16Code)
isList32 :: Word8 -> Bool
isList32 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
list32Code)

-- |Checks whether the represented data is '[Value]'
isList :: Word8 -> Bool
isList :: Word8 -> Bool
isList = [Word8 -> Bool] -> Word8 -> Bool
forall (t :: * -> *) b.
(Foldable t, Functor t) =>
t (b -> Bool) -> b -> Bool
isSmth [Word8 -> Bool
isTinyList, Word8 -> Bool
isList8, Word8 -> Bool
isList16, Word8 -> Bool
isList32]

isTinyDict, isDict8, isDict16, isDict32 :: Word8 -> Bool
isTinyDict :: Word8 -> Bool
isTinyDict = (Bool -> Bool -> Bool)
-> (Word8 -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(&&) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
dictTinyCode) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
dictTinyCode Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
0x0F)
isDict8 :: Word8 -> Bool
isDict8 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
dict8Code)
isDict16 :: Word8 -> Bool
isDict16 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
dict16Code)
isDict32 :: Word8 -> Bool
isDict32 = (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
dict32Code)

-- |Checks whether the represented data is 'Map Text Value'
isDict :: Word8 -> Bool
isDict :: Word8 -> Bool
isDict = [Word8 -> Bool] -> Word8 -> Bool
forall (t :: * -> *) b.
(Foldable t, Functor t) =>
t (b -> Bool) -> b -> Bool
isSmth [Word8 -> Bool
isTinyDict, Word8 -> Bool
isDict8, Word8 -> Bool
isDict16, Word8 -> Bool
isDict32]

-- |Checks whether the represented data is 'Structure'
isStructure :: Word8 -> Bool
isStructure :: Word8 -> Bool
isStructure = (Bool -> Bool -> Bool)
-> (Word8 -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(&&) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
structureCode) (Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
structureCode Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
0x0F)

-- * Helper functions

-- |Extracts the size of tiny collection ('Text', '[Value]' or 'Map Text Value')
tinySize :: Word8 -> Int
tinySize :: Word8 -> Int
tinySize Word8
x = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> Word8 -> Int
forall a b. (a -> b) -> a -> b
$ Word8
x Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x0F

-- |Gets the collection of predicates and checks whether any is 'True' on some data
isSmth :: (Foldable t, Functor t) => t (b -> Bool) -> b -> Bool
isSmth :: t (b -> Bool) -> b -> Bool
isSmth t (b -> Bool)
preds = t Bool -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or (t Bool -> Bool) -> (b -> t Bool) -> b -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (((b -> Bool) -> Bool) -> t (b -> Bool) -> t Bool)
-> t (b -> Bool) -> ((b -> Bool) -> Bool) -> t Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip ((b -> Bool) -> Bool) -> t (b -> Bool) -> t Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap t (b -> Bool)
preds (((b -> Bool) -> Bool) -> t Bool)
-> (b -> (b -> Bool) -> Bool) -> b -> t Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((b -> Bool) -> b -> Bool) -> b -> (b -> Bool) -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip (b -> Bool) -> b -> Bool
forall a. a -> a
id

-- * Codes
--
-- These are the 'PackStream' constants that mark specific data types.

nullCode :: Word8
nullCode :: Word8
nullCode = Word8
0xC0

falseCode, trueCode :: Word8
falseCode :: Word8
falseCode = Word8
0xC2
trueCode :: Word8
trueCode = Word8
0xC3

int8Code, int16Code, int32Code, int64Code :: Word8
int8Code :: Word8
int8Code = Word8
0xC8
int16Code :: Word8
int16Code = Word8
0xC9
int32Code :: Word8
int32Code = Word8
0xCA
int64Code :: Word8
int64Code = Word8
0xCB

floatCode :: Word8
floatCode :: Word8
floatCode = Word8
0xC1

bytes8Code, bytes16Code, bytes32Code :: Word8
bytes8Code :: Word8
bytes8Code = Word8
0xCC
bytes16Code :: Word8
bytes16Code = Word8
0xCD
bytes32Code :: Word8
bytes32Code = Word8
0xCE

stringTinyCode, string8Code, string16Code, string32Code :: Word8
stringTinyCode :: Word8
stringTinyCode = Word8
0x80
string8Code :: Word8
string8Code = Word8
0xD0
string16Code :: Word8
string16Code = Word8
0xD1
string32Code :: Word8
string32Code = Word8
0xD2

listTinyCode, list8Code, list16Code, list32Code :: Word8
listTinyCode :: Word8
listTinyCode = Word8
0x90
list8Code :: Word8
list8Code = Word8
0xD4
list16Code :: Word8
list16Code = Word8
0xD5
list32Code :: Word8
list32Code = Word8
0xD6

dictTinyCode, dict8Code, dict16Code, dict32Code :: Word8
dictTinyCode :: Word8
dictTinyCode = Word8
0xA0
dict8Code :: Word8
dict8Code = Word8
0xD8
dict16Code :: Word8
dict16Code = Word8
0xD9
dict32Code :: Word8
dict32Code = Word8
0xDA

structureCode :: Word8
structureCode :: Word8
structureCode = Word8
0xB0