{-# LANGUAGE TemplateHaskell #-}
module Streamly.Internal.Data.Serialize.TH.RecHeader
( mkRecSerializeExpr
, mkRecDeserializeExpr
, mkRecSizeOfExpr
, conUpdateFuncDec
, mkDeserializeKeysDec
) where
import Control.Monad (void)
import Data.List (foldl')
import Data.Word (Word32, Word8)
import Data.Maybe (fromJust)
import Language.Haskell.TH
import Streamly.Internal.Data.Serialize.Type (Serialize(..))
import Data.Foldable (foldlM)
import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
import Data.Proxy (Proxy(..))
import qualified Streamly.Internal.Data.Unbox as Unbox
import Streamly.Internal.Data.Serialize.TH.Bottom
import Streamly.Internal.Data.Serialize.TH.Common
newtype CompactList a =
CompactList
{ forall a. CompactList a -> [a]
unCompactList :: [a]
}
instance forall a. Serialize a => Serialize (CompactList a) where
addSizeTo :: Int -> CompactList a -> Int
addSizeTo Int
acc (CompactList [a]
xs) =
(Int -> a -> Int) -> Int -> [a] -> Int
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Int -> a -> Int
forall a. Serialize a => Int -> a -> Int
addSizeTo (Int
acc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Proxy Word8 -> Int
forall a. Unbox a => Proxy a -> Int
Unbox.sizeOf (Proxy Word8
forall {k} (t :: k). Proxy t
Proxy :: Proxy Word8))) [a]
xs
{-# INLINABLE deserializeAt #-}
deserializeAt :: Int -> MutByteArray -> Int -> IO (Int, CompactList a)
deserializeAt Int
off MutByteArray
arr Int
sz = do
(Int
off1, Word8
len8) <- Int -> MutByteArray -> Int -> IO (Int, Word8)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeAt Int
off MutByteArray
arr Int
sz :: IO (Int, Word8)
let len :: Int
len = Word8 -> Int
w8_int Word8
len8
peekList :: ([a] -> b) -> Int -> t -> IO (Int, b)
peekList [a] -> b
f Int
o t
i | t
i t -> t -> Bool
forall a. Ord a => a -> a -> Bool
>= t
3 = do
(Int
o1, a
x1) <- Int -> MutByteArray -> Int -> IO (Int, a)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeAt Int
o MutByteArray
arr Int
sz
(Int
o2, a
x2) <- Int -> MutByteArray -> Int -> IO (Int, a)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeAt Int
o1 MutByteArray
arr Int
sz
(Int
o3, a
x3) <- Int -> MutByteArray -> Int -> IO (Int, a)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeAt Int
o2 MutByteArray
arr Int
sz
([a] -> b) -> Int -> t -> IO (Int, b)
peekList ([a] -> b
f ([a] -> b) -> ([a] -> [a]) -> [a] -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\[a]
xs -> a
x1a -> [a] -> [a]
forall a. a -> [a] -> [a]
:a
x2a -> [a] -> [a]
forall a. a -> [a] -> [a]
:a
x3a -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs)) Int
o3 (t
i t -> t -> t
forall a. Num a => a -> a -> a
- t
3)
peekList [a] -> b
f Int
o t
0 = (Int, b) -> IO (Int, b)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
o, [a] -> b
f [])
peekList [a] -> b
f Int
o t
i = do
(Int
o1, a
x) <- Int -> MutByteArray -> Int -> IO (Int, a)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeAt Int
o MutByteArray
arr Int
sz
([a] -> b) -> Int -> t -> IO (Int, b)
peekList ([a] -> b
f ([a] -> b) -> ([a] -> [a]) -> [a] -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:)) Int
o1 (t
i t -> t -> t
forall a. Num a => a -> a -> a
- t
1)
(Int
nextOff, [a]
lst) <- ([a] -> [a]) -> Int -> Int -> IO (Int, [a])
forall {t} {a} {b}.
(Ord t, Num t, Serialize a) =>
([a] -> b) -> Int -> t -> IO (Int, b)
peekList [a] -> [a]
forall a. a -> a
id Int
off1 Int
len
(Int, CompactList a) -> IO (Int, CompactList a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
nextOff, [a] -> CompactList a
forall a. [a] -> CompactList a
CompactList [a]
lst)
{-# INLINABLE serializeAt #-}
serializeAt :: Int -> MutByteArray -> CompactList a -> IO Int
serializeAt Int
off MutByteArray
arr (CompactList [a]
val) = do
IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Int -> IO ()) -> IO Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int -> MutByteArray -> Word8 -> IO Int
forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
serializeAt Int
off MutByteArray
arr (Int -> Word8
int_w8 ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
val) :: Word8)
let off1 :: Int
off1 = Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Proxy Word8 -> Int
forall a. Unbox a => Proxy a -> Int
Unbox.sizeOf (Proxy Word8
forall {k} (t :: k). Proxy t
Proxy :: Proxy Word8)
let pokeList :: Int -> [a] -> IO Int
pokeList Int
o [] = Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o
pokeList Int
o (a
x:[a]
xs) = do
Int
o1 <- Int -> MutByteArray -> a -> IO Int
forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
serializeAt Int
o MutByteArray
arr a
x
Int -> [a] -> IO Int
pokeList Int
o1 [a]
xs
Int -> [a] -> IO Int
forall {a}. Serialize a => Int -> [a] -> IO Int
pokeList Int
off1 [a]
val
fieldToNameBase :: Field -> String
fieldToNameBase :: Field -> String
fieldToNameBase = Name -> String
nameBase (Name -> String) -> (Field -> Name) -> Field -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Name -> Name
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Name -> Name) -> (Field -> Maybe Name) -> Field -> Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field -> Maybe Name
forall a b. (a, b) -> a
fst
isMaybeType :: Type -> Bool
isMaybeType :: Type -> Bool
isMaybeType (AppT (ConT Name
m) Type
_) = Name
m Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== ''Maybe
isMaybeType Type
_ = Bool
False
exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
exprGetSize Q Exp
acc (Int
i, Type
_) =
[|addSizeTo $(Q Exp
acc) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE (Int -> Name
mkFieldName Int
i)) + 4|]
sizeOfHeader :: SimpleDataCon -> Int
(SimpleDataCon Name
_ [Field]
fields) =
Int
sizeForFinalOff Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
sizeForHeaderLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
sizeForNumFields
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Field -> Int) -> [Field] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ((Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
sizeForFieldLen) (Int -> Int) -> (Field -> Int) -> Field -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> (Field -> String) -> Field -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field -> String
fieldToNameBase) [Field]
fields)
where
sizeForFinalOff :: Int
sizeForFinalOff = Int
4
sizeForHeaderLength :: Int
sizeForHeaderLength = Int
4
sizeForNumFields :: Int
sizeForNumFields = Int
1
sizeForFieldLen :: Int
sizeForFieldLen = Int
1
mkRecSizeOfExpr :: SimpleDataCon -> Q Exp
mkRecSizeOfExpr :: SimpleDataCon -> Q Exp
mkRecSizeOfExpr SimpleDataCon
con = do
Name
n_acc <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"acc"
Name
n_x <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"x"
([Q Pat] -> Q Exp -> Q Exp
forall (m :: * -> *). Quote m => [m Pat] -> m Exp -> m Exp
lamE
[Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
n_acc, Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
n_x]
[|$(Int -> Q Exp
forall a. Integral a => a -> Q Exp
litIntegral Int
hlen) +
$(Q Exp -> [Q Match] -> Q Exp
forall (m :: * -> *). Quote m => m Exp -> [m Match] -> m Exp
caseE (Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
n_x) [Q Exp -> SimpleDataCon -> Q Match
matchCons (Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
n_acc) SimpleDataCon
con])|])
where
hlen :: Int
hlen = SimpleDataCon -> Int
sizeOfHeader SimpleDataCon
con
sizeOfFields :: Q Exp -> [Type] -> Q Exp
sizeOfFields Q Exp
acc [Type]
fields = (Q Exp -> (Int, Type) -> Q Exp) -> Q Exp -> [(Int, Type)] -> Q Exp
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Q Exp -> (Int, Type) -> Q Exp
exprGetSize Q Exp
acc ([(Int, Type)] -> Q Exp) -> [(Int, Type)] -> Q Exp
forall a b. (a -> b) -> a -> b
$ [Int] -> [Type] -> [(Int, Type)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] [Type]
fields
matchCons :: Q Exp -> SimpleDataCon -> Q Match
matchCons Q Exp
acc (SimpleDataCon Name
cname [Field]
fields) =
let expr :: Q Exp
expr = Q Exp -> [Type] -> Q Exp
sizeOfFields Q Exp
acc ((Field -> Type) -> [Field] -> [Type]
forall a b. (a -> b) -> [a] -> [b]
map Field -> Type
forall a b. (a, b) -> b
snd [Field]
fields)
in Name -> Int -> Q Exp -> Q Match
matchConstructor Name
cname ([Field] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Field]
fields) Q Exp
expr
headerValue :: SimpleDataCon -> [Word8]
(SimpleDataCon Name
_ [Field]
fields) =
Int -> Word8
int_w8 Int
numFields Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: [[Word8]] -> [Word8]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ((Field -> [Word8]) -> [Field] -> [[Word8]]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Field -> [Word8]
lengthPrependedFieldEncoding [Field]
fields)
where
numFields :: Int
numFields =
let lenFields :: Int
lenFields = [Field] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Field]
fields
in if Int
lenFields Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
255
then Int
lenFields
else String -> Int
forall a. String -> a
errorUnsupported
String
"Number of fields in the record should be <= 255."
lengthPrependedFieldEncoding :: Field -> [Word8]
lengthPrependedFieldEncoding Field
field =
let fEnc :: [Word8]
fEnc =
let fEnc_ :: [Word8]
fEnc_ = (Char -> Word8) -> String -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
c2w (Field -> String
fieldToNameBase Field
field)
lenFEnc :: Int
lenFEnc = [Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
fEnc_
in if Int
lenFEnc Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
255
then [Word8]
fEnc_
else
String -> [Word8]
forall a. String -> a
errorUnsupported
String
"Length of any key should be <= 255."
in (Int -> Word8
int_w8 ([Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
fEnc)) Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: [Word8]
fEnc
{-# INLINE serializeWithSize #-}
serializeWithSize :: Serialize a => Int -> MutByteArray -> a -> IO Int
serializeWithSize :: forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
serializeWithSize Int
off MutByteArray
arr a
val = do
Int
off1 <- Int -> MutByteArray -> a -> IO Int
forall a. Serialize a => Int -> MutByteArray -> a -> IO Int
serializeAt (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) MutByteArray
arr a
val
Int -> MutByteArray -> Word32 -> IO ()
forall a. Unbox a => Int -> MutByteArray -> a -> IO ()
Unbox.pokeAt Int
off MutByteArray
arr (Int -> Word32
int_w32 (Int
off1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
4) :: Word32)
Int -> IO Int
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
off1
mkRecSerializeExpr :: Name -> SimpleDataCon -> Q Exp
mkRecSerializeExpr :: Name -> SimpleDataCon -> Q Exp
mkRecSerializeExpr Name
initialOffset (con :: SimpleDataCon
con@(SimpleDataCon Name
cname [Field]
fields)) = do
Name
afterHLen <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"afterHLen"
[|do $(Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
afterHLen) <-
serializeAt
($(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
initialOffset) + 4)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
_arr)
($(Int -> Q Exp
forall a. Integral a => a -> Q Exp
litIntegral Int
hlen) :: Word32)
$(Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP (Int -> Name
makeI Int
0)) <- $(Name -> Name -> [Word8] -> Q Exp
serializeW8List Name
afterHLen Name
_arr [Word8]
hval)
let $(Name -> Int -> Q Pat
openConstructor Name
cname ([Field] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Field]
fields)) = $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
_val)
finalOff <- $(Name -> [Field] -> Q Exp
mkSerializeExprFields 'serializeWithSize [Field]
fields)
Unbox.pokeAt
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
initialOffset)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
_arr)
((fromIntegral :: Int -> Word32)
(finalOff - $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
initialOffset)))
pure finalOff|]
where
hval :: [Word8]
hval = SimpleDataCon -> [Word8]
headerValue SimpleDataCon
con
hlen :: Int
hlen = [Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
hval
{-# INLINE deserializeWithSize #-}
deserializeWithSize ::
Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeWithSize :: forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeWithSize Int
off MutByteArray
arr Int
endOff = Int -> MutByteArray -> Int -> IO (Int, a)
forall a. Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
deserializeAt (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) MutByteArray
arr Int
endOff
conUpdateFuncDec :: Name -> [Field] -> Q [Dec]
conUpdateFuncDec :: Name -> [Field] -> Q [Dec]
conUpdateFuncDec Name
funcName [Field]
fields = do
Name
prevAcc <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"prevAcc"
Name
curOff <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"curOff"
Name
endOff <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"endOff"
Name
arr <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"arr"
Name
key <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"key"
Exp
method <-
(Q Exp -> [Q Match] -> Q Exp
forall (m :: * -> *). Quote m => m Exp -> [m Match] -> m Exp
caseE
(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
key)
([[Q Match]] -> [Q Match]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
[ (Name -> Q Match) -> [Name] -> [Q Match]
forall a b. (a -> b) -> [a] -> [b]
map (Name -> Name -> (Name, Name) -> Name -> Q Match
matchField Name
arr Name
endOff (Name
prevAcc, Name
curOff)) [Name]
fnames
, [ Q Pat -> Q Body -> [Q Dec] -> Q Match
forall (m :: * -> *).
Quote m =>
m Pat -> m Body -> [m Dec] -> m Match
match
Q Pat
forall (m :: * -> *). Quote m => m Pat
wildP
(Q Exp -> Q Body
forall (m :: * -> *). Quote m => m Exp -> m Body
normalB
[|do (valOff, valLen :: Word32) <-
deserializeAt
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
curOff)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
arr)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)
pure
( $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
prevAcc)
, valOff + w32_int valLen)|])
[]
]
]))
[Dec] -> Q [Dec]
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
[ Pragma -> Dec
PragmaD (Name -> Inline -> RuleMatch -> Phases -> Pragma
InlineP Name
funcName Inline
NoInline RuleMatch
FunLike Phases
AllPhases)
, Name -> [Clause] -> Dec
FunD
Name
funcName
[ [Pat] -> Body -> [Dec] -> Clause
Clause
[ Name -> Pat
VarP Name
arr
, Name -> Pat
VarP Name
endOff
, [Pat] -> Pat
TupP [Name -> Pat
VarP Name
prevAcc, Name -> Pat
VarP Name
curOff]
, Name -> Pat
VarP Name
key
]
(Exp -> Body
NormalB Exp
method)
[]
]
]
where
fnames :: [Name]
fnames = (Field -> Name) -> [Field] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe Name -> Name
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Name -> Name) -> (Field -> Maybe Name) -> Field -> Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field -> Maybe Name
forall a b. (a, b) -> a
fst) [Field]
fields
matchField :: Name -> Name -> (Name, Name) -> Name -> Q Match
matchField :: Name -> Name -> (Name, Name) -> Name -> Q Match
matchField Name
arr Name
endOff (Name
acc, Name
currOff) Name
fname = do
let fnameLit :: Lit
fnameLit = String -> Lit
StringL (Name -> String
nameBase Name
fname)
Q Pat -> Q Body -> [Q Dec] -> Q Match
forall (m :: * -> *).
Quote m =>
m Pat -> m Body -> [m Dec] -> m Match
match
(Lit -> Q Pat
forall (m :: * -> *). Quote m => Lit -> m Pat
litP Lit
fnameLit)
(Q Exp -> Q Body
forall (m :: * -> *). Quote m => m Exp -> m Body
normalB
[|do (valOff, valLen :: Word32) <-
deserializeAt
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
currOff)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
arr)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)
pure
( ($(Lit -> Q Exp
forall (m :: * -> *). Quote m => Lit -> m Exp
litE Lit
fnameLit), $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
currOff)) : $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
acc)
, valOff + w32_int valLen)|])
[]
mkDeserializeKeysDec :: Name -> Name -> SimpleDataCon -> Q [Dec]
mkDeserializeKeysDec :: Name -> Name -> SimpleDataCon -> Q [Dec]
mkDeserializeKeysDec Name
funcName Name
updateFunc (SimpleDataCon Name
cname [Field]
fields) = do
Name
hOff <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"hOff"
Name
finalOff <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"finalOff"
Name
arr <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"arr"
Name
endOff <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"endOff"
Name
kvEncoded <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"kvEncoded"
Name
finalRec <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"finalRec"
let deserializeFieldExpr :: Field -> m Exp
deserializeFieldExpr (Just Name
name, Type
ty) = do
let nameLit :: m Exp
nameLit = Lit -> m Exp
forall (m :: * -> *). Quote m => Lit -> m Exp
litE (String -> Lit
StringL (Name -> String
nameBase Name
name))
[|case lookup $(m Exp
nameLit) $(Name -> m Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
kvEncoded) of
Nothing -> $(Name -> Type -> m Exp
forall {m :: * -> *}. Quote m => Name -> Type -> m Exp
emptyTy Name
name Type
ty)
Just off -> do
val <- deserializeWithSize off $(Name -> m Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
arr) $(Name -> m Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)
pure $ snd val|]
deserializeFieldExpr Field
_ =
String -> m Exp
forall a. String -> a
errorUnsupported String
"The datatype should use record syntax."
Exp
method <-
[|do (dataOff, hlist :: CompactList (CompactList Word8)) <-
deserializeAt $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
hOff) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
arr) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)
let keys = wListToString . unCompactList <$> unCompactList hlist
($(Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
kvEncoded), _) <-
foldlM
($(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
updateFunc) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
arr) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff))
([], dataOff)
keys
$(Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
finalRec) <-
$((Q Exp -> Field -> Q Exp) -> Q Exp -> [Field] -> Q Exp
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl
(\Q Exp
acc Field
i ->
[|$(Q Exp
acc) <*>
$(Field -> Q Exp
forall {m :: * -> *}. Quote m => Field -> m Exp
deserializeFieldExpr Field
i)|])
[|pure $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
conE Name
cname)|]
[Field]
fields)
pure ($(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
finalOff), $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
finalRec))|]
[Dec] -> Q [Dec]
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
[ Pragma -> Dec
PragmaD (Name -> Inline -> RuleMatch -> Phases -> Pragma
InlineP Name
funcName Inline
NoInline RuleMatch
FunLike Phases
AllPhases)
, Name -> [Clause] -> Dec
FunD
Name
funcName
[ [Pat] -> Body -> [Dec] -> Clause
Clause
[ Name -> Pat
VarP Name
hOff
, Name -> Pat
VarP Name
finalOff
, Name -> Pat
VarP Name
arr
, Name -> Pat
VarP Name
endOff
]
(Exp -> Body
NormalB Exp
method)
[]
]
]
where
emptyTy :: Name -> Type -> m Exp
emptyTy Name
k Type
ty =
if Type -> Bool
isMaybeType Type
ty
then [|pure Nothing|]
else [|error $(Lit -> m Exp
forall (m :: * -> *). Quote m => Lit -> m Exp
litE (String -> Lit
StringL (Name -> String
nameBase Name
k String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is not found.")))|]
mkRecDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
mkRecDeserializeExpr :: Name -> Name -> Name -> SimpleDataCon -> Q Exp
mkRecDeserializeExpr Name
initialOff Name
endOff Name
deserializeWithKeys SimpleDataCon
con = do
Name
hOff <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"hOff"
let sizeForFinalOff :: Int
sizeForFinalOff = Int
4
sizeForHeaderLength :: Int
sizeForHeaderLength = Int
4
sizePreData :: Int
sizePreData = Int
sizeForFinalOff Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
sizeForHeaderLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
hlen
[|do (hlenOff, encLen :: Word32) <-
deserializeAt $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
initialOff) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
_arr) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)
($(Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP Name
hOff), hlen1 :: Word32) <-
deserializeAt hlenOff $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
_arr) $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)
if (hlen1 == $(Int -> Q Exp
forall a. Integral a => a -> Q Exp
litIntegral Int
hlen)) && $([Word8] -> Name -> Name -> Q Exp
xorCmp [Word8]
hval Name
hOff Name
_arr)
then do
let $(Name -> Q Pat
forall (m :: * -> *). Quote m => Name -> m Pat
varP (Int -> Name
makeI Int
0)) =
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
initialOff) +
$(Int -> Q Exp
forall a. Integral a => a -> Q Exp
litIntegral Int
sizePreData)
$(Name -> SimpleDataCon -> Q Exp
mkDeserializeExprOne 'deserializeWithSize SimpleDataCon
con)
else $(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
deserializeWithKeys)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
hOff)
($(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
initialOff) + w32_int encLen)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
_arr)
$(Name -> Q Exp
forall (m :: * -> *). Quote m => Name -> m Exp
varE Name
endOff)|]
where
hval :: [Word8]
hval = SimpleDataCon -> [Word8]
headerValue SimpleDataCon
con
hlen :: Int
hlen = [Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
hval