{-# LANGUAGE TemplateHaskell #-}
module Streamly.Internal.Data.Serialize.TH.Bottom
(
SerializeConfig(..)
, serializeConfig
, inlineAddSizeTo
, inlineSerializeAt
, inlineDeserializeAt
, encodeConstrNames
, encodeRecordFields
, TypeOfType(..)
, typeOfType
, SimpleDataCon(..)
, simplifyDataCon
, Field
, mkFieldName
, isUnitType
, isRecordSyntax
, c2w
, wListToString
, xorCmp
, serializeW8List
, litIntegral
, litProxy
, matchConstructor
, openConstructor
, makeI
, makeN
, makeA
, int_w8
, int_w32
, w32_int
, w8_int
, _acc
, _arr
, _endOffset
, _initialOffset
, _x
, _tag
, _val
, errorUnsupported
, errorUnimplemented
) where
import Data.Maybe (isJust)
import Data.Char (chr, ord)
import Data.List (foldl')
import Data.Word (Word16, Word32, Word64, Word8)
import Data.Bits (Bits, (.|.), shiftL, zeroBits, xor)
import Streamly.Internal.System.IO (unsafeInlineIO)
import Streamly.Internal.Data.Unbox (Unbox)
import Data.Proxy (Proxy)
import Language.Haskell.TH
import Streamly.Internal.Data.Serialize.Type
import qualified Streamly.Internal.Data.Unbox as Unbox
import Streamly.Internal.Data.Unbox.TH (DataCon(..))
data SerializeConfig =
SerializeConfig
{ SerializeConfig -> Maybe Inline
cfgInlineSize :: Maybe Inline
, SerializeConfig -> Maybe Inline
cfgInlineSerialize :: Maybe Inline
, SerializeConfig -> Maybe Inline
cfgInlineDeserialize :: Maybe Inline
, SerializeConfig -> Bool
cfgConstructorTagAsString :: Bool
, :: Bool
}
inlineAddSizeTo :: Maybe Inline -> SerializeConfig -> SerializeConfig
inlineAddSizeTo :: Maybe Inline -> SerializeConfig -> SerializeConfig
inlineAddSizeTo Maybe Inline
v SerializeConfig
cfg = SerializeConfig
cfg {cfgInlineSize :: Maybe Inline
cfgInlineSize = Maybe Inline
v}
inlineSerializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
inlineSerializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
inlineSerializeAt Maybe Inline
v SerializeConfig
cfg = SerializeConfig
cfg {cfgInlineSerialize :: Maybe Inline
cfgInlineSerialize = Maybe Inline
v}
inlineDeserializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
inlineDeserializeAt :: Maybe Inline -> SerializeConfig -> SerializeConfig
inlineDeserializeAt Maybe Inline
v SerializeConfig
cfg = SerializeConfig
cfg {cfgInlineDeserialize :: Maybe Inline
cfgInlineDeserialize = Maybe Inline
v}
encodeConstrNames :: Bool -> SerializeConfig -> SerializeConfig
encodeConstrNames :: Bool -> SerializeConfig -> SerializeConfig
encodeConstrNames Bool
v SerializeConfig
cfg = SerializeConfig
cfg {cfgConstructorTagAsString :: Bool
cfgConstructorTagAsString = Bool
v}
encodeRecordFields :: Bool -> SerializeConfig -> SerializeConfig
encodeRecordFields :: Bool -> SerializeConfig -> SerializeConfig
encodeRecordFields Bool
v SerializeConfig
cfg = SerializeConfig
cfg {cfgRecordSyntaxWithHeader :: Bool
cfgRecordSyntaxWithHeader = Bool
v}
serializeConfig :: SerializeConfig
serializeConfig :: SerializeConfig
serializeConfig =
SerializeConfig
{ cfgInlineSize :: Maybe Inline
cfgInlineSize = forall a. Maybe a
Nothing
, cfgInlineSerialize :: Maybe Inline
cfgInlineSerialize = forall a. a -> Maybe a
Just Inline
Inline
, cfgInlineDeserialize :: Maybe Inline
cfgInlineDeserialize = forall a. a -> Maybe a
Just Inline
Inline
, cfgConstructorTagAsString :: Bool
cfgConstructorTagAsString = Bool
False
, cfgRecordSyntaxWithHeader :: Bool
cfgRecordSyntaxWithHeader = Bool
False
}
type Field = (Maybe Name, Type)
_x :: Name
_x :: Name
_x = String -> Name
mkName String
"x"
_acc :: Name
_acc :: Name
_acc = String -> Name
mkName String
"acc"
_arr :: Name
_arr :: Name
_arr = String -> Name
mkName String
"arr"
_tag :: Name
_tag :: Name
_tag = String -> Name
mkName String
"tag"
_initialOffset :: Name
_initialOffset :: Name
_initialOffset = String -> Name
mkName String
"initialOffset"
_endOffset :: Name
_endOffset :: Name
_endOffset = String -> Name
mkName String
"endOffset"
_val :: Name
_val :: Name
_val = String -> Name
mkName String
"val"
mkFieldName :: Int -> Name
mkFieldName :: Int -> Name
mkFieldName Int
i = String -> Name
mkName (String
"field" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
i)
makeI :: Int -> Name
makeI :: Int -> Name
makeI Int
i = String -> Name
mkName forall a b. (a -> b) -> a -> b
$ String
"i" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
i
makeN :: Int -> Name
makeN :: Int -> Name
makeN Int
i = String -> Name
mkName forall a b. (a -> b) -> a -> b
$ String
"n" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
i
makeA :: Int -> Name
makeA :: Int -> Name
makeA Int
i = String -> Name
mkName forall a b. (a -> b) -> a -> b
$ String
"a" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
i
openConstructor :: Name -> Int -> Q Pat
openConstructor :: Name -> Int -> Q Pat
openConstructor Name
cname Int
numFields =
forall (m :: * -> *). Quote m => Name -> [m Pat] -> m Pat
conP Name
cname (forall a b. (a -> b) -> [a] -> [b]
map forall (m :: * -> *). Quote m => Name -> m Pat
varP (forall a b. (a -> b) -> [a] -> [b]
map Int -> Name
mkFieldName [Int
0 .. (Int
numFields forall a. Num a => a -> a -> a
- Int
1)]))
matchConstructor :: Name -> Int -> Q Exp -> Q Match
matchConstructor :: Name -> Int -> Q Exp -> Q Match
matchConstructor Name
cname Int
numFields Q Exp
exp0 =
forall (m :: * -> *).
Quote m =>
m Pat -> m Body -> [m Dec] -> m Match
match (Name -> Int -> Q Pat
openConstructor Name
cname Int
numFields) (forall (m :: * -> *). Quote m => m Exp -> m Body
normalB Q Exp
exp0) []
data SimpleDataCon =
SimpleDataCon Name [Field]
deriving (SimpleDataCon -> SimpleDataCon -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SimpleDataCon -> SimpleDataCon -> Bool
$c/= :: SimpleDataCon -> SimpleDataCon -> Bool
== :: SimpleDataCon -> SimpleDataCon -> Bool
$c== :: SimpleDataCon -> SimpleDataCon -> Bool
Eq)
simplifyDataCon :: DataCon -> SimpleDataCon
simplifyDataCon :: DataCon -> SimpleDataCon
simplifyDataCon (DataCon Name
cname [Name]
_ Cxt
_ [Field]
fields) = Name -> [Field] -> SimpleDataCon
SimpleDataCon Name
cname [Field]
fields
data TypeOfType
= UnitType Name
| TheType SimpleDataCon
| MultiType [SimpleDataCon]
deriving (TypeOfType -> TypeOfType -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TypeOfType -> TypeOfType -> Bool
$c/= :: TypeOfType -> TypeOfType -> Bool
== :: TypeOfType -> TypeOfType -> Bool
$c== :: TypeOfType -> TypeOfType -> Bool
Eq)
typeOfType :: Type -> [DataCon] -> TypeOfType
typeOfType :: Type -> [DataCon] -> TypeOfType
typeOfType Type
headTy [] =
forall a. HasCallStack => String -> a
error
(String
"Attempting to get size with no constructors (" forall a. [a] -> [a] -> [a]
++
(forall a. Ppr a => a -> String
pprint Type
headTy) forall a. [a] -> [a] -> [a]
++ String
")")
typeOfType Type
_ [DataCon Name
cname [Name]
_ Cxt
_ []] = Name -> TypeOfType
UnitType Name
cname
typeOfType Type
_ [con :: DataCon
con@(DataCon Name
_ [Name]
_ Cxt
_ [Field]
_)] = SimpleDataCon -> TypeOfType
TheType forall a b. (a -> b) -> a -> b
$ DataCon -> SimpleDataCon
simplifyDataCon DataCon
con
typeOfType Type
_ [DataCon]
cons = [SimpleDataCon] -> TypeOfType
MultiType forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map DataCon -> SimpleDataCon
simplifyDataCon [DataCon]
cons
isUnitType :: [DataCon] -> Bool
isUnitType :: [DataCon] -> Bool
isUnitType [DataCon Name
_ [Name]
_ Cxt
_ []] = Bool
True
isUnitType [DataCon]
_ = Bool
False
isRecordSyntax :: SimpleDataCon -> Bool
isRecordSyntax :: SimpleDataCon -> Bool
isRecordSyntax (SimpleDataCon Name
_ [Field]
fields) = forall (t :: * -> *). Foldable t => t Bool -> Bool
and (forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Field]
fields)
int_w8 :: Int -> Word8
int_w8 :: Int -> Word8
int_w8 = forall a b. (Integral a, Num b) => a -> b
fromIntegral
int_w32 :: Int -> Word32
int_w32 :: Int -> Word32
int_w32 = forall a b. (Integral a, Num b) => a -> b
fromIntegral
w8_w16 :: Word8 -> Word16
w8_w16 :: Word8 -> Word16
w8_w16 = forall a b. (Integral a, Num b) => a -> b
fromIntegral
w8_w32 :: Word8 -> Word32
w8_w32 :: Word8 -> Word32
w8_w32 = forall a b. (Integral a, Num b) => a -> b
fromIntegral
w8_w64 :: Word8 -> Word64
w8_w64 :: Word8 -> Word64
w8_w64 = forall a b. (Integral a, Num b) => a -> b
fromIntegral
w8_int :: Word8 -> Int
w8_int :: Word8 -> Int
w8_int = forall a b. (Integral a, Num b) => a -> b
fromIntegral
w32_int :: Word32 -> Int
w32_int :: Word32 -> Int
w32_int = forall a b. (Integral a, Num b) => a -> b
fromIntegral
c2w :: Char -> Word8
c2w :: Char -> Word8
c2w = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord
wListToString :: [Word8] -> String
wListToString :: [Word8] -> String
wListToString = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Char
chr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral)
shiftAdd :: Bits a => (b -> a) -> [b] -> a
shiftAdd :: forall a b. Bits a => (b -> a) -> [b] -> a
shiftAdd b -> a
conv [b]
xs =
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall a. Bits a => a -> a -> a
(.|.) forall a. Bits a => a
zeroBits forall a b. (a -> b) -> a -> b
$
forall a b. (a -> b) -> [a] -> [b]
map (\(Int
j, a
x) -> forall a. Bits a => a -> Int -> a
shiftL a
x (Int
j forall a. Num a => a -> a -> a
* Int
8)) forall a b. (a -> b) -> a -> b
$ forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map b -> a
conv [b]
xs
xorCmp :: [Word8] -> Name -> Name -> Q Exp
xorCmp :: [Word8] -> Name -> Name -> Q Exp
xorCmp [Word8]
tag Name
off Name
arr =
case Int
tagLen of
Int
x | Int
x forall a. Ord a => a -> a -> Bool
< Int
2 -> [|$(go8 0) == zeroBits|]
Int
x | Int
x forall a. Ord a => a -> a -> Bool
< Int
4 -> [|$(go16 0) == zeroBits|]
Int
x | Int
x forall a. Ord a => a -> a -> Bool
< Int
8 -> [|$(go32 0) == zeroBits|]
Int
_ -> [|$(go64 0) == zeroBits|]
where
tagLen :: Int
tagLen = forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
tag
go8 :: Int -> Q Exp
go8 Int
i | Int
i forall a. Ord a => a -> a -> Bool
>= Int
tagLen = [|zeroBits|]
go8 Int
i = do
let wIntegral :: Q Exp
wIntegral = forall a. Integral a => a -> Q Exp
litIntegral Int
i
[|xor (unsafeInlineIO
(Unbox.peekAt
($(varE off) + $(litIntegral i))
$(varE arr)))
($(wIntegral) :: Word8) .|.
$(go8 (i + 1))|]
go16 :: Int -> Q Exp
go16 Int
i
| Int
i forall a. Ord a => a -> a -> Bool
>= Int
tagLen = [|zeroBits|]
go16 Int
i
| Int
tagLen forall a. Num a => a -> a -> a
- Int
i forall a. Ord a => a -> a -> Bool
< Int
2 = Int -> Q Exp
go16 (Int
tagLen forall a. Num a => a -> a -> a
- Int
2)
go16 Int
i = do
let wIntegral :: Q Exp
wIntegral =
forall a. Integral a => a -> Q Exp
litIntegral
(forall a b. Bits a => (b -> a) -> [b] -> a
shiftAdd Word8 -> Word16
w8_w16 [[Word8]
tag forall a. [a] -> Int -> a
!! Int
i, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
1)] :: Word16)
[|xor (unsafeInlineIO
(Unbox.peekAt
($(varE off) + $(litIntegral i))
$(varE arr)))
($(wIntegral) :: Word16) .|.
$(go16 (i + 2))|]
go32 :: Int -> Q Exp
go32 Int
i
| Int
i forall a. Ord a => a -> a -> Bool
>= Int
tagLen = [|zeroBits|]
go32 Int
i
| Int
tagLen forall a. Num a => a -> a -> a
- Int
i forall a. Ord a => a -> a -> Bool
< Int
4 = Int -> Q Exp
go32 (Int
tagLen forall a. Num a => a -> a -> a
- Int
4)
go32 Int
i = do
let wIntegral :: Q Exp
wIntegral =
forall a. Integral a => a -> Q Exp
litIntegral
(forall a b. Bits a => (b -> a) -> [b] -> a
shiftAdd
Word8 -> Word32
w8_w32
[ [Word8]
tag forall a. [a] -> Int -> a
!! Int
i
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
1)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
2)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
3)
] :: Word32)
[|xor (unsafeInlineIO
(Unbox.peekAt
($(varE off) + $(litIntegral i))
$(varE arr)))
($(wIntegral) :: Word32) .|.
$(go32 (i + 4))|]
go64 :: Int -> Q Exp
go64 Int
i
| Int
i forall a. Ord a => a -> a -> Bool
>= Int
tagLen = [|zeroBits|]
go64 Int
i
| Int
tagLen forall a. Num a => a -> a -> a
- Int
i forall a. Ord a => a -> a -> Bool
< Int
8 = Int -> Q Exp
go64 (Int
tagLen forall a. Num a => a -> a -> a
- Int
8)
go64 Int
i = do
let wIntegral :: Q Exp
wIntegral =
forall a. Integral a => a -> Q Exp
litIntegral
(forall a b. Bits a => (b -> a) -> [b] -> a
shiftAdd
Word8 -> Word64
w8_w64
[ [Word8]
tag forall a. [a] -> Int -> a
!! Int
i
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
1)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
2)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
3)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
4)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
5)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
6)
, [Word8]
tag forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
+ Int
7)
])
[|xor (unsafeInlineIO
(Unbox.peekAt
($(varE off) + $(litIntegral i))
$(varE arr)))
($(wIntegral) :: Word64) .|.
$(go64 (i + 8))|]
serializeW8List :: Name -> Name -> [Word8] -> Q Exp
serializeW8List :: Name -> Name -> [Word8] -> Q Exp
serializeW8List Name
off Name
arr [Word8]
w8List = do
[|let $(varP (makeN 0)) = $(varE off)
in $(doE (fmap makeBind [0 .. (lenW8List - 1)] ++
[noBindS ([|pure $(varE (makeN lenW8List))|])]))|]
where
lenW8List :: Int
lenW8List = forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
w8List
makeBind :: Int -> Q Stmt
makeBind Int
i =
forall (m :: * -> *). Quote m => m Pat -> m Exp -> m Stmt
bindS
(forall (m :: * -> *). Quote m => Name -> m Pat
varP (Int -> Name
makeN (Int
i forall a. Num a => a -> a -> a
+ Int
1)))
[|$(varE 'serializeAt)
$(varE (makeN i))
$(varE arr)
($(litIntegral (w8List !! i)) :: Word8)|]
litIntegral :: Integral a => a -> Q Exp
litIntegral :: forall a. Integral a => a -> Q Exp
litIntegral = forall (m :: * -> *). Quote m => Lit -> m Exp
litE forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Lit
IntegerL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral
litProxy :: Unbox a => Proxy a -> Q Exp
litProxy :: forall a. Unbox a => Proxy a -> Q Exp
litProxy = forall (m :: * -> *). Quote m => Lit -> m Exp
litE forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Lit
IntegerL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Unbox a => Proxy a -> Int
Unbox.sizeOf
errorUnsupported :: String -> a
errorUnsupported :: forall a. String -> a
errorUnsupported String
err =
forall a. HasCallStack => String -> a
error
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
[ String
"Unsupported"
, String
"==========="
, String
"This is improper use of the library."
, String
"This case is unsupported."
, String
"Please contact the developer if this case is of interest."
, String
""
, String
"Message"
, String
"-------"
, String
err
]
errorUnimplemented :: a
errorUnimplemented :: forall a. a
errorUnimplemented =
forall a. HasCallStack => String -> a
error
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
[ String
"Unimplemented"
, String
"============="
, String
"Please contact the developer if this case is of interest."
]