module Z.Data.JSON.Base
(
DecodeError
, decode, decode', decodeText, decodeText', decodeChunks, decodeChunks', encodeBytes, encodeText, encodeTextBuilder
, Value(..)
, JV.parseValue, JV.parseValue', JV.parseValueChunks, JV.parseValueChunks'
, convert, convert', Converter(..), fail', (<?>), prependContext
, PathElement(..), ConvertError
, typeMismatch, fromNull, withBool, withScientific, withBoundedScientific, withRealFloat
, withBoundedIntegral, withText, withArray, withKeyValues, withFlatMap, withFlatMapR
, withHashMap, withHashMapR, withEmbeddedJSON
, (.:), (.:?), (.:!), convertField, convertFieldMaybe, convertFieldMaybe'
, defaultSettings, Settings(..)
, ToValue(..), GToValue(..)
, FromValue(..), GFromValue(..)
, EncodeJSON(..), GEncodeJSON(..)
, Field, GWriteFields(..), GMergeFields(..), GConstrToValue(..)
, LookupTable, GFromFields(..), GBuildLookup(..), GConstrFromValue(..)
, GAddPunctuation(..), GConstrEncodeJSON(..)
, commaList'
, commaVec'
) where
import Control.Applicative
import Control.DeepSeq
import Control.Monad
import qualified Control.Monad.Fail as Fail
import Control.Monad.ST
import Data.Char (ord)
import Data.Data
import Data.Fixed
import Data.Functor.Compose
import Data.Functor.Const
import Data.Functor.Identity
import Data.Functor.Product
import Data.Functor.Sum
import Data.Hashable
import qualified Data.HashMap.Strict as HM
import qualified Data.HashSet as HS
import Data.Int
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Monoid as Monoid
import Data.Primitive.Types (Prim)
import Data.Proxy (Proxy(..))
import Data.Ratio (Ratio, (%), numerator, denominator)
import Data.Scientific (Scientific, base10Exponent, toBoundedInteger)
import qualified Data.Scientific as Scientific
import qualified Data.Semigroup as Semigroup
import qualified Data.Primitive.ByteArray as A
import qualified Data.Primitive.SmallArray as A
import Data.Tagged (Tagged (..))
import Data.Version (Version, parseVersion)
import Data.Word
import Foreign.C.Types
import GHC.Exts (Proxy#, proxy#)
import GHC.Generics
import GHC.Natural
import System.Exit
import Text.ParserCombinators.ReadP (readP_to_S)
import qualified Z.Data.Array as A
import qualified Z.Data.Builder as B
import Z.Data.Generics.Utils
import Z.Data.JSON.Value (Value(..))
import qualified Z.Data.JSON.Value as JV
import qualified Z.Data.JSON.Builder as JB
import qualified Z.Data.Parser as P
import qualified Z.Data.Parser.Numeric as P
import qualified Z.Data.Text.Base as T
import qualified Z.Data.Text as T
import qualified Z.Data.Text.ShowT as T
import qualified Z.Data.Vector.Base as V
import qualified Z.Data.Vector.Extra as V
import qualified Z.Data.Vector.FlatIntMap as FIM
import qualified Z.Data.Vector.FlatIntSet as FIS
import qualified Z.Data.Vector.FlatMap as FM
import qualified Z.Data.Vector.FlatSet as FS
type DecodeError = Either P.ParseError ConvertError
decodeText' :: FromValue a => T.Text -> Either DecodeError a
{-# INLINE decodeText' #-}
decodeText' = decode' . T.getUTF8Bytes
decodeText :: FromValue a => T.Text -> (T.Text, Either DecodeError a)
{-# INLINE decodeText #-}
decodeText t =
let (rest, r) = decode (T.getUTF8Bytes t)
in (T.Text rest, r)
decode' :: FromValue a => V.Bytes -> Either DecodeError a
{-# INLINE decode' #-}
decode' bs = case P.parse_ (JV.value <* JV.skipSpaces <* P.endOfInput) bs of
Left pErr -> Left (Left pErr)
Right v -> case convert fromValue v of
Left cErr -> Left (Right cErr)
Right r -> Right r
decode :: FromValue a => V.Bytes -> (V.Bytes, Either DecodeError a)
{-# INLINE decode #-}
decode bs = case P.parse JV.value bs of
(bs', Left pErr) -> (bs', Left (Left pErr))
(bs', Right v) -> case convert fromValue v of
Left cErr -> (bs', Left (Right cErr))
Right r -> (bs', Right r)
decodeChunks :: (FromValue a, Monad m) => m V.Bytes -> V.Bytes -> m (V.Bytes, Either DecodeError a)
{-# INLINE decodeChunks #-}
decodeChunks mb bs = do
mr <- (P.parseChunks JV.value mb bs)
case mr of
(bs', Left pErr) -> pure (bs', Left (Left pErr))
(bs', Right v) -> case convert fromValue v of
Left cErr -> pure (bs', Left (Right cErr))
Right r -> pure (bs', Right r)
decodeChunks' :: (FromValue a, Monad m) => m V.Bytes -> V.Bytes -> m (Either DecodeError a)
{-# INLINE decodeChunks' #-}
decodeChunks' mb bs = do
mr <- (P.parseChunks (JV.value <* JV.skipSpaces <* P.endOfInput) mb bs)
case mr of
(_, Left pErr) -> pure (Left (Left pErr))
(_, Right v) -> case convert fromValue v of
Left cErr -> pure (Left (Right cErr))
Right r -> pure (Right r)
encodeBytes :: EncodeJSON a => a -> V.Bytes
{-# INLINE encodeBytes #-}
encodeBytes = B.buildBytes . encodeJSON
encodeText :: EncodeJSON a => a -> T.Text
{-# INLINE encodeText #-}
encodeText = T.buildText . encodeTextBuilder
encodeTextBuilder :: EncodeJSON a => a -> T.TextBuilder ()
{-# INLINE encodeTextBuilder #-}
encodeTextBuilder = T.unsafeFromBuilder . encodeJSON
convert :: (a -> Converter r) -> a -> Either ConvertError r
{-# INLINE convert #-}
convert m v = runConverter (m v) (\ paths msg -> (Left (ConvertError paths msg))) Right
convert' :: (FromValue a) => Value -> Either ConvertError a
{-# INLINE convert' #-}
convert' = convert fromValue
data PathElement
= Key {-# UNPACK #-} !T.Text
| Index {-# UNPACK #-} !Int
| Embedded
deriving (Eq, Show, Typeable, Ord, Generic, NFData)
data ConvertError = ConvertError { errPath :: [PathElement], errMsg :: T.Text } deriving (Eq, Ord, Generic, NFData)
instance Show ConvertError where
show (ConvertError paths msg) = T.unpack . T.buildText $ do
"<"
mapM_ renderPath (reverse paths)
"> "
T.text msg
where
renderPath (Index ix) = T.char7 '[' >> T.int ix >> T.char7 ']'
renderPath (Key k) = T.char7 '.' >> (T.unsafeFromBuilder $ JB.string k)
renderPath Embedded = "<Embedded>"
newtype Converter a = Converter { runConverter :: forall r. ([PathElement] -> T.Text -> r) -> (a -> r) -> r }
instance Functor Converter where
fmap f m = Converter (\ kf k -> runConverter m kf (k . f))
{-# INLINE fmap #-}
instance Applicative Converter where
pure a = Converter (\ _ k -> k a)
{-# INLINE pure #-}
(Converter f) <*> (Converter g) = Converter (\ kf k ->
f kf (\ f' -> g kf (k . f')))
{-# INLINE (<*>) #-}
instance Alternative Converter where
{-# INLINE (<|>) #-}
(Converter f) <|> (Converter g) = Converter (\ kf k -> f (\ _ _ -> g kf k) k)
{-# INLINE empty #-}
empty = fail' "Z.Data.JSON.Base(Alternative).empty"
instance MonadPlus Converter where
mzero = empty
{-# INLINE mzero #-}
mplus = (<|>)
{-# INLINE mplus #-}
instance Monad Converter where
(Converter f) >>= g = Converter (\ kf k ->
f kf (\ a -> runConverter (g a) kf k))
{-# INLINE (>>=) #-}
return = pure
{-# INLINE return #-}
instance Fail.MonadFail Converter where
{-# INLINE fail #-}
fail = fail' . T.pack
fail' :: T.Text -> Converter a
{-# INLINE fail' #-}
fail' msg = Converter (\ kf _ -> kf [] msg)
typeMismatch :: T.Text
-> T.Text
-> Value
-> Converter a
{-# INLINE typeMismatch #-}
typeMismatch name expected v =
fail' $ T.concat ["converting ", name, " failed, expected ", expected, ", encountered ", actual]
where
actual = case v of
Object _ -> "Object"
Array _ -> "Array"
String _ -> "String"
Number _ -> "Number"
Bool _ -> "Boolean"
_ -> "Null"
(<?>) :: Converter a -> PathElement -> Converter a
{-# INLINE (<?>) #-}
(Converter p) <?> path = Converter (\ kf k -> p (kf . (path:)) k)
infixl 9 <?>
prependContext :: T.Text -> Converter a -> Converter a
{-# INLINE prependContext #-}
prependContext name (Converter p) = Converter (\ kf k ->
p (\ paths msg -> kf paths (T.concat ["converting ", name, " failed, ", msg])) k)
fromNull :: T.Text -> a -> Value -> Converter a
{-# INLINE fromNull #-}
fromNull _ a Null = pure a
fromNull c _ v = typeMismatch c "Null" v
withBool :: T.Text -> (Bool -> Converter a) -> Value -> Converter a
{-# INLINE withBool #-}
withBool _ f (Bool x) = f x
withBool name _ v = typeMismatch name "Bool" v
withScientific :: T.Text -> (Scientific -> Converter a) -> Value -> Converter a
{-# INLINE withScientific #-}
withScientific _ f (Number x) = f x
withScientific name _ v = typeMismatch name "Number" v
withRealFloat :: RealFloat a => T.Text -> (a -> Converter r) -> Value -> Converter r
{-# INLINE withRealFloat #-}
withRealFloat _ f (Number s) = f (Scientific.toRealFloat s)
withRealFloat _ f Null = f (0/0)
withRealFloat name _ v = typeMismatch name "Number or Null" v
withBoundedScientific :: T.Text -> (Scientific -> Converter a) -> Value -> Converter a
{-# INLINE withBoundedScientific #-}
withBoundedScientific name f (Number x)
| e <= 1024 = f x
| otherwise = fail' . T.buildText $ do
"converting "
T.text name
" failed, found a number with exponent "
T.int e
", but it must not be greater than 1024"
where e = base10Exponent x
withBoundedScientific name _ v = typeMismatch name "Number" v
withBoundedIntegral :: (Bounded a, Integral a) => T.Text -> (a -> Converter r) -> Value -> Converter r
{-# INLINE withBoundedIntegral #-}
withBoundedIntegral name f (Number x) =
case toBoundedInteger x of
Just i -> f i
_ -> fail' . T.buildText $ do
"converting "
T.text name
"failed, value is either floating or will cause over or underflow: "
T.scientific x
withBoundedIntegral name _ v = typeMismatch name "Number" v
withText :: T.Text -> (T.Text -> Converter a) -> Value -> Converter a
{-# INLINE withText #-}
withText _ f (String x) = f x
withText name _ v = typeMismatch name "String" v
withArray :: T.Text -> (V.Vector Value -> Converter a) -> Value -> Converter a
{-# INLINE withArray #-}
withArray _ f (Array arr) = f arr
withArray name _ v = typeMismatch name "Array" v
withKeyValues :: T.Text -> (V.Vector (T.Text, Value) -> Converter a) -> Value -> Converter a
{-# INLINE withKeyValues #-}
withKeyValues _ f (Object kvs) = f kvs
withKeyValues name _ v = typeMismatch name "Object" v
withFlatMap :: T.Text -> (FM.FlatMap T.Text Value -> Converter a) -> Value -> Converter a
{-# INLINE withFlatMap #-}
withFlatMap _ f (Object obj) = f (FM.packVector obj)
withFlatMap name _ v = typeMismatch name "Object" v
withFlatMapR :: T.Text -> (FM.FlatMap T.Text Value -> Converter a) -> Value -> Converter a
{-# INLINE withFlatMapR #-}
withFlatMapR _ f (Object obj) = f (FM.packVectorR obj)
withFlatMapR name _ v = typeMismatch name "Object" v
withHashMap :: T.Text -> (HM.HashMap T.Text Value -> Converter a) -> Value -> Converter a
{-# INLINE withHashMap #-}
withHashMap _ f (Object obj) = f (HM.fromList (V.unpackR obj))
withHashMap name _ v = typeMismatch name "Object" v
withHashMapR :: T.Text -> (HM.HashMap T.Text Value -> Converter a) -> Value -> Converter a
{-# INLINE withHashMapR #-}
withHashMapR _ f (Object obj) = f (HM.fromList (V.unpack obj))
withHashMapR name _ v = typeMismatch name "Object" v
withEmbeddedJSON :: T.Text
-> (Value -> Converter a)
-> Value -> Converter a
{-# INLINE withEmbeddedJSON #-}
withEmbeddedJSON _ innerConverter (String txt) = Converter (\ kf k ->
case decode' (T.getUTF8Bytes txt) of
Right v -> runConverter (innerConverter v) (\ paths msg -> kf (Embedded:paths) msg) k
Left (Left pErr) -> kf [] (T.intercalate ", " ("parsing embeded JSON failed ": pErr))
_ -> error "Z.JSON.Base: impossible, converting to Value should not fail")
withEmbeddedJSON name _ v = typeMismatch name "String" v
(.:) :: (FromValue a) => FM.FlatMap T.Text Value -> T.Text -> Converter a
{-# INLINE (.:) #-}
(.:) = convertField fromValue
(.:?) :: (FromValue a) => FM.FlatMap T.Text Value -> T.Text -> Converter (Maybe a)
{-# INLINE (.:?) #-}
(.:?) = convertFieldMaybe fromValue
(.:!) :: (FromValue a) => FM.FlatMap T.Text Value -> T.Text -> Converter (Maybe a)
{-# INLINE (.:!) #-}
(.:!) = convertFieldMaybe' fromValue
convertField :: (Value -> Converter a)
-> FM.FlatMap T.Text Value -> T.Text -> Converter a
{-# INLINE convertField #-}
convertField p obj key = case FM.lookup key obj of
Just v -> p v <?> Key key
_ -> fail' (T.concat $ ["key ", key, " not present"])
convertFieldMaybe :: (Value -> Converter a) -> FM.FlatMap T.Text Value -> T.Text -> Converter (Maybe a)
{-# INLINE convertFieldMaybe #-}
convertFieldMaybe p obj key = case FM.lookup key obj of
Just Null -> pure Nothing
Just v -> Just <$> p v <?> Key key
_ -> pure Nothing
convertFieldMaybe' :: (Value -> Converter a) -> FM.FlatMap T.Text Value -> T.Text -> Converter (Maybe a)
{-# INLINE convertFieldMaybe' #-}
convertFieldMaybe' p obj key = case FM.lookup key obj of
Just v -> Just <$> p v <?> Key key
_ -> pure Nothing
commaList' :: EncodeJSON a => [a] -> B.Builder ()
{-# INLINE commaList' #-}
commaList' = B.intercalateList B.comma encodeJSON
commaVec' :: (EncodeJSON a, V.Vec v a) => v a -> B.Builder ()
{-# INLINE commaVec' #-}
commaVec' = B.intercalateVec B.comma encodeJSON
data Settings = Settings
{ fieldFmt :: String -> T.Text
, constrFmt :: String -> T.Text
}
defaultSettings :: Settings
defaultSettings = Settings T.pack T.pack
class ToValue a where
toValue :: a -> Value
default toValue :: (Generic a, GToValue (Rep a)) => a -> Value
toValue = gToValue defaultSettings . from
class GToValue f where
gToValue :: Settings -> f a -> Value
type family Field f where
Field (a :*: b) = Field a
Field (S1 (MetaSel Nothing u ss ds) f) = Value
Field (S1 (MetaSel (Just l) u ss ds) f) = (T.Text, Value)
class GWriteFields f where
gWriteFields :: Settings -> A.SmallMutableArray s (Field f) -> Int -> f a -> ST s ()
instance (ProductSize a, GWriteFields a, GWriteFields b, Field a ~ Field b) => GWriteFields (a :*: b) where
{-# INLINE gWriteFields #-}
gWriteFields s marr idx (a :*: b) = do
gWriteFields s marr idx a
gWriteFields s marr (idx + productSize (proxy# :: Proxy# a)) b
instance (GToValue f) => GWriteFields (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gWriteFields #-}
gWriteFields s marr idx (M1 x) = A.writeSmallArray marr idx (gToValue s x)
instance (GToValue f, Selector (MetaSel (Just l) u ss ds)) => GWriteFields (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gWriteFields #-}
gWriteFields s marr idx m1@(M1 x) = A.writeSmallArray marr idx ((fieldFmt s) (selName m1), gToValue s x)
instance (GToValue f, Selector (MetaSel (Just l) u ss ds)) => GToValue (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gToValue #-}
gToValue s m1@(M1 x) =
let k = fieldFmt s $ selName m1
v = gToValue s x
in Object (V.singleton (k, v))
instance GToValue f => GToValue (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gToValue #-}
gToValue s (M1 x) = gToValue s x
instance ToValue a => GToValue (K1 i a) where
{-# INLINE gToValue #-}
gToValue _ (K1 x) = toValue x
class GMergeFields f where
gMergeFields :: Proxy# f -> A.SmallMutableArray s (Field f) -> ST s Value
instance GMergeFields a => GMergeFields (a :*: b) where
{-# INLINE gMergeFields #-}
gMergeFields _ = gMergeFields (proxy# :: Proxy# a)
instance GMergeFields (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gMergeFields #-}
gMergeFields _ marr = do
arr <- A.unsafeFreezeSmallArray marr
let l = A.sizeofSmallArray arr
pure (Array (V.Vector arr 0 l))
instance GMergeFields (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gMergeFields #-}
gMergeFields _ marr = do
arr <- A.unsafeFreezeSmallArray marr
let l = A.sizeofSmallArray arr
pure (Object (V.Vector arr 0 l))
class GConstrToValue f where
gConstrToValue :: Bool -> Settings -> f a -> Value
instance GConstrToValue V1 where
{-# INLINE gConstrToValue #-}
gConstrToValue _ _ _ = error "Z.Data.JSON.Base: empty data type"
instance (GConstrToValue f, GConstrToValue g) => GConstrToValue (f :+: g) where
{-# INLINE gConstrToValue #-}
gConstrToValue _ s (L1 x) = gConstrToValue True s x
gConstrToValue _ s (R1 x) = gConstrToValue True s x
instance (Constructor c) => GConstrToValue (C1 c U1) where
{-# INLINE gConstrToValue #-}
gConstrToValue _ s (M1 _) = String . constrFmt s $ conName (undefined :: t c U1 a)
instance (Constructor c, GToValue (S1 sc f)) => GConstrToValue (C1 c (S1 sc f)) where
{-# INLINE gConstrToValue #-}
gConstrToValue False s (M1 x) = gToValue s x
gConstrToValue True s (M1 x) =
let k = constrFmt s $ conName @c undefined
v = gToValue s x
in Object (V.singleton (k, v))
instance (ProductSize (a :*: b), GWriteFields (a :*: b), GMergeFields (a :*: b), Constructor c)
=> GConstrToValue (C1 c (a :*: b)) where
{-# INLINE gConstrToValue #-}
gConstrToValue False s (M1 x) = runST (do
marr <- A.newSmallArray (productSize (proxy# :: Proxy# (a :*: b))) undefined
gWriteFields s marr 0 x
gMergeFields (proxy# :: Proxy# (a :*: b)) marr)
gConstrToValue True s (M1 x) =
let k = constrFmt s $ conName @c undefined
v = runST (do
marr <- A.newSmallArray (productSize (proxy# :: Proxy# (a :*: b))) undefined
gWriteFields s marr 0 x
gMergeFields (proxy# :: Proxy# (a :*: b)) marr)
in Object (V.singleton (k, v))
instance GConstrToValue f => GToValue (D1 c f) where
{-# INLINE gToValue #-}
gToValue s (M1 x) = gConstrToValue False s x
class EncodeJSON a where
encodeJSON :: a -> B.Builder ()
default encodeJSON :: (Generic a, GEncodeJSON (Rep a)) => a -> B.Builder ()
encodeJSON = gEncodeJSON defaultSettings . from
class GEncodeJSON f where
gEncodeJSON :: Settings -> f a -> B.Builder ()
instance (GEncodeJSON f, Selector (MetaSel (Just l) u ss ds)) => GEncodeJSON (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gEncodeJSON #-}
gEncodeJSON s m1@(M1 x) = (fieldFmt s $ selName m1) `JB.kv` gEncodeJSON s x
instance GEncodeJSON f => GEncodeJSON (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gEncodeJSON #-}
gEncodeJSON s (M1 x) = gEncodeJSON s x
instance (GEncodeJSON a, GEncodeJSON b) => GEncodeJSON (a :*: b) where
{-# INLINE gEncodeJSON #-}
gEncodeJSON s (a :*: b) = gEncodeJSON s a >> B.comma >> gEncodeJSON s b
instance EncodeJSON a => GEncodeJSON (K1 i a) where
{-# INLINE gEncodeJSON #-}
gEncodeJSON _ (K1 x) = encodeJSON x
class GAddPunctuation (f :: * -> *) where
gAddPunctuation :: Proxy# f -> B.Builder () -> B.Builder ()
instance GAddPunctuation a => GAddPunctuation (a :*: b) where
{-# INLINE gAddPunctuation #-}
gAddPunctuation _ = gAddPunctuation (proxy# :: Proxy# a)
instance GAddPunctuation (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gAddPunctuation #-}
gAddPunctuation _ b = B.square b
instance GAddPunctuation (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gAddPunctuation #-}
gAddPunctuation _ b = B.curly b
class GConstrEncodeJSON f where
gConstrEncodeJSON :: Bool -> Settings -> f a -> B.Builder ()
instance GConstrEncodeJSON V1 where
{-# INLINE gConstrEncodeJSON #-}
gConstrEncodeJSON _ _ _ = error "Z.Data.JSON.Base: empty data type"
instance (GConstrEncodeJSON f, GConstrEncodeJSON g) => GConstrEncodeJSON (f :+: g) where
{-# INLINE gConstrEncodeJSON #-}
gConstrEncodeJSON _ s (L1 x) = gConstrEncodeJSON True s x
gConstrEncodeJSON _ s (R1 x) = gConstrEncodeJSON True s x
instance (Constructor c) => GConstrEncodeJSON (C1 c U1) where
{-# INLINE gConstrEncodeJSON #-}
gConstrEncodeJSON _ s (M1 _) = B.quotes $
B.text . constrFmt s $ conName (undefined :: t c U1 a)
instance (Constructor c, GEncodeJSON (S1 (MetaSel Nothing u ss ds) f))
=> GConstrEncodeJSON (C1 c (S1 (MetaSel Nothing u ss ds) f)) where
{-# INLINE gConstrEncodeJSON #-}
gConstrEncodeJSON False s (M1 x) = gEncodeJSON s x
gConstrEncodeJSON True s (M1 x) = B.curly $ do
(constrFmt s $ conName @c undefined) `JB.kv` gEncodeJSON s x
instance (Constructor c, GEncodeJSON (S1 (MetaSel (Just l) u ss ds) f))
=> GConstrEncodeJSON (C1 c (S1 (MetaSel (Just l) u ss ds) f)) where
{-# INLINE gConstrEncodeJSON #-}
gConstrEncodeJSON False s (M1 x) = B.curly (gEncodeJSON s x)
gConstrEncodeJSON True s (M1 x) = B.curly $ do
(constrFmt s $ conName @c undefined) `JB.kv` B.curly (gEncodeJSON s x)
instance (GEncodeJSON (a :*: b), GAddPunctuation (a :*: b), Constructor c)
=> GConstrEncodeJSON (C1 c (a :*: b)) where
{-# INLINE gConstrEncodeJSON #-}
gConstrEncodeJSON False s (M1 x) = gAddPunctuation (proxy# :: Proxy# (a :*: b)) (gEncodeJSON s x)
gConstrEncodeJSON True s (M1 x) = B.curly $ do
(constrFmt s $ conName @c @_ @_ @_ undefined) `JB.kv`
gAddPunctuation (proxy# :: Proxy# (a :*: b)) (gEncodeJSON s x)
instance GConstrEncodeJSON f => GEncodeJSON (D1 c f) where
{-# INLINE gEncodeJSON #-}
gEncodeJSON s (M1 x) = gConstrEncodeJSON False s x
class FromValue a where
fromValue :: Value -> Converter a
default fromValue :: (Generic a, GFromValue (Rep a)) => Value -> Converter a
fromValue v = to <$> gFromValue defaultSettings v
class GFromValue f where
gFromValue :: Settings -> Value -> Converter (f a)
type family LookupTable f where
LookupTable (a :*: b) = LookupTable a
LookupTable (S1 (MetaSel Nothing u ss ds) f) = V.Vector Value
LookupTable (S1 (MetaSel (Just l) u ss ds) f) = FM.FlatMap T.Text Value
class GFromFields f where
gFromFields :: Settings -> LookupTable f -> Int -> Converter (f a)
instance (ProductSize a, GFromFields a, GFromFields b, LookupTable a ~ LookupTable b)
=> GFromFields (a :*: b) where
{-# INLINE gFromFields #-}
gFromFields s v idx = do
a <- gFromFields s v idx
b <- gFromFields s v (idx + productSize (proxy# :: Proxy# a))
pure (a :*: b)
instance (GFromValue f) => GFromFields (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gFromFields #-}
gFromFields s v idx = do
v' <- V.unsafeIndexM v idx
M1 <$> gFromValue s v' <?> Index idx
instance (GFromValue f, Selector (MetaSel (Just l) u ss ds)) => GFromFields (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gFromFields #-}
gFromFields s v _ = do
case FM.lookup fn v of
Just v' -> M1 <$> gFromValue s v' <?> Key fn
_ -> fail' ("Z.Data.JSON.Base: missing field " <> fn)
where
fn = (fieldFmt s) (selName (undefined :: S1 (MetaSel (Just l) u ss ds) f a))
instance GFromValue f => GFromValue (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gFromValue #-}
gFromValue s x = M1 <$> gFromValue s x
instance (GFromValue f, Selector (MetaSel (Just l) u ss ds)) => GFromValue (S1 (MetaSel (Just l) u ss ds) f) where
{-# INLINE gFromValue #-}
gFromValue s (Object v) = do
case FM.lookup fn (FM.packVectorR v) of
Just v' -> M1 <$> gFromValue s v' <?> Key fn
_ -> fail' ("Z.Data.JSON.Base: missing field " <> fn)
where fn = (fieldFmt s) (selName (undefined :: S1 (MetaSel (Just l) u ss ds) f a))
gFromValue s v = typeMismatch ("field " <> fn) "Object" v <?> Key fn
where fn = (fieldFmt s) (selName (undefined :: S1 (MetaSel (Just l) u ss ds) f a))
instance FromValue a => GFromValue (K1 i a) where
{-# INLINE gFromValue #-}
gFromValue _ x = K1 <$> fromValue x
class GBuildLookup f where
gBuildLookup :: Proxy# f -> Int -> T.Text -> Value -> Converter (LookupTable f)
instance (GBuildLookup a, GBuildLookup b) => GBuildLookup (a :*: b) where
{-# INLINE gBuildLookup #-}
gBuildLookup _ siz = gBuildLookup (proxy# :: Proxy# a) siz
instance GBuildLookup (S1 (MetaSel Nothing u ss ds) f) where
{-# INLINE gBuildLookup #-}
gBuildLookup _ siz name (Array v)
| siz' /= siz = fail' . T.buildText $ do
"converting "
T.text name
" failed, product size mismatch, expected "
T.int siz
", get"
T.int siz'
| otherwise = pure v
where siz' = V.length v
gBuildLookup _ _ name x = typeMismatch name "Array" x
instance GBuildLookup (S1 ((MetaSel (Just l) u ss ds)) f) where
{-# INLINE gBuildLookup #-}
gBuildLookup _ siz name (Object v)
| siz' /= siz = fail' . T.buildText $ do
"converting "
T.text name
" failed, product size mismatch, expected "
T.int siz
", get"
T.int siz'
| otherwise = pure m
where siz' = FM.size m
m = FM.packVectorR v
gBuildLookup _ _ name x = typeMismatch name "Object" x
class GConstrFromValue f where
gConstrFromValue :: Bool -> Settings -> Value -> Converter (f a)
instance GConstrFromValue V1 where
{-# INLINE gConstrFromValue #-}
gConstrFromValue _ _ _ = error "Z.Data.JSON.Base: empty data type"
instance (GConstrFromValue f, GConstrFromValue g) => GConstrFromValue (f :+: g) where
{-# INLINE gConstrFromValue #-}
gConstrFromValue _ s x = (L1 <$> gConstrFromValue True s x) <|> (R1 <$> gConstrFromValue True s x)
instance (Constructor c) => GConstrFromValue (C1 c U1) where
{-# INLINE gConstrFromValue #-}
gConstrFromValue _ s (String x)
| cn == x = pure (M1 U1)
| otherwise = fail' . T.concat $ ["converting ", cn', "failed, unknown constructor name ", x]
where cn = constrFmt s $ conName (undefined :: t c U1 a)
cn' = T.pack $ conName (undefined :: t c U1 a)
gConstrFromValue _ _ v = typeMismatch cn' "String" v
where cn' = T.pack $ conName (undefined :: t c U1 a)
instance (Constructor c, GFromValue (S1 sc f)) => GConstrFromValue (C1 c (S1 sc f)) where
{-# INLINE gConstrFromValue #-}
gConstrFromValue False s x = M1 <$> gFromValue s x
gConstrFromValue True s x = case x of
Object v -> case V.indexM v 0 of
Just (k, v') | k == cn -> M1 <$> gFromValue s v' <?> Key cn
_ -> fail' .T.concat $ ["converting ", cn', " failed, constructor not found"]
_ -> typeMismatch cn' "Object" x
where cn = constrFmt s $ conName @c undefined
cn' = T.pack $ conName @c undefined
instance (ProductSize (a :*: b), GFromFields (a :*: b), GBuildLookup (a :*: b), Constructor c)
=> GConstrFromValue (C1 c (a :*: b)) where
{-# INLINE gConstrFromValue #-}
gConstrFromValue False s x = do
t <- gBuildLookup p (productSize p) cn' x
M1 <$> gFromFields s t 0
where cn' = T.pack $ conName @c undefined
p = proxy# :: Proxy# (a :*: b)
gConstrFromValue True s x = case x of
Object v -> case V.indexM v 0 of
Just (k, v') | k == cn -> do t <- gBuildLookup p (productSize p) cn' v'
M1 <$> gFromFields s t 0
_ -> fail' .T.concat $ ["converting ", cn', " failed, constructor not found"]
_ -> typeMismatch cn' "Object" x
where cn = constrFmt s $ conName @c undefined
cn' = T.pack $ conName @c undefined
p = proxy# :: Proxy# (a :*: b)
instance GConstrFromValue f => GFromValue (D1 c f) where
{-# INLINE gFromValue #-}
gFromValue s x = M1 <$> gConstrFromValue False s x
instance FromValue (Proxy a) where {{-# INLINE fromValue #-}; fromValue = fromNull "Proxy" Proxy;}
instance ToValue (Proxy a) where {{-# INLINE toValue #-}; toValue _ = Null;}
instance EncodeJSON (Proxy a) where {{-# INLINE encodeJSON #-}; encodeJSON _ = "null";}
instance FromValue Value where {{-# INLINE fromValue #-}; fromValue = pure;}
instance ToValue Value where { {-# INLINE toValue #-}; toValue = id; }
instance EncodeJSON Value where { {-# INLINE encodeJSON #-}; encodeJSON = JB.value; }
instance FromValue T.Text where {{-# INLINE fromValue #-}; fromValue = withText "Text" pure;}
instance ToValue T.Text where {{-# INLINE toValue #-}; toValue = String;}
instance EncodeJSON T.Text where {{-# INLINE encodeJSON #-}; encodeJSON = JB.string;}
instance FromValue Scientific where {{-# INLINE fromValue #-}; fromValue = withScientific "Scientific" pure;}
instance ToValue Scientific where {{-# INLINE toValue #-}; toValue = Number;}
instance EncodeJSON Scientific where {{-# INLINE encodeJSON #-}; encodeJSON = B.scientific;}
instance FromValue a => FromValue (FM.FlatMap T.Text a) where
{-# INLINE fromValue #-}
fromValue = withFlatMapR "Z.Data.Vector.FlatMap.FlatMap"
(FM.traverseWithKey $ \ k v -> fromValue v <?> Key k)
instance ToValue a => ToValue (FM.FlatMap T.Text a) where
{-# INLINE toValue #-}
toValue = Object . FM.sortedKeyValues . FM.map' toValue
instance EncodeJSON a => EncodeJSON (FM.FlatMap T.Text a) where
{-# INLINE encodeJSON #-}
encodeJSON = JB.object' encodeJSON . FM.sortedKeyValues
instance (Ord a, FromValue a) => FromValue (FS.FlatSet a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Vector.FlatSet.FlatSet" $ \ vs ->
FS.packRN (V.length vs) <$>
(zipWithM (\ k v -> fromValue v <?> Index k) [0..] (V.unpack vs))
instance ToValue a => ToValue (FS.FlatSet a) where
{-# INLINE toValue #-}
toValue = Array . V.map' toValue . FS.sortedValues
instance EncodeJSON a => EncodeJSON (FS.FlatSet a) where
{-# INLINE encodeJSON #-}
encodeJSON = JB.array' encodeJSON . FS.sortedValues
instance FromValue a => FromValue (HM.HashMap T.Text a) where
{-# INLINE fromValue #-}
fromValue = withHashMapR "Data.HashMap.HashMap"
(HM.traverseWithKey $ \ k v -> fromValue v <?> Key k)
instance ToValue a => ToValue (HM.HashMap T.Text a) where
{-# INLINE toValue #-}
toValue = Object . V.pack . HM.toList . HM.map toValue
instance EncodeJSON a => EncodeJSON (HM.HashMap T.Text a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.curly . B.intercalateList B.comma (\ (k, v) -> k `JB.kv'` encodeJSON v) . HM.toList
instance FromValue a => FromValue (FIM.FlatIntMap a) where
{-# INLINE fromValue #-}
fromValue = withFlatMapR "Z.Data.Vector.FlatIntMap.FlatIntMap" $ \ m ->
let kvs = FM.sortedKeyValues m
in FIM.packVectorR <$> (forM kvs $ \ (k, v) -> do
case P.parse_ P.int (T.getUTF8Bytes k) of
Right k' -> do
v' <- fromValue v <?> Key k
return (V.IPair k' v')
_ -> fail' ("converting Z.Data.Vector.FlatIntMap.FlatIntMap failed, unexpected key " <> k))
instance ToValue a => ToValue (FIM.FlatIntMap a) where
{-# INLINE toValue #-}
toValue = Object . V.map' toKV . FIM.sortedKeyValues
where toKV (V.IPair i x) = let !k = T.buildText (T.int i)
!v = toValue x
in (k, v)
instance EncodeJSON a => EncodeJSON (FIM.FlatIntMap a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.curly . B.intercalateVec B.comma (\ (V.IPair i x) -> do
B.quotes (B.int i)
B.colon
encodeJSON x) . FIM.sortedKeyValues
instance FromValue FIS.FlatIntSet where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Vector.FlatIntSet.FlatIntSet" $ \ vs ->
FIS.packRN (V.length vs) <$> zipWithM (\ k v -> fromValue v <?> Index k) [0..] (V.unpack vs)
instance ToValue FIS.FlatIntSet where
{-# INLINE toValue #-}
toValue = toValue . FIS.sortedValues
instance EncodeJSON FIS.FlatIntSet where
{-# INLINE encodeJSON #-}
encodeJSON = encodeJSON . FIS.sortedValues
instance FromValue a => FromValue (A.Array a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Array.Array"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k)
instance ToValue a => ToValue (A.Array a) where
{-# INLINE toValue #-}
toValue = Array . V.map toValue
instance EncodeJSON a => EncodeJSON (A.Array a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaVec'
instance FromValue a => FromValue (A.SmallArray a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Array.SmallArray"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k)
instance ToValue a => ToValue (A.SmallArray a) where
{-# INLINE toValue #-}
toValue = Array . V.map toValue
instance EncodeJSON a => EncodeJSON (A.SmallArray a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaVec'
instance (Prim a, FromValue a) => FromValue (A.PrimArray a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Array.PrimArray"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k)
instance (Prim a, ToValue a) => ToValue (A.PrimArray a) where
{-# INLINE toValue #-}
toValue = Array . V.map toValue
instance (Prim a, EncodeJSON a) => EncodeJSON (A.PrimArray a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaVec'
instance FromValue A.ByteArray where
{-# INLINE fromValue #-}
fromValue value = do
(A.PrimArray ba# :: A.PrimArray Word8) <-
withArray "Data.Primitive.ByteArray"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k) value
return (A.ByteArray ba#)
instance ToValue A.ByteArray where
{-# INLINE toValue #-}
toValue (A.ByteArray ba#) =
Array (V.map toValue (A.PrimArray ba# :: A.PrimArray Word8))
instance EncodeJSON A.ByteArray where
{-# INLINE encodeJSON #-}
encodeJSON (A.ByteArray ba#) =
B.square (commaVec' (A.PrimArray ba# :: A.PrimArray Word8))
instance (A.PrimUnlifted a, FromValue a) => FromValue (A.UnliftedArray a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Array.UnliftedArray"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k)
instance (A.PrimUnlifted a, ToValue a) => ToValue (A.UnliftedArray a) where
{-# INLINE toValue #-}
toValue = Array . V.map toValue
instance (A.PrimUnlifted a, EncodeJSON a) => EncodeJSON (A.UnliftedArray a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaVec'
instance FromValue a => FromValue (V.Vector a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Vector.Vector"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k)
instance ToValue a => ToValue (V.Vector a) where
{-# INLINE toValue #-}
toValue = Array . V.map toValue
instance EncodeJSON a => EncodeJSON (V.Vector a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaVec'
instance (Prim a, FromValue a) => FromValue (V.PrimVector a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Vector.PrimVector"
(V.traverseWithIndex $ \ k v -> fromValue v <?> Index k)
instance (Prim a, ToValue a) => ToValue (V.PrimVector a) where
{-# INLINE toValue #-}
toValue = Array . V.map toValue
instance (Prim a, EncodeJSON a) => EncodeJSON (V.PrimVector a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaVec'
instance (Eq a, Hashable a, FromValue a) => FromValue (HS.HashSet a) where
{-# INLINE fromValue #-}
fromValue = withArray "Z.Data.Vector.FlatSet.FlatSet" $ \ vs ->
HS.fromList <$>
(zipWithM (\ k v -> fromValue v <?> Index k) [0..] (V.unpack vs))
instance (ToValue a) => ToValue (HS.HashSet a) where
{-# INLINE toValue #-}
toValue = toValue . HS.toList
instance (EncodeJSON a) => EncodeJSON (HS.HashSet a) where
{-# INLINE encodeJSON #-}
encodeJSON = encodeJSON . HS.toList
instance FromValue a => FromValue [a] where
{-# INLINE fromValue #-}
fromValue = withArray "[a]" $ \ vs ->
zipWithM (\ k v -> fromValue v <?> Index k) [0..] (V.unpack vs)
instance ToValue a => ToValue [a] where
{-# INLINE toValue #-}
toValue = Array . V.pack . map toValue
instance EncodeJSON a => EncodeJSON [a] where
{-# INLINE encodeJSON #-}
encodeJSON = B.square . commaList'
instance FromValue a => FromValue (NonEmpty a) where
{-# INLINE fromValue #-}
fromValue = withArray "NonEmpty" $ \ vs -> do
l <- zipWithM (\ k v -> fromValue v <?> Index k) [0..] (V.unpack vs)
case l of (x:xs) -> pure (x :| xs)
_ -> fail' "unexpected empty array"
instance (ToValue a) => ToValue (NonEmpty a) where
{-# INLINE toValue #-}
toValue = toValue . NonEmpty.toList
instance (EncodeJSON a) => EncodeJSON (NonEmpty a) where
{-# INLINE encodeJSON #-}
encodeJSON = encodeJSON . NonEmpty.toList
instance FromValue Bool where {{-# INLINE fromValue #-}; fromValue = withBool "Bool" pure;}
instance ToValue Bool where {{-# INLINE toValue #-}; toValue = Bool; }
instance EncodeJSON Bool where {{-# INLINE encodeJSON #-}; encodeJSON True = "true"; encodeJSON _ = "false";}
instance FromValue Char where
{-# INLINE fromValue #-}
fromValue = withText "Char" $ \ t ->
if (T.length t == 1)
then pure (T.head t)
else fail' (T.concat ["converting Char failed, expected a string of length 1"])
instance ToValue Char where
{-# INLINE toValue #-}
toValue = String . T.singleton
instance EncodeJSON Char where
{-# INLINE encodeJSON #-}
encodeJSON '\b' = "\"\\b\""
encodeJSON '\f' = "\"\\f\""
encodeJSON '\n' = "\"\\n\""
encodeJSON '\r' = "\"\\r\""
encodeJSON '\t' = "\"\\t\""
encodeJSON '\"' = "\"\\\"\""
encodeJSON '\\' = "\"\\\\\""
encodeJSON '/' = "\"\\/\""
encodeJSON c | c <= '\US' = "\"\\u00" >> B.hex (fromIntegral (ord c) :: Word8) >> B.char8 '\"'
| otherwise = B.quotes (B.charUTF8 c)
instance FromValue Double where {{-# INLINE fromValue #-}; fromValue = withRealFloat "Double" pure;}
instance FromValue Float where {{-# INLINE fromValue #-}; fromValue = withRealFloat "Double" pure;}
instance ToValue Float where {{-# INLINE toValue #-}; toValue = Number . P.floatToScientific;}
instance ToValue Double where {{-# INLINE toValue #-}; toValue = Number . P.doubleToScientific;}
instance EncodeJSON Float where {{-# INLINE encodeJSON #-}; encodeJSON = B.float;}
instance EncodeJSON Double where {{-# INLINE encodeJSON #-}; encodeJSON = B.double;}
instance FromValue Int where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Int" pure;}
instance FromValue Int8 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Int8" pure;}
instance FromValue Int16 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Int16" pure;}
instance FromValue Int32 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Int32" pure;}
instance FromValue Int64 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Int64" pure;}
instance FromValue Word where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Word" pure;}
instance FromValue Word8 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Word8" pure;}
instance FromValue Word16 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Word16" pure;}
instance FromValue Word32 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Word32" pure;}
instance FromValue Word64 where {{-# INLINE fromValue #-}; fromValue = withBoundedIntegral "Word64" pure;}
instance ToValue Int where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Int8 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Int16 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Int32 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Int64 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Word where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Word8 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Word16 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Word32 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance ToValue Word64 where {{-# INLINE toValue #-}; toValue = Number . fromIntegral;}
instance EncodeJSON Int where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Int8 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Int16 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Int32 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Int64 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Word where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Word8 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Word16 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Word32 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance EncodeJSON Word64 where {{-# INLINE encodeJSON #-}; encodeJSON = B.int;}
instance FromValue Integer where
{-# INLINE fromValue #-}
fromValue = withBoundedScientific "Integer" $ \ n ->
case Scientific.floatingOrInteger n :: Either Double Integer of
Right x -> pure x
Left _ -> fail' . T.buildText $ do
"converting Integer failed, unexpected floating number "
T.scientific n
instance ToValue Integer where
{-# INLINE toValue #-}
toValue = Number . fromIntegral
instance EncodeJSON Integer where
{-# INLINE encodeJSON #-}
encodeJSON = B.integer
instance FromValue Natural where
{-# INLINE fromValue #-}
fromValue = withBoundedScientific "Natural" $ \ n ->
if n < 0
then fail' . T.buildText $ do
"converting Natural failed, unexpected negative number "
T.scientific n
else case Scientific.floatingOrInteger n :: Either Double Natural of
Right x -> pure x
Left _ -> fail' . T.buildText $ do
"converting Natural failed, unexpected floating number "
T.scientific n
instance ToValue Natural where
{-# INLINE toValue #-}
toValue = Number . fromIntegral
instance EncodeJSON Natural where
{-# INLINE encodeJSON #-}
encodeJSON = B.integer . fromIntegral
instance FromValue Ordering where
fromValue = withText "Ordering" $ \ s ->
case s of
"LT" -> pure LT
"EQ" -> pure EQ
"GT" -> pure GT
_ -> fail' . T.concat $ ["converting Ordering failed, unexpected ",
s, " expected \"LT\", \"EQ\", or \"GT\""]
instance ToValue Ordering where
{-# INLINE toValue #-}
toValue LT = String "LT"
toValue EQ = String "EQ"
toValue GT = String "GT"
instance EncodeJSON Ordering where
{-# INLINE encodeJSON #-}
encodeJSON LT = "LT"
encodeJSON EQ = "EQ"
encodeJSON GT = "GT"
instance FromValue () where
{-# INLINE fromValue #-}
fromValue = withArray "()" $ \ v ->
if V.null v
then pure ()
else fail' "converting () failed, expected an empty array"
instance ToValue () where
{-# INLINE toValue #-}
toValue () = Array V.empty
instance EncodeJSON () where
{-# INLINE encodeJSON #-}
encodeJSON () = "[]"
instance FromValue ExitCode where
{-# INLINE fromValue #-}
fromValue (String "ExitSuccess") = return ExitSuccess
fromValue (Number x) =
case toBoundedInteger x of
Just i -> return (ExitFailure i)
_ -> fail' . T.buildText $ do
"converting ExitCode failed, value is either floating or will cause over or underflow: "
T.scientific x
fromValue _ = fail' "converting ExitCode failed, expected a string or number"
instance ToValue ExitCode where
{-# INLINE toValue #-}
toValue ExitSuccess = String "ExitSuccess"
toValue (ExitFailure n) = Number (fromIntegral n)
instance EncodeJSON ExitCode where
{-# INLINE encodeJSON #-}
encodeJSON ExitSuccess = "ExitSuccess"
encodeJSON (ExitFailure n) = B.int n
instance FromValue Version where
{-# INLINE fromValue #-}
fromValue = withText "Version" (go . readP_to_S parseVersion . T.unpack)
where
go [(v,[])] = pure v
go (_ : xs) = go xs
go _ = fail "converting Version failed"
instance ToValue Version where
{-# INLINE toValue #-}
toValue = String . T.pack . show
instance EncodeJSON Version where
{-# INLINE encodeJSON #-}
encodeJSON = B.string7 . show
instance FromValue a => FromValue (Maybe a) where
{-# INLINE fromValue #-}
fromValue Null = pure Nothing
fromValue v = Just <$> fromValue v
instance ToValue a => ToValue (Maybe a) where
{-# INLINE toValue #-}
toValue Nothing = Null
toValue (Just x) = toValue x
instance EncodeJSON a => EncodeJSON (Maybe a) where
{-# INLINE encodeJSON #-}
encodeJSON Nothing = "null"
encodeJSON (Just x) = encodeJSON x
instance (FromValue a, Integral a) => FromValue (Ratio a) where
{-# INLINE fromValue #-}
fromValue = withFlatMapR "Rational" $ \obj -> do
n <- obj .: "numerator"
d <- obj .: "denominator"
if d == 0
then fail' "Ratio denominator was 0"
else pure (n % d)
instance (ToValue a, Integral a) => ToValue (Ratio a) where
{-# INLINE toValue #-}
toValue x = Object (V.pack [("numerator", n), ("denominator", d)])
where !n = toValue (numerator x)
!d = toValue (denominator x)
instance (EncodeJSON a, Integral a) => EncodeJSON (Ratio a) where
{-# INLINE encodeJSON #-}
encodeJSON x =
B.curly $ ("\"numerator\"" >> B.colon >> encodeJSON (numerator x))
>> B.comma >> ("\"denominator\"" >> B.colon >> encodeJSON (denominator x))
instance HasResolution a => FromValue (Fixed a) where
{-# INLINE fromValue #-}
fromValue = withBoundedScientific "Fixed" (pure . realToFrac)
instance HasResolution a => ToValue (Fixed a) where
{-# INLINE toValue #-}
toValue = Number . realToFrac
instance HasResolution a => EncodeJSON (Fixed a) where
{-# INLINE encodeJSON #-}
encodeJSON = B.scientific . realToFrac
deriving newtype instance FromValue (f (g a)) => FromValue (Compose f g a)
deriving newtype instance FromValue a => FromValue (Semigroup.Min a)
deriving newtype instance FromValue a => FromValue (Semigroup.Max a)
deriving newtype instance FromValue a => FromValue (Semigroup.First a)
deriving newtype instance FromValue a => FromValue (Semigroup.Last a)
deriving newtype instance FromValue a => FromValue (Semigroup.WrappedMonoid a)
deriving newtype instance FromValue a => FromValue (Semigroup.Dual a)
deriving newtype instance FromValue a => FromValue (Monoid.First a)
deriving newtype instance FromValue a => FromValue (Monoid.Last a)
deriving newtype instance FromValue a => FromValue (Identity a)
deriving newtype instance FromValue a => FromValue (Const a b)
deriving newtype instance FromValue b => FromValue (Tagged a b)
deriving newtype instance ToValue (f (g a)) => ToValue (Compose f g a)
deriving newtype instance ToValue a => ToValue (Semigroup.Min a)
deriving newtype instance ToValue a => ToValue (Semigroup.Max a)
deriving newtype instance ToValue a => ToValue (Semigroup.First a)
deriving newtype instance ToValue a => ToValue (Semigroup.Last a)
deriving newtype instance ToValue a => ToValue (Semigroup.WrappedMonoid a)
deriving newtype instance ToValue a => ToValue (Semigroup.Dual a)
deriving newtype instance ToValue a => ToValue (Monoid.First a)
deriving newtype instance ToValue a => ToValue (Monoid.Last a)
deriving newtype instance ToValue a => ToValue (Identity a)
deriving newtype instance ToValue a => ToValue (Const a b)
deriving newtype instance ToValue b => ToValue (Tagged a b)
deriving newtype instance EncodeJSON (f (g a)) => EncodeJSON (Compose f g a)
deriving newtype instance EncodeJSON a => EncodeJSON (Semigroup.Min a)
deriving newtype instance EncodeJSON a => EncodeJSON (Semigroup.Max a)
deriving newtype instance EncodeJSON a => EncodeJSON (Semigroup.First a)
deriving newtype instance EncodeJSON a => EncodeJSON (Semigroup.Last a)
deriving newtype instance EncodeJSON a => EncodeJSON (Semigroup.WrappedMonoid a)
deriving newtype instance EncodeJSON a => EncodeJSON (Semigroup.Dual a)
deriving newtype instance EncodeJSON a => EncodeJSON (Monoid.First a)
deriving newtype instance EncodeJSON a => EncodeJSON (Monoid.Last a)
deriving newtype instance EncodeJSON a => EncodeJSON (Identity a)
deriving newtype instance EncodeJSON a => EncodeJSON (Const a b)
deriving newtype instance EncodeJSON b => EncodeJSON (Tagged a b)
deriving newtype instance FromValue CChar
deriving newtype instance FromValue CSChar
deriving newtype instance FromValue CUChar
deriving newtype instance FromValue CShort
deriving newtype instance FromValue CUShort
deriving newtype instance FromValue CInt
deriving newtype instance FromValue CUInt
deriving newtype instance FromValue CLong
deriving newtype instance FromValue CULong
deriving newtype instance FromValue CPtrdiff
deriving newtype instance FromValue CSize
deriving newtype instance FromValue CWchar
deriving newtype instance FromValue CSigAtomic
deriving newtype instance FromValue CLLong
deriving newtype instance FromValue CULLong
deriving newtype instance FromValue CBool
deriving newtype instance FromValue CIntPtr
deriving newtype instance FromValue CUIntPtr
deriving newtype instance FromValue CIntMax
deriving newtype instance FromValue CUIntMax
deriving newtype instance FromValue CClock
deriving newtype instance FromValue CTime
deriving newtype instance FromValue CUSeconds
deriving newtype instance FromValue CSUSeconds
deriving newtype instance FromValue CFloat
deriving newtype instance FromValue CDouble
deriving newtype instance ToValue CChar
deriving newtype instance ToValue CSChar
deriving newtype instance ToValue CUChar
deriving newtype instance ToValue CShort
deriving newtype instance ToValue CUShort
deriving newtype instance ToValue CInt
deriving newtype instance ToValue CUInt
deriving newtype instance ToValue CLong
deriving newtype instance ToValue CULong
deriving newtype instance ToValue CPtrdiff
deriving newtype instance ToValue CSize
deriving newtype instance ToValue CWchar
deriving newtype instance ToValue CSigAtomic
deriving newtype instance ToValue CLLong
deriving newtype instance ToValue CULLong
deriving newtype instance ToValue CBool
deriving newtype instance ToValue CIntPtr
deriving newtype instance ToValue CUIntPtr
deriving newtype instance ToValue CIntMax
deriving newtype instance ToValue CUIntMax
deriving newtype instance ToValue CClock
deriving newtype instance ToValue CTime
deriving newtype instance ToValue CUSeconds
deriving newtype instance ToValue CSUSeconds
deriving newtype instance ToValue CFloat
deriving newtype instance ToValue CDouble
deriving newtype instance EncodeJSON CChar
deriving newtype instance EncodeJSON CSChar
deriving newtype instance EncodeJSON CUChar
deriving newtype instance EncodeJSON CShort
deriving newtype instance EncodeJSON CUShort
deriving newtype instance EncodeJSON CInt
deriving newtype instance EncodeJSON CUInt
deriving newtype instance EncodeJSON CLong
deriving newtype instance EncodeJSON CULong
deriving newtype instance EncodeJSON CPtrdiff
deriving newtype instance EncodeJSON CSize
deriving newtype instance EncodeJSON CWchar
deriving newtype instance EncodeJSON CSigAtomic
deriving newtype instance EncodeJSON CLLong
deriving newtype instance EncodeJSON CULLong
deriving newtype instance EncodeJSON CBool
deriving newtype instance EncodeJSON CIntPtr
deriving newtype instance EncodeJSON CUIntPtr
deriving newtype instance EncodeJSON CIntMax
deriving newtype instance EncodeJSON CUIntMax
deriving newtype instance EncodeJSON CClock
deriving newtype instance EncodeJSON CTime
deriving newtype instance EncodeJSON CUSeconds
deriving newtype instance EncodeJSON CSUSeconds
deriving newtype instance EncodeJSON CFloat
deriving newtype instance EncodeJSON CDouble
deriving anyclass instance (FromValue (f a), FromValue (g a), FromValue a) => FromValue (Sum f g a)
deriving anyclass instance (FromValue a, FromValue b) => FromValue (Either a b)
deriving anyclass instance (FromValue (f a), FromValue (g a)) => FromValue (Product f g a)
deriving anyclass instance (FromValue a, FromValue b) => FromValue (a, b)
deriving anyclass instance (FromValue a, FromValue b, FromValue c) => FromValue (a, b, c)
deriving anyclass instance (FromValue a, FromValue b, FromValue c, FromValue d) => FromValue (a, b, c, d)
deriving anyclass instance (FromValue a, FromValue b, FromValue c, FromValue d, FromValue e) => FromValue (a, b, c, d, e)
deriving anyclass instance (FromValue a, FromValue b, FromValue c, FromValue d, FromValue e, FromValue f) => FromValue (a, b, c, d, e, f)
deriving anyclass instance (FromValue a, FromValue b, FromValue c, FromValue d, FromValue e, FromValue f, FromValue g) => FromValue (a, b, c, d, e, f, g)
deriving anyclass instance (ToValue (f a), ToValue (g a), ToValue a) => ToValue (Sum f g a)
deriving anyclass instance (ToValue a, ToValue b) => ToValue (Either a b)
deriving anyclass instance (ToValue (f a), ToValue (g a)) => ToValue (Product f g a)
deriving anyclass instance (ToValue a, ToValue b) => ToValue (a, b)
deriving anyclass instance (ToValue a, ToValue b, ToValue c) => ToValue (a, b, c)
deriving anyclass instance (ToValue a, ToValue b, ToValue c, ToValue d) => ToValue (a, b, c, d)
deriving anyclass instance (ToValue a, ToValue b, ToValue c, ToValue d, ToValue e) => ToValue (a, b, c, d, e)
deriving anyclass instance (ToValue a, ToValue b, ToValue c, ToValue d, ToValue e, ToValue f) => ToValue (a, b, c, d, e, f)
deriving anyclass instance (ToValue a, ToValue b, ToValue c, ToValue d, ToValue e, ToValue f, ToValue g) => ToValue (a, b, c, d, e, f, g)
deriving anyclass instance (EncodeJSON (f a), EncodeJSON (g a), EncodeJSON a) => EncodeJSON (Sum f g a)
deriving anyclass instance (EncodeJSON a, EncodeJSON b) => EncodeJSON (Either a b)
deriving anyclass instance (EncodeJSON (f a), EncodeJSON (g a)) => EncodeJSON (Product f g a)
deriving anyclass instance (EncodeJSON a, EncodeJSON b) => EncodeJSON (a, b)
deriving anyclass instance (EncodeJSON a, EncodeJSON b, EncodeJSON c) => EncodeJSON (a, b, c)
deriving anyclass instance (EncodeJSON a, EncodeJSON b, EncodeJSON c, EncodeJSON d) => EncodeJSON (a, b, c, d)
deriving anyclass instance (EncodeJSON a, EncodeJSON b, EncodeJSON c, EncodeJSON d, EncodeJSON e) => EncodeJSON (a, b, c, d, e)
deriving anyclass instance (EncodeJSON a, EncodeJSON b, EncodeJSON c, EncodeJSON d, EncodeJSON e, EncodeJSON f) => EncodeJSON (a, b, c, d, e, f)
deriving anyclass instance (EncodeJSON a, EncodeJSON b, EncodeJSON c, EncodeJSON d, EncodeJSON e, EncodeJSON f, EncodeJSON g) => EncodeJSON (a, b, c, d, e, f, g)