packages feed

packstream-0.1.0.0: src/Data/PackStream/Internal/Code.hs

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 = (== nullCode)

isFalse, isTrue :: Word8 -> Bool
isFalse = (== falseCode)
isTrue = (== trueCode)

-- |Checks whether the represented data is 'Bool'
isBool :: Word8 -> Bool
isBool = isSmth [isFalse, isTrue]

isTinyInt, isInt8, isInt16, isInt32, isInt64 :: Word8 -> Bool
isTinyInt = liftA2 (||) (>= 0xF0) (<= 0x7F)
isInt8 = (== int8Code)
isInt16 = (== int16Code)
isInt32 = (== int32Code)
isInt64 = (== int64Code)

-- |Checks whether the represented data is 'Int'
isInt :: Word8 -> Bool
isInt = isSmth [isTinyInt, isInt8, isInt16, isInt32, isInt64]

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

isBytes8, isBytes16, isBytes32 :: Word8 -> Bool
isBytes8  = (== bytes8Code)
isBytes16 = (== bytes16Code)
isBytes32 = (== bytes32Code)

-- |Checks whether the represented data is 'ByteString'
isBytes :: Word8 -> Bool
isBytes = isSmth [isBytes8, isBytes16, isBytes32]

isTinyString, isString8, isString16, isString32 :: Word8 -> Bool
isTinyString = liftA2 (&&) (>= stringTinyCode) (<= stringTinyCode + 0x0F)
isString8 = (== string8Code)
isString16 = (== string16Code)
isString32 = (== string32Code)

-- |Checks whether the represented data is 'Text'
isString :: Word8 -> Bool
isString = isSmth [isTinyString, isString8, isString16, isString32]

isTinyList, isList8, isList16, isList32 :: Word8 -> Bool
isTinyList = liftA2 (&&) (>= listTinyCode) (<= listTinyCode + 0x0F)
isList8 = (== list8Code)
isList16 = (== list16Code)
isList32 = (== list32Code)

-- |Checks whether the represented data is '[Value]'
isList :: Word8 -> Bool
isList = isSmth [isTinyList, isList8, isList16, isList32]

isTinyDict, isDict8, isDict16, isDict32 :: Word8 -> Bool
isTinyDict = liftA2 (&&) (>= dictTinyCode) (<= dictTinyCode + 0x0F)
isDict8 = (== dict8Code)
isDict16 = (== dict16Code)
isDict32 = (== dict32Code)

-- |Checks whether the represented data is 'Map Text Value'
isDict :: Word8 -> Bool
isDict = isSmth [isTinyDict, isDict8, isDict16, isDict32]

-- |Checks whether the represented data is 'Structure'
isStructure :: Word8 -> Bool
isStructure = liftA2 (&&) (>= structureCode) (<= structureCode + 0x0F)

-- * Helper functions

-- |Extracts the size of tiny collection ('Text', '[Value]' or 'Map Text Value')
tinySize :: Word8 -> Int
tinySize x = fromIntegral $ x .&. 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 preds = or . flip fmap preds . flip id

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

nullCode :: Word8
nullCode = 0xC0

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

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

floatCode :: Word8
floatCode = 0xC1

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

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

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

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

structureCode :: Word8
structureCode = 0xB0