on master help sign in
Change deriveUnbox to use instance splice
commit33bffd614bc7ccbcfe1f167d9fd62fc7186e2eb1 authorHarendra Kumar <harendra@composewell.com> dateWed 22 Nov 2023, 03:17 (3 years ago) parent1640a68
7 files changed+63−96
benchmark/Streamly/Benchmark/Data/Serialize.hs+1−1 core/src/Streamly/Data/Serialize.hs−1 core/src/Streamly/Internal/Data/Serialize/TH.hs+8−9 core/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs+1−1 core/src/Streamly/Internal/Data/Unbox/TH.hs+42−71 test/Streamly/Test/Data/Unbox.hs+6−9 test/Streamly/Test/Data/Unbox/TH.hs+5−4
benchmark/Streamly/Benchmark/Data/Serialize.hs+1−1
@@ -42,7 +42,7 @@ import Streamly.Benchmark.Data.Serialize.RecNonCompatible
4242
4343#ifdef USE_UNBOX
4444#define SERIALIZE_CLASS Unbox
45−#define DERIVE_CLASS(typ) $(deriveUnbox ''typ)
45+#define DERIVE_CLASS(typ) $(deriveUnbox [d|instance Unbox typ|])
4646#define SERIALIZE_OP pokeByteIndex
4747#define DESERIALIZE_OP peekByteIndex
4848#else
core/src/Streamly/Data/Serialize.hs−1
@@ -47,7 +47,6 @@ module Streamly.Data.Serialize
4747 -- * Unbox
4848 , Unbox(..)
4949 , deriveUnbox
50− , deriveUnboxWith
5150
5251 -- * Serialize
5352 , Serialize(..)
core/src/Streamly/Internal/Data/Serialize/TH.hs+8−9
@@ -464,17 +464,16 @@ deriveSerializeWith :: SerializeConfig -> Q [Dec] -> Q [Dec]
464464deriveSerializeWith conf mDecs = do
465465 dec <- mDecs
466466 case dec of
467− [inst@(InstanceD _ _ headTyWC [])] -> do
467+ [InstanceD mo preds headTyWC []] -> do
468468 let headTy = unwrap dec headTyWC
469469 dt <- reifyDataType (getMainTypeName dec headTy)
470470 let cons = dtCons dt
471− deriveSerializeInternal conf headTy cons (next inst)
472− _ -> errorUnsupported (errorMessage dec)
473− where
471+ deriveSerializeInternal conf headTy cons (next mo preds headTyWC)
472+ _ -> errorMessage dec
473+
474+ where
474475
475− next (InstanceD mo preds headTyWC []) methods =
476− pure [InstanceD mo preds headTyWC methods]
477− next dec _ = errorUnsupported (errorMessage dec)
476+ next mo preds headTyWC methods = pure [InstanceD mo preds headTyWC methods]
478477
479478 errorMessage dec =
480479 error $ unlines
@@ -482,8 +481,8 @@ deriveSerializeWith conf mDecs = do
482481 , ""
483482 , ">> " ++ pprint dec
484483 , ""
485− , "The above is not a valid instance declaration."
486− , "Any haskell instance declaration without a body is valid."
484+ , "The supplied declaration is not a valid instance declaration."
485+ , "Provide a valid Haskell instance declaration without a body."
487486 , ""
488487 , "Examples:"
489488 , "instance Serialize (Proxy a)"
core/src/Streamly/Internal/Data/Serialize/TH/Bottom.hs+1−1
@@ -450,7 +450,7 @@ errorUnsupported err =
450450 $ unlines
451451 [ "Unsupported"
452452 , "==========="
453− , "There is improper use of the library."
453+ , "This is improper use of the library."
454454 , "This case is unsupported."
455455 , "Please contact the developer if this case is of interest."
456456 , ""
core/src/Streamly/Internal/Data/Unbox/TH.hs+42−71
@@ -10,13 +10,11 @@
1010--
1111module Streamly.Internal.Data.Unbox.TH
1212 ( deriveUnbox
13− , deriveUnboxWith
1413
1514 -- th-helpers
1615 , DataCon(..)
1716 , DataType(..)
1817 , reifyDataType
19− , appsT
2018 ) where
2119
2220--------------------------------------------------------------------------------
@@ -69,10 +67,6 @@ tvName = elimTV id (\n _ -> n)
6967tyVarBndrName :: TyVarBndr_ flag -> Name
7068tyVarBndrName = tvName
7169
72−appsT :: Type -> [Type] -> Type
73−appsT x [] = x
74−appsT x (y:xs) = appsT (AppT x y) xs
75−
7670-- | Simplified info about a 'DataD'. Omits deriving, strictness,
7771-- kind info, and whether it's @data@ or @newtype@.
7872data DataType = DataType
@@ -397,8 +391,8 @@ mkPokeExpr headTy cons =
397391-- [(Nothing, (ConT ''Bool)), (Nothing, (VarT (mkName "b")))]
398392-- ])
399393-- @
400−deriveUnboxInternal :: Cxt -> Type -> [DataCon] -> Q [Dec]
401−deriveUnboxInternal preds headTy cons = do
394+deriveUnboxInternal :: Type -> [DataCon] -> ([Dec] -> Q [Dec]) -> Q [Dec]
395+deriveUnboxInternal headTy cons mkDec = do
402396 sizeOfMethod <- mkSizeOfExpr headTy cons
403397 peekMethod <- mkPeekExpr headTy cons
404398 pokeMethod <- mkPokeExpr headTy cons
@@ -428,77 +422,54 @@ deriveUnboxInternal preds headTy cons = do
428422 []
429423 ]
430424 ]
431− return [InstanceD Nothing preds (AppT (ConT ''Unbox) headTy) methods]
425+ mkDec methods
432426
433−-- | @deriveUnbox dataTypeName@ generates a template Haskell splice consisting
434−-- of a declaration of the 'Unbox' instance for the given dataTypeName, all type
435−-- parameters of dataTypeName are required to have the 'Unbox' constraint.
436−--
437−-- For example,
438−--
439−-- @
440−-- data CustomDataType a b c = ...
441−-- \$(deriveUnbox ''CustomDataType)
442−-- @
427+-- | Given an 'Unbox' instance declaration splice without the methods,
428+-- generate a full instance declaration including all the type class methods.
443429--
444−-- Generates the following code:
430+-- Usage:
445431--
446432-- @
447−-- instance (Unbox a, Unbox b, Unbox c) => Unbox (CustomDataType a b c) where
448−-- ...
433+-- \$(deriveUnbox [d|instance Unbox a => Unbox (Maybe a)|])
449434-- @
450−--
451−-- To control which type parameters get the Unbox constraint, use
452−-- 'deriveUnboxWith'.
453−deriveUnbox :: Name -> Q [Dec]
454−deriveUnbox name = do
455− dt <- reifyDataType name
456− let preds = map (unboxPred . VarT) (dtTvs dt)
457− headTy = appsT (ConT name) (map VarT (dtTvs dt))
458− cons = dtCons dt
459− deriveUnboxInternal preds headTy cons
435+deriveUnbox :: Q [Dec] -> Q [Dec]
436+deriveUnbox mDecs = do
437+ dec <- mDecs
438+ case dec of
439+ [InstanceD mo preds headTyWC []] -> do
440+ let headTy = unwrap dec headTyWC
441+ dt <- reifyDataType (getMainTypeName dec headTy)
442+ let cons = dtCons dt
443+ deriveUnboxInternal headTy cons (mkInst mo preds headTyWC)
444+ _ -> errorMessage dec
460445
461446 where
462447
463− unboxPred ty =
464−#if MIN_VERSION_template_haskell(2,10,0)
465− AppT (ConT ''Unbox) ty
466−#else
467− ClassP ''Unbox [ty]
468−#endif
448+ mkInst mo preds headTyWC methods =
449+ pure [InstanceD mo preds headTyWC methods]
450+
451+ errorMessage dec =
452+ error $ unlines
453+ [ "Error: deriveUnbox:"
454+ , ""
455+ , ">> " ++ pprint dec
456+ , ""
457+ , "The supplied declaration not a valid instance declaration."
458+ , "Provide a valid Haskell instance declaration without a body."
459+ , ""
460+ , "Examples:"
461+ , "instance Unbox (Proxy a)"
462+ , "instance Unbox a => Unbox (Identity a)"
463+ , "instance Unbox (TableT Identity)"
464+ ]
469465
470−-- | @deriveUnbox dataTypeName@ generates a template Haskell splice consisting
471−-- of a declaration of the 'Unbox' instance for the given dataTypeName,
472−-- varNames is a list of parameter names of dataTypeName that are required
473−-- to have the 'Unbox' constraint.
474−--
475−-- For example,
476−--
477−-- @
478−-- data CustomDataType a b c = ...
479−-- \$(deriveUnboxWith ["a", "c"] ''CustomDataType)
480−-- @
481−--
482−-- Generates the following code:
483−--
484−-- @
485−-- instance (Unbox a, Unbox c) => Unbox (CustomDataType a b c) where
486−-- ...
487−-- @
488−--
489−deriveUnboxWith :: [String] -> Name -> Q [Dec]
490−deriveUnboxWith vars name = do
491− dt <- reifyDataType name
492− let preds = map (unboxPred . VarT) (fmap mkName vars)
493− headTy = appsT (ConT name) (map VarT (dtTvs dt))
494− cons = dtCons dt
495− deriveUnboxInternal preds headTy cons
466+ unwrap _ (AppT (ConT _) r) = r
467+ unwrap dec _ = errorMessage dec
496468
497− where
469+ getMainTypeName dec = go
498470
499− unboxPred ty =
500−#if MIN_VERSION_template_haskell(2,10,0)
501− AppT (ConT ''Unbox) ty
502−#else
503− ClassP ''Unbox [ty]
504−#endif
471+ where
472+
473+ go (ConT nm) = nm
474+ go (AppT l _) = go l
475+ go _ = errorMessage dec
test/Streamly/Test/Data/Unbox.hs+6−9
@@ -28,9 +28,6 @@ import GHC.Generics (Generic, Rep(..))
2828import GHC.Real (Ratio(..))
2929
3030import Streamly.Internal.Data.Serialize
31−#ifdef USE_SERIALIZE
32−import qualified Streamly.Internal.Data.Serialize as Serialize
33−#endif
3431
3532import Test.Hspec as H
3633
@@ -41,7 +38,7 @@ import Test.Hspec as H
4138#ifdef USE_SERIALIZE
4239
4340#define MODULE_NAME "Data.Serialize.Deriving.TH"
44−#define DERIVE_UNBOX(typ) $(Serialize.deriveSerialize [d|instance Serialize typ|])
41+#define DERIVE_UNBOX(typ) $(deriveSerialize [d|instance Serialize typ|])
4542#define PEEK(i, arr, sz) (deserialize i arr sz)
4643#define POKE(i, arr, val) (serialize i arr val)
4744#define TYPE_CLASS Serialize
@@ -55,7 +52,7 @@ import Test.Hspec as H
5552#ifdef USE_TH
5653
5754#define MODULE_NAME "Data.Unbox.Deriving.TH"
58−#define DERIVE_UNBOX(typ) $(deriveUnbox ''typ)
55+#define DERIVE_UNBOX(typ) $(deriveUnbox [d|instance Unbox typ|])
5956
6057#else
6158
@@ -168,13 +165,13 @@ DERIVE_UNBOX(NestedSOP)
168165deriving instance Generic (Ratio Int)
169166
170167#if defined(USE_SERIALIZE)
171−$(Serialize.deriveSerialize
168+$(deriveSerialize
172169 [d|instance Serialize a => Serialize (Complex a)|])
173−$(Serialize.deriveSerialize
170+$(deriveSerialize
174171 [d|instance Serialize a => Serialize (Ratio a)|])
175−$(Serialize.deriveSerialize
172+$(deriveSerialize
176173 [d|instance Serialize a => Serialize (Const a b)|])
177−$(Serialize.deriveSerialize
174+$(deriveSerialize
178175 [d|instance Serialize a => Serialize (Identity a)|])
179176#endif
180177
test/Streamly/Test/Data/Unbox/TH.hs+5−4
@@ -62,10 +62,11 @@ data CustomDataType4 a b
6262 | CDT4Constructor3 Bool b
6363 deriving (Show, Eq)
6464
65−$(deriveUnbox ''CustomDataType1)
66−$(deriveUnbox ''CustomDataType2)
67−$(deriveUnbox ''CustomDataType3)
68−$(deriveUnboxWith ["b"] ''CustomDataType4)
65+$(deriveUnbox [d|instance Unbox CustomDataType1|])
66+$(deriveUnbox [d|instance Unbox CustomDataType2|])
67+$(deriveUnbox
68+ [d|instance (Unbox a, Unbox b, Unbox c) => Unbox (CustomDataType3 a b c)|])
69+$(deriveUnbox [d|instance Unbox b => Unbox (CustomDataType4 a b)|])
6970
7071--------------------------------------------------------------------------------
7172-- CPP helpers