{-# LANGUAGE CPP, DefaultSignatures, EmptyDataDecls, FlexibleInstances,
FunctionalDependencies, KindSignatures,
ScopedTypeVariables, TypeOperators, UndecidableInstances,
ViewPatterns, NamedFieldPuns, FlexibleContexts, PatternGuards,
RecordWildCards, DataKinds #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
#include "overlapping-compat.h"
module Data.Aeson.Types.Generic ( ) where
import Control.Applicative ((<|>))
import Control.Monad ((<=<))
import Control.Monad.ST (ST)
import Data.Aeson.Encode.Builder (emptyArray_)
import Data.Aeson.Encode.Functions (builder)
import Data.Aeson.Types.Instances
import Data.Aeson.Types.Internal
import Data.Bits (unsafeShiftR)
import Data.ByteString.Builder as B
import Data.DList (DList, toList, empty)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.Text (Text, pack, unpack)
import GHC.Generics
import qualified Data.HashMap.Strict as H
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as VM
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<*>), (<$>), pure)
import Data.Monoid (mempty)
#endif
instance OVERLAPPABLE_ (GToJSON a) => GToJSON (M1 i c a) where
gToJSON opts = gToJSON opts . unM1
instance (ToJSON a) => GToJSON (K1 i a) where
gToJSON _opts = toJSON . unK1
instance GToJSON U1 where
gToJSON _opts _ = emptyArray
instance (ConsToJSON a) => GToJSON (C1 c a) where
gToJSON opts = consToJSON opts . unM1
instance ( WriteProduct a, WriteProduct b
, ProductSize a, ProductSize b ) => GToJSON (a :*: b) where
gToJSON opts p =
Array $ V.create $ do
mv <- VM.unsafeNew lenProduct
writeProduct opts mv 0 lenProduct p
return mv
where
lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
productSize
instance ( AllNullary (a :+: b) allNullary
, SumToJSON (a :+: b) allNullary ) => GToJSON (a :+: b) where
gToJSON opts = (unTagged :: Tagged allNullary Value -> Value)
. sumToJSON opts
instance OVERLAPPABLE_ (GToEncoding a) => GToEncoding (M1 i c a) where
gToEncoding opts = gToEncoding opts . unM1
instance (ToJSON a) => GToEncoding (K1 i a) where
gToEncoding _opts = toEncoding . unK1
instance GToEncoding U1 where
gToEncoding _opts _ = emptyArray_
instance (ConsToEncoding a) => GToEncoding (C1 c a) where
gToEncoding opts = Encoding . consToEncoding opts . unM1
instance ( EncodeProduct a, EncodeProduct b ) => GToEncoding (a :*: b) where
gToEncoding opts p = Encoding $
B.char7 '[' <> encodeProduct opts p <> B.char7 ']'
instance ( AllNullary (a :+: b) allNullary
, SumToEncoding (a :+: b) allNullary ) => GToEncoding (a :+: b) where
gToEncoding opts = Encoding .
(unTagged :: Tagged allNullary B.Builder -> B.Builder) .
sumToEncoding opts
class SumToJSON f allNullary where
sumToJSON :: Options -> f a -> Tagged allNullary Value
instance ( GetConName f
, TaggedObjectPairs f
, ObjectWithSingleFieldObj f
, TwoElemArrayObj f ) => SumToJSON f True where
sumToJSON opts
| allNullaryToStringTag opts = Tagged . String . pack
. constructorTagModifier opts . getConName
| otherwise = Tagged . nonAllNullarySumToJSON opts
instance ( TwoElemArrayObj f
, TaggedObjectPairs f
, ObjectWithSingleFieldObj f ) => SumToJSON f False where
sumToJSON opts = Tagged . nonAllNullarySumToJSON opts
nonAllNullarySumToJSON :: ( TwoElemArrayObj f
, TaggedObjectPairs f
, ObjectWithSingleFieldObj f
) => Options -> f a -> Value
nonAllNullarySumToJSON opts =
case sumEncoding opts of
TaggedObject{..} ->
object . taggedObjectPairs opts tagFieldName contentsFieldName
ObjectWithSingleField -> Object . objectWithSingleFieldObj opts
TwoElemArray -> Array . twoElemArrayObj opts
class SumToEncoding f allNullary where
sumToEncoding :: Options -> f a -> Tagged allNullary B.Builder
instance ( GetConName f
, TaggedObjectEnc f
, ObjectWithSingleFieldEnc f
, TwoElemArrayEnc f ) => SumToEncoding f True where
sumToEncoding opts
| allNullaryToStringTag opts = Tagged . builder .
constructorTagModifier opts . getConName
| otherwise = Tagged . nonAllNullarySumToEncoding opts
instance ( TwoElemArrayEnc f
, TaggedObjectEnc f
, ObjectWithSingleFieldEnc f ) => SumToEncoding f False where
sumToEncoding opts = Tagged . nonAllNullarySumToEncoding opts
nonAllNullarySumToEncoding :: ( TwoElemArrayEnc f
, TaggedObjectEnc f
, ObjectWithSingleFieldEnc f
) => Options -> f a -> B.Builder
nonAllNullarySumToEncoding opts =
case sumEncoding opts of
TaggedObject{..} ->
taggedObjectEnc opts tagFieldName contentsFieldName
ObjectWithSingleField -> objectWithSingleFieldEnc opts
TwoElemArray -> twoElemArrayEnc opts
class TaggedObjectPairs f where
taggedObjectPairs :: Options -> String -> String -> f a -> [Pair]
instance ( TaggedObjectPairs a
, TaggedObjectPairs b ) => TaggedObjectPairs (a :+: b) where
taggedObjectPairs opts tagFieldName contentsFieldName (L1 x) =
taggedObjectPairs opts tagFieldName contentsFieldName x
taggedObjectPairs opts tagFieldName contentsFieldName (R1 x) =
taggedObjectPairs opts tagFieldName contentsFieldName x
instance ( IsRecord a isRecord
, TaggedObjectPairs' a isRecord
, Constructor c ) => TaggedObjectPairs (C1 c a) where
taggedObjectPairs opts tagFieldName contentsFieldName =
(pack tagFieldName .= constructorTagModifier opts
(conName (undefined :: t c a p)) :) .
(unTagged :: Tagged isRecord [Pair] -> [Pair]) .
taggedObjectPairs' opts contentsFieldName . unM1
class TaggedObjectPairs' f isRecord where
taggedObjectPairs' :: Options -> String -> f a -> Tagged isRecord [Pair]
instance (RecordToPairs f) => TaggedObjectPairs' f True where
taggedObjectPairs' opts _ = Tagged . toList . recordToPairs opts
instance (GToJSON f) => TaggedObjectPairs' f False where
taggedObjectPairs' opts contentsFieldName =
Tagged . (:[]) . (pack contentsFieldName .=) . gToJSON opts
class TaggedObjectEnc f where
taggedObjectEnc :: Options -> String -> String -> f a -> B.Builder
instance ( TaggedObjectEnc a
, TaggedObjectEnc b ) => TaggedObjectEnc (a :+: b) where
taggedObjectEnc opts tagFieldName contentsFieldName (L1 x) =
taggedObjectEnc opts tagFieldName contentsFieldName x
taggedObjectEnc opts tagFieldName contentsFieldName (R1 x) =
taggedObjectEnc opts tagFieldName contentsFieldName x
instance ( IsRecord a isRecord
, TaggedObjectEnc' a isRecord
, Constructor c ) => TaggedObjectEnc (C1 c a) where
taggedObjectEnc opts tagFieldName contentsFieldName v =
B.char7 '{' <>
(builder tagFieldName <>
B.char7 ':' <>
builder (constructorTagModifier opts (conName (undefined :: t c a p)))) <>
B.char7 ',' <>
((unTagged :: Tagged isRecord B.Builder -> B.Builder) .
taggedObjectEnc' opts contentsFieldName . unM1 $ v) <>
B.char7 '}'
class TaggedObjectEnc' f isRecord where
taggedObjectEnc' :: Options -> String -> f a -> Tagged isRecord B.Builder
instance (RecordToEncoding f) => TaggedObjectEnc' f True where
taggedObjectEnc' opts _ = Tagged . recordToEncoding opts
instance (GToEncoding f) => TaggedObjectEnc' f False where
taggedObjectEnc' opts contentsFieldName =
Tagged . (\z -> builder contentsFieldName <> B.char7 ':' <> z) .
gbuilder opts
class GetConName f where
getConName :: f a -> String
instance (GetConName a, GetConName b) => GetConName (a :+: b) where
getConName (L1 x) = getConName x
getConName (R1 x) = getConName x
instance (Constructor c) => GetConName (C1 c a) where
getConName = conName
class TwoElemArrayObj f where
twoElemArrayObj :: Options -> f a -> V.Vector Value
instance (TwoElemArrayObj a, TwoElemArrayObj b) => TwoElemArrayObj (a :+: b) where
twoElemArrayObj opts (L1 x) = twoElemArrayObj opts x
twoElemArrayObj opts (R1 x) = twoElemArrayObj opts x
instance ( GToJSON a, ConsToJSON a
, Constructor c ) => TwoElemArrayObj (C1 c a) where
twoElemArrayObj opts x = V.create $ do
mv <- VM.unsafeNew 2
VM.unsafeWrite mv 0 $ String $ pack $ constructorTagModifier opts
$ conName (undefined :: t c a p)
VM.unsafeWrite mv 1 $ gToJSON opts x
return mv
class TwoElemArrayEnc f where
twoElemArrayEnc :: Options -> f a -> B.Builder
instance (TwoElemArrayEnc a, TwoElemArrayEnc b) => TwoElemArrayEnc (a :+: b) where
twoElemArrayEnc opts (L1 x) = twoElemArrayEnc opts x
twoElemArrayEnc opts (R1 x) = twoElemArrayEnc opts x
instance ( GToEncoding a, ConsToEncoding a
, Constructor c ) => TwoElemArrayEnc (C1 c a) where
twoElemArrayEnc opts x = fromEncoding . tuple $
builder (constructorTagModifier opts (conName (undefined :: t c a p))) >*<
gbuilder opts x
class ConsToJSON f where
consToJSON :: Options -> f a -> Value
class ConsToJSON' f isRecord where
consToJSON' :: Options -> Bool
-> f a -> Tagged isRecord Value
instance ( IsRecord f isRecord
, ConsToJSON' f isRecord ) => ConsToJSON f where
consToJSON opts = (unTagged :: Tagged isRecord Value -> Value)
. consToJSON' opts (isUnary (undefined :: f a))
instance (RecordToPairs f) => ConsToJSON' f True where
consToJSON' opts isUn f = let
vals = toList $ recordToPairs opts f
in case (unwrapUnaryRecords opts,isUn,vals) of
(True,True,[(_,val)]) -> Tagged val
_ -> Tagged $ object vals
instance GToJSON f => ConsToJSON' f False where
consToJSON' opts _ = Tagged . gToJSON opts
class ConsToEncoding f where
consToEncoding :: Options -> f a -> B.Builder
class ConsToEncoding' f isRecord where
consToEncoding' :: Options -> Bool
-> f a -> Tagged isRecord B.Builder
instance ( IsRecord f isRecord
, ConsToEncoding' f isRecord ) => ConsToEncoding f where
consToEncoding opts = (unTagged :: Tagged isRecord B.Builder -> B.Builder)
. consToEncoding' opts (isUnary (undefined :: f a))
instance (RecordToEncoding f) => ConsToEncoding' f True where
consToEncoding' opts isUn x
| (True,True) <- (unwrapUnaryRecords opts,isUn) = Tagged $ recordToEncoding opts x
| otherwise = Tagged $
B.char7 '{' <>
recordToEncoding opts x <>
B.char7 '}'
instance GToEncoding f => ConsToEncoding' f False where
consToEncoding' opts _ = Tagged . gbuilder opts
class RecordToPairs f where
recordToPairs :: Options -> f a -> DList Pair
instance (RecordToPairs a, RecordToPairs b) => RecordToPairs (a :*: b) where
recordToPairs opts (a :*: b) = recordToPairs opts a <>
recordToPairs opts b
instance (Selector s, GToJSON a) => RecordToPairs (S1 s a) where
recordToPairs = fieldToPair
instance OVERLAPPING_ (Selector s, ToJSON a) =>
RecordToPairs (S1 s (K1 i (Maybe a))) where
recordToPairs opts (M1 k1) | omitNothingFields opts
, K1 Nothing <- k1 = empty
recordToPairs opts m1 = fieldToPair opts m1
fieldToPair :: (Selector s, GToJSON a) => Options -> S1 s a p -> DList Pair
fieldToPair opts m1 = pure ( pack $ fieldLabelModifier opts $ selName m1
, gToJSON opts (unM1 m1)
)
class RecordToEncoding f where
recordToEncoding :: Options -> f a -> B.Builder
instance (RecordToEncoding a, RecordToEncoding b) => RecordToEncoding (a :*: b) where
recordToEncoding opts (a :*: b) = recordToEncoding opts a <>
B.char7 ',' <>
recordToEncoding opts b
instance (Selector s, GToEncoding a) => RecordToEncoding (S1 s a) where
recordToEncoding = fieldToEncoding
instance OVERLAPPING_ (Selector s, ToJSON a) =>
RecordToEncoding (S1 s (K1 i (Maybe a))) where
recordToEncoding opts (M1 k1) | omitNothingFields opts
, K1 Nothing <- k1 = mempty
recordToEncoding opts m1 = fieldToEncoding opts m1
fieldToEncoding :: (Selector s, GToEncoding a) => Options -> S1 s a p -> B.Builder
fieldToEncoding opts m1 =
builder (fieldLabelModifier opts $ selName m1) <>
B.char7 ':' <>
gbuilder opts (unM1 m1)
class WriteProduct f where
writeProduct :: Options
-> VM.MVector s Value
-> Int
-> Int
-> f a
-> ST s ()
instance ( WriteProduct a
, WriteProduct b ) => WriteProduct (a :*: b) where
writeProduct opts mv ix len (a :*: b) = do
writeProduct opts mv ix lenL a
writeProduct opts mv ixR lenR b
where
lenL = len `unsafeShiftR` 1
lenR = len - lenL
ixR = ix + lenL
instance OVERLAPPABLE_ (GToJSON a) => WriteProduct a where
writeProduct opts mv ix _ = VM.unsafeWrite mv ix . gToJSON opts
class EncodeProduct f where
encodeProduct :: Options -> f a -> B.Builder
instance ( EncodeProduct a
, EncodeProduct b ) => EncodeProduct (a :*: b) where
encodeProduct opts (a :*: b) = encodeProduct opts a <>
B.char7 ',' <>
encodeProduct opts b
instance OVERLAPPABLE_ (GToEncoding a) => EncodeProduct a where
encodeProduct opts = gbuilder opts
class ObjectWithSingleFieldObj f where
objectWithSingleFieldObj :: Options -> f a -> Object
instance ( ObjectWithSingleFieldObj a
, ObjectWithSingleFieldObj b ) => ObjectWithSingleFieldObj (a :+: b) where
objectWithSingleFieldObj opts (L1 x) = objectWithSingleFieldObj opts x
objectWithSingleFieldObj opts (R1 x) = objectWithSingleFieldObj opts x
instance ( GToJSON a, ConsToJSON a
, Constructor c ) => ObjectWithSingleFieldObj (C1 c a) where
objectWithSingleFieldObj opts = H.singleton typ . gToJSON opts
where
typ = pack $ constructorTagModifier opts $
conName (undefined :: t c a p)
class ObjectWithSingleFieldEnc f where
objectWithSingleFieldEnc :: Options -> f a -> B.Builder
instance ( ObjectWithSingleFieldEnc a
, ObjectWithSingleFieldEnc b ) => ObjectWithSingleFieldEnc (a :+: b) where
objectWithSingleFieldEnc opts (L1 x) = objectWithSingleFieldEnc opts x
objectWithSingleFieldEnc opts (R1 x) = objectWithSingleFieldEnc opts x
instance ( GToEncoding a, ConsToEncoding a
, Constructor c ) => ObjectWithSingleFieldEnc (C1 c a) where
objectWithSingleFieldEnc opts v =
B.char7 '{' <>
builder (constructorTagModifier opts
(conName (undefined :: t c a p))) <>
B.char7 ':' <>
gbuilder opts v <>
B.char7 '}'
gbuilder :: GToEncoding f => Options -> f a -> Builder
gbuilder opts = fromEncoding . gToEncoding opts
instance OVERLAPPABLE_ (GFromJSON a) => GFromJSON (M1 i c a) where
gParseJSON opts = fmap M1 . gParseJSON opts
instance (FromJSON a) => GFromJSON (K1 i a) where
gParseJSON _opts = fmap K1 . parseJSON
instance GFromJSON U1 where
gParseJSON _opts v
| isEmptyArray v = pure U1
| otherwise = typeMismatch "unit constructor (U1)" v
instance (ConsFromJSON a) => GFromJSON (C1 c a) where
gParseJSON opts = fmap M1 . consParseJSON opts
instance ( FromProduct a, FromProduct b
, ProductSize a, ProductSize b ) => GFromJSON (a :*: b) where
gParseJSON opts = withArray "product (:*:)" $ \arr ->
let lenArray = V.length arr
lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
productSize in
if lenArray == lenProduct
then parseProduct opts arr 0 lenProduct
else fail $ "When expecting a product of " ++ show lenProduct ++
" values, encountered an Array of " ++ show lenArray ++
" elements instead"
instance ( AllNullary (a :+: b) allNullary
, ParseSum (a :+: b) allNullary ) => GFromJSON (a :+: b) where
gParseJSON opts = (unTagged :: Tagged allNullary (Parser ((a :+: b) d)) ->
(Parser ((a :+: b) d)))
. parseSum opts
class ParseSum f allNullary where
parseSum :: Options -> Value -> Tagged allNullary (Parser (f a))
instance ( SumFromString (a :+: b)
, FromPair (a :+: b)
, FromTaggedObject (a :+: b) ) => ParseSum (a :+: b) True where
parseSum opts
| allNullaryToStringTag opts = Tagged . parseAllNullarySum opts
| otherwise = Tagged . parseNonAllNullarySum opts
instance ( FromPair (a :+: b)
, FromTaggedObject (a :+: b) ) => ParseSum (a :+: b) False where
parseSum opts = Tagged . parseNonAllNullarySum opts
parseAllNullarySum :: SumFromString f => Options -> Value -> Parser (f a)
parseAllNullarySum opts = withText "Text" $ \key ->
maybe (notFound $ unpack key) return $
parseSumFromString opts key
class SumFromString f where
parseSumFromString :: Options -> Text -> Maybe (f a)
instance (SumFromString a, SumFromString b) => SumFromString (a :+: b) where
parseSumFromString opts key = (L1 <$> parseSumFromString opts key) <|>
(R1 <$> parseSumFromString opts key)
instance (Constructor c) => SumFromString (C1 c U1) where
parseSumFromString opts key | key == name = Just $ M1 U1
| otherwise = Nothing
where
name = pack $ constructorTagModifier opts $
conName (undefined :: t c U1 p)
parseNonAllNullarySum :: ( FromPair (a :+: b)
, FromTaggedObject (a :+: b)
) => Options -> Value -> Parser ((a :+: b) c)
parseNonAllNullarySum opts =
case sumEncoding opts of
TaggedObject{..} ->
withObject "Object" $ \obj -> do
tag <- obj .: pack tagFieldName
fromMaybe (notFound $ unpack tag) $
parseFromTaggedObject opts contentsFieldName obj tag
ObjectWithSingleField ->
withObject "Object" $ \obj ->
case H.toList obj of
[pair@(tag, _)] -> fromMaybe (notFound $ unpack tag) $
parsePair opts pair
_ -> fail "Object doesn't have a single field"
TwoElemArray ->
withArray "Array" $ \arr ->
if V.length arr == 2
then case V.unsafeIndex arr 0 of
String tag -> fromMaybe (notFound $ unpack tag) $
parsePair opts (tag, V.unsafeIndex arr 1)
_ -> fail "First element is not a String"
else fail "Array doesn't have 2 elements"
class FromTaggedObject f where
parseFromTaggedObject :: Options -> String -> Object -> Text
-> Maybe (Parser (f a))
instance (FromTaggedObject a, FromTaggedObject b) =>
FromTaggedObject (a :+: b) where
parseFromTaggedObject opts contentsFieldName obj tag =
(fmap L1 <$> parseFromTaggedObject opts contentsFieldName obj tag) <|>
(fmap R1 <$> parseFromTaggedObject opts contentsFieldName obj tag)
instance ( FromTaggedObject' f
, Constructor c ) => FromTaggedObject (C1 c f) where
parseFromTaggedObject opts contentsFieldName obj tag
| tag == name = Just $ M1 <$> parseFromTaggedObject'
opts contentsFieldName obj
| otherwise = Nothing
where
name = pack $ constructorTagModifier opts $
conName (undefined :: t c f p)
class FromTaggedObject' f where
parseFromTaggedObject' :: Options -> String -> Object -> Parser (f a)
class FromTaggedObject'' f isRecord where
parseFromTaggedObject'' :: Options -> String -> Object
-> Tagged isRecord (Parser (f a))
instance ( IsRecord f isRecord
, FromTaggedObject'' f isRecord
) => FromTaggedObject' f where
parseFromTaggedObject' opts contentsFieldName =
(unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a)) .
parseFromTaggedObject'' opts contentsFieldName
instance (FromRecord f) => FromTaggedObject'' f True where
parseFromTaggedObject'' opts _ = Tagged . parseRecord opts Nothing
instance (GFromJSON f) => FromTaggedObject'' f False where
parseFromTaggedObject'' opts contentsFieldName = Tagged .
(gParseJSON opts <=< (.: pack contentsFieldName))
class ConsFromJSON f where
consParseJSON :: Options -> Value -> Parser (f a)
class ConsFromJSON' f isRecord where
consParseJSON' :: Options -> (Maybe Text)
-> Value -> Tagged isRecord (Parser (f a))
instance ( IsRecord f isRecord
, ConsFromJSON' f isRecord
) => ConsFromJSON f where
consParseJSON opts v = let
(v2,lab) = case (unwrapUnaryRecords opts,isUnary (undefined :: f a)) of
(True,True) -> ((object [(pack "dummy",v)]),Just $ pack "dummy")
_ ->(v,Nothing)
in (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))
$ consParseJSON' opts lab v2
instance (FromRecord f) => ConsFromJSON' f True where
consParseJSON' opts mlab = Tagged . (withObject "record (:*:)"
$ parseRecord opts mlab)
instance (GFromJSON f) => ConsFromJSON' f False where
consParseJSON' opts _ = Tagged . gParseJSON opts
class FromRecord f where
parseRecord :: Options -> (Maybe Text)
-> Object -> Parser (f a)
instance (FromRecord a, FromRecord b) => FromRecord (a :*: b) where
parseRecord opts _ obj = (:*:) <$> parseRecord opts Nothing obj
<*> parseRecord opts Nothing obj
instance (Selector s, GFromJSON a) => FromRecord (S1 s a) where
parseRecord opts (Just lab) = maybe (notFound $ unpack lab)
(gParseJSON opts) . H.lookup lab
parseRecord opts Nothing = maybe (notFound label)
(gParseJSON opts) . H.lookup (pack label)
where
label = fieldLabelModifier opts $ selName (undefined :: t s a p)
instance OVERLAPPING_ (Selector s, FromJSON a) =>
FromRecord (S1 s (K1 i (Maybe a))) where
parseRecord _ (Just lab) obj = (M1 . K1) <$> obj .:? lab
parseRecord opts Nothing obj = (M1 . K1) <$> obj .:? pack label
where
label = fieldLabelModifier opts $
selName (undefined :: t s (K1 i (Maybe a)) p)
class ProductSize f where
productSize :: Tagged2 f Int
instance (ProductSize a, ProductSize b) => ProductSize (a :*: b) where
productSize = Tagged2 $ unTagged2 (productSize :: Tagged2 a Int) +
unTagged2 (productSize :: Tagged2 b Int)
instance ProductSize (S1 s a) where
productSize = Tagged2 1
class FromProduct f where
parseProduct :: Options -> Array -> Int -> Int -> Parser (f a)
instance (FromProduct a, FromProduct b) => FromProduct (a :*: b) where
parseProduct opts arr ix len =
(:*:) <$> parseProduct opts arr ix lenL
<*> parseProduct opts arr ixR lenR
where
lenL = len `unsafeShiftR` 1
ixR = ix + lenL
lenR = len - lenL
instance (GFromJSON a) => FromProduct (S1 s a) where
parseProduct opts arr ix _ = gParseJSON opts $ V.unsafeIndex arr ix
class FromPair f where
parsePair :: Options -> Pair -> Maybe (Parser (f a))
instance (FromPair a, FromPair b) => FromPair (a :+: b) where
parsePair opts pair = (fmap L1 <$> parsePair opts pair) <|>
(fmap R1 <$> parsePair opts pair)
instance (Constructor c, GFromJSON a, ConsFromJSON a) => FromPair (C1 c a) where
parsePair opts (tag, value)
| tag == tag' = Just $ gParseJSON opts value
| otherwise = Nothing
where
tag' = pack $ constructorTagModifier opts $
conName (undefined :: t c a p)
class IsRecord (f :: * -> *) isRecord | f -> isRecord
where
isUnary :: f a -> Bool
isUnary = const True
instance (IsRecord f isRecord) => IsRecord (f :*: g) isRecord
where isUnary = const False
#if MIN_VERSION_base(4,9,0)
instance OVERLAPPING_ IsRecord (M1 S ('MetaSel 'Nothing u ss ds) f) False
#else
instance OVERLAPPING_ IsRecord (M1 S NoSelector f) False
#endif
instance (IsRecord f isRecord) => IsRecord (M1 S c f) isRecord
instance IsRecord (K1 i c) True
instance IsRecord U1 False
where isUnary = const False
--------------------------------------------------------------------------------
class AllNullary (f :: * -> *) allNullary | f -> allNullary
instance ( AllNullary a allNullaryL
, AllNullary b allNullaryR
, And allNullaryL allNullaryR allNullary
) => AllNullary (a :+: b) allNullary
instance AllNullary a allNullary => AllNullary (M1 i c a) allNullary
instance AllNullary (a :*: b) False
instance AllNullary (K1 i c) False
instance AllNullary U1 True
--------------------------------------------------------------------------------
data True
data False
class And bool1 bool2 bool3 | bool1 bool2 -> bool3
instance And True True True
instance And False False False
instance And False True False
instance And True False False
--------------------------------------------------------------------------------
newtype Tagged s b = Tagged {unTagged :: b}
newtype Tagged2 (s :: * -> *) b = Tagged2 {unTagged2 :: b}
--------------------------------------------------------------------------------
notFound :: String -> Parser a
notFound key = fail $ "The key \"" ++ key ++ "\" was not found"
{-# INLINE notFound #-}