{-# LANGUAGE UndecidableInstances #-}
module Data.Repa.Convert.Format.Object
( Object (..)
, ObjectFormat
, ObjectFields
, Field (..)
, mkObject)
where
import Data.Repa.Convert.Internal.Format
import Data.Repa.Convert.Internal.Packable
import Data.Repa.Convert.Internal.Packer
import Data.Repa.Convert.Format.String
import Data.Repa.Convert.Format.Binary
import Data.Repa.Scalar.Product
import Data.Word
import Data.Char
import GHC.Exts
import Data.Text (Text)
import qualified Data.Text as T
data Object fields where
Object
:: ObjectFields fields
-> Object fields
data ObjectFields fields where
ObjectFieldsNil
:: ObjectFields ()
ObjectFieldsCons
:: {-# UNPACK #-} !ObjectMeta
-> !Text
-> !f
-> Maybe (Value f -> Bool)
-> ObjectFields fs
-> ObjectFields (f :*: fs)
data ObjectMeta
= ObjectMeta
{
omFieldCount :: !Int
, omMinSize :: !Int
, omFixedSize :: !(Maybe Int) }
mkObject :: ObjectFormat f
=> f -> Object (ObjectFormat' f)
mkObject f = Object (mkObjectFields f)
class ObjectFormat f where
type ObjectFormat' f
mkObjectFields :: f -> ObjectFields (ObjectFormat' f)
instance ObjectFormat () where
type ObjectFormat' () = ()
mkObjectFields () = ObjectFieldsNil
{-# INLINE mkObjectFields #-}
data Field f
= Field
{ fieldName :: String
, fieldFormat :: f
, fieldInclude :: Maybe (Value f -> Bool) }
instance ( Format f1
, ObjectFormat fs)
=> ObjectFormat (Field f1 :*: fs) where
type ObjectFormat' (Field f1 :*: fs)
= f1 :*: ObjectFormat' fs
mkObjectFields (Field label f1 mKeep :*: fs)
= case mkObjectFields fs of
ObjectFieldsNil
-> ObjectFieldsCons
(ObjectMeta
{ omFieldCount = 1
, omMinSize = 5 + length label + minSize f1
, omFixedSize = fmap (+ (5 + length label)) $ fixedSize f1 })
(T.pack label) f1 mKeep ObjectFieldsNil
cc@(ObjectFieldsCons jm _ _ _ _)
-> ObjectFieldsCons
(ObjectMeta
{ omFieldCount = 1 + omFieldCount jm
, omMinSize = 4 + minSize f1 + omMinSize jm
, omFixedSize
= do s1 <- fixedSize f1
ss <- omFixedSize jm
return $ s1 + 4 + ss })
(T.pack label) f1 mKeep cc
{-# INLINE mkObjectFields #-}
instance ( Format (ObjectFields fs)
, Value (ObjectFields fs) ~ Value fs)
=> Format (Object fs) where
type Value (Object fs)
= Value fs
fieldCount (Object _)
= 1
{-# INLINE fieldCount #-}
minSize (Object fs)
= 2 + minSize fs
{-# INLINE minSize #-}
fixedSize (Object fs)
= do sz <- fixedSize fs
return (2 + sz)
{-# INLINE fixedSize #-}
packedSize (Object fs) xs
= do ps <- packedSize fs xs
return $ 2 + ps
{-# INLINE packedSize #-}
instance Format (ObjectFields ()) where
type Value (ObjectFields ()) = ()
fieldCount ObjectFieldsNil = 0
minSize ObjectFieldsNil = 0
fixedSize ObjectFieldsNil = return 0
packedSize ObjectFieldsNil _ = return 0
{-# INLINE fieldCount #-}
{-# INLINE minSize #-}
{-# INLINE fixedSize #-}
{-# INLINE packedSize #-}
instance Packable (ObjectFields ()) where
packer _fmt _val dst _fails k
= k dst
{-# INLINE packer #-}
instance Unpackable (ObjectFields ()) where
unpacker _fmt start _end _stop _fail eat
= eat start ()
{-# INLINE unpacker #-}
instance ( Format f1, Format (ObjectFields fs)
, Value (ObjectFields fs) ~ Value fs)
=> Format (ObjectFields (f1 :*: fs)) where
type Value (ObjectFields (f1 :*: fs))
= Value f1 :*: Value fs
fieldCount (ObjectFieldsCons jm _l1 _f1 _keep _jfs)
= omFieldCount jm
{-# INLINE fieldCount #-}
minSize (ObjectFieldsCons jm _l1 _f1 _keep _jfs)
= omMinSize jm
{-# INLINE minSize #-}
fixedSize (ObjectFieldsCons jm _l1 _f1 _keep _jfs)
= omFixedSize jm
{-# INLINE fixedSize #-}
packedSize (ObjectFieldsCons _jm l1 f1 _keep jfs) (x1 :*: xs)
= do sl <- packedSize VarCharString (T.unpack l1)
s1 <- packedSize f1 x1
ss <- packedSize jfs xs
let sSep = zeroOrOne (fieldCount jfs)
return $ sl + 1 + s1 + sSep + ss
{-# INLINE packedSize #-}
instance ( Format (Object f)
, Value (ObjectFields f) ~ Value f
, Packable (ObjectFields f))
=> Packable (Object f) where
pack (Object fs) xs
= pack Word8be (w8 $ ord '{')
<> pack fs xs
<> pack Word8be (w8 $ ord '}')
{-# INLINE pack #-}
packer f v
= fromPacker $ pack f v
{-# INLINE packer #-}
instance ( Packable f1
, Value (ObjectFields ()) ~ Value ())
=> Packable (ObjectFields (f1 :*: ())) where
pack (ObjectFieldsCons _jm l1 f1 _keep _jfs) (x1 :*: _)
= pack VarCharString (T.unpack l1)
<> pack Word8be (w8 $ ord ':')
<> pack f1 x1
{-# INLINE pack #-}
packer f v
= fromPacker $ pack f v
{-# INLINE packer #-}
instance ( Packable f1
, Packable (ObjectFields (f2 :*: fs))
, Value (ObjectFields (f2 :*: fs)) ~ Value (f2 :*: fs)
, Value (ObjectFields fs) ~ Value fs)
=> Packable (ObjectFields (f1 :*: f2 :*: fs)) where
pack (ObjectFieldsCons _jm l1 f1 mKeep jfs) (x1 :*: xs)
= if (case mKeep of
Just keep -> keep x1
_ -> True)
then here
else rest
where
here = pack VarCharString (T.unpack l1)
<> pack Word8be (w8 $ ord ':')
<> pack f1 x1
<> pack Word8be (w8 $ ord ',')
<> rest
rest = pack jfs xs
{-# INLINE pack #-}
packer f v
= fromPacker $ pack f v
{-# INLINE packer #-}
w8 :: Integral a => a -> Word8
w8 = fromIntegral
{-# INLINE w8 #-}
zeroOrOne :: Int -> Int
zeroOrOne (I# i) = I# (1# -# (0# ==# i))
{-# INLINE zeroOrOne #-}