{-# LANGUAGE CPP        #-}
{-# LANGUAGE LambdaCase #-}

-- |
-- Module      : Data.Aeson.Cominators.Decode
-- Copyright   : (c) Marek Fajkus
-- License     : BSD3
--
-- Maintainer  : marek.faj@gmail.com
--
-- Aeson decoding API is closed over the type class 'FromJSON'.
-- Because of this there is one to one mapping between JSON
-- format and data decoded from it (decoding is closed over types).
-- While this is handy in many situations, in others it forces
-- users of Aeson library to define proxy types and
-- data wrappers just for sake of implementing multiple instances
-- of 'FromJSON' class.
-- This module provides value level 'Decoder' which can be used
-- instead of instance implementation to define any number of JSON
-- decoders for the same data type.
--
module Data.Aeson.Combinators.Decode (
  -- * Example Usage
  -- $usage

  -- ** Applicative "Elm Style" Decoders
  -- $applicative
    Decoder(..)
  , auto
-- * Decoding Containers
-- *** Maybe
  , nullable
-- *** Sequences
  , list, vector
-- *** Hashmap
  , hashMapLazy, hashMapStrict
-- *** Map
  , mapLazy, mapStrict
-- * Combinators
  , jsonNull
-- *** Objects
  , key
  , at
-- *** Arrays
  , index
  , indexes
-- *** Path
-- $jsonpath
  , element
  , path
-- *** Dealing With Failure
  , maybe
  , either
  , oneOf
-- * Decoding Primitive Values
-- *** Void, Unit, Bool
  , void
  , unit, bool
-- *** Integers (and Natural)
  , int, integer, int8, int16, int32, int64
  , word, word8, word16, word32, word64
#if (MIN_VERSION_base(4,8,0))
  , natural
#endif
-- *** Real Numbers
  , float, double
  , scientific
-- *** Strings
  , char, text, string
  , uuid, version
-- * Time
  , zonedTime, localTime, timeOfDay
  , utcTime
  , day
#if (MIN_VERSION_time_compat(1,9,2))
  , dayOfWeek
#endif
-- * Decoding ByteStrings
-- $decoding
-- *** Decoding From Byte Strings
  , decode, decode'
  , eitherDecode, eitherDecode'
  , decodeStrict, decodeStrict'
  , eitherDecodeStrict, eitherDecodeStrict'
-- *** Decoding Files
  , decodeFileStrict, decodeFileStrict'
  , eitherDecodeFileStrict, eitherDecodeFileStrict'
-- * Parsing (Running Decoders)
  , parseMaybe
  , parseEither
  ) where

import           Prelude                    hiding (either, fail, maybe)
import qualified Prelude                    (either)

import           Control.Applicative
import           Control.Monad              hiding (void)
import           Control.Monad.Fail         (MonadFail (..))
import qualified Control.Monad.Fail         as Fail

import           Data.Aeson.Internal        (JSONPath, JSONPathElement (..))
import qualified Data.Aeson.Internal        as AI
import qualified Data.Aeson.Parser          as Parser
import qualified Data.Aeson.Parser.Internal as ParserI
import           Data.Aeson.Types           hiding (parseEither, parseMaybe)
import qualified Data.Aeson.Types           as ATypes

import qualified Data.ByteString            as B
import qualified Data.ByteString.Lazy       as LB
import           Data.List.NonEmpty         (NonEmpty (..))
import           Data.Text                  (Text)
import qualified Data.Vector                as Vector

-- Data imports
import           Data.Int                   (Int16, Int32, Int64, Int8)
import           Data.Time.Calendar         (Day)
#if (MIN_VERSION_time_compat(1,9,2))
import           Data.Time.Calendar.Compat  (DayOfWeek)
#endif
import           Data.Time.Clock            (UTCTime)
import           Data.Time.LocalTime        (LocalTime, TimeOfDay, ZonedTime)
import           Data.UUID.Types            (UUID)
import           Data.Vector                (Vector, (!?))
import           Data.Version               (Version)
import           Data.Void                  (Void)
import           Data.Word                  (Word, Word16, Word32, Word64,
                                             Word8)
#if (MIN_VERSION_base(4,8,0))
import           GHC.Natural                (Natural)
#endif
import qualified Data.HashMap.Lazy          as HL
import qualified Data.HashMap.Strict        as HS
import qualified Data.Map.Lazy              as ML
import qualified Data.Map.Strict            as MS
import           Data.Scientific            (Scientific)
import           Data.Traversable           (traverse)


-- $usage
-- Combinators and type classes can be used together.
--
-- __Decode type nested in json__
--
-- >>> :set -XOverloadedStrings
-- >>> :set -XDeriveGeneric
--
-- > import Data.Text
-- > import Data.ByteString.Lazy (ByteString)
-- > import Data.Aeson.Types
-- > import qualified Data.Aeson.Combinators.Decode as ACD
-- > import GHC.Generics
-- >
-- > data Person = Person
-- >     { name :: Text
-- >     , age  :: Int
-- >     } deriving (Generic, Show)
-- >
-- > instance FromJSON Person
-- >
-- > decodeEmbededPerson :: [Text] -> ByteString -> Maybe Person
-- > decodeEmbededPerson path json =
-- >     ACD.decode (ACD.at path ACD.auto) json
--
-- Now we can extract Person from any key within the json.
--
-- > >>> decodeEmbededPerson ["data", "person"] "{\"data\": {\"person\":{\"name\":\"Joe\",\"age\":12}}}"
-- > Just (Person {name = "Joe", age = 12})
--
-- __Easily decode multiple data from single json:__
--
-- > -- data Person defined above ^
-- >
-- > -- using alias for simplicity
-- > type Token = Text
-- >
-- > decodePersonWithToken :: ByteString -> Maybe (Token, Person)
-- > decodePersonWithToken json = ACD.decode decoder json
-- >     where decoder =
-- >             (,) <$> ACD.key "token" ACD.text
-- >                 <*> ACD.key "person" ACD.auto
--
-- Which can be used as following
--
-- > >>> decodePersonWithToken "{\"person\":{\"name\":\"Joe\",\"age\":12}, \"token\": \"foo\"}"
-- > Just ("foo",Person {name = "Joe", age = 12})

-- $applicative
--
-- If you like elm style decoding you can avoid using 'FromJSON' type class altogher.
--
-- > import Data.Text
-- > import qualified Data.Aeson.Combinators.Decode as ACD
-- >
-- > data Person = Person
-- >     { name :: Text
-- >     , age  :: Int
-- >     } deriving (Show)
-- >
-- > personDecoder :: ACD.Decoder Person
-- > personDecoder = Person
-- >         <$> ACD.key "name" ACD.text
-- >         <*> ACD.key "age" ACD.int
--
-- And use it directly as:
--
-- > >>> decode personDecoder "{\"name\":\"Joe\",\"age\":12}"
-- > Just (Person {name = "Joe", age = 12})


-- |
-- A value describing how other values are decoded from JSON.
-- This type is an alternative to Aeson's 'FromJSON' instance implementation.
--
-- Use 'decode', 'decode', 'eitherDecode', 'eitherDecode''
-- 'decodeStrict', 'decodeStrict'', 'eitherDecodeStrict' or 'eitherDecodeStrict''
-- alternatives provided by this module for decoding from 'ByteString'.
--
-- For decoding files use
-- 'decodeFileStrict', 'decodeFileStrict''
-- 'eitherDecodeFileStrict', 'eitherDecodeFileStrict''
-- also provided by this module.
--
-- When working with 'Value', use 'parseMaybe' or 'parseEither' function.
--
-- === Functor to map function over 'Decoder'
--
-- > intToString :: Decoder String
-- > intToString = show <$> Decode.int
--
-- > >>> decode intToString "2"
-- > Just "2"
--
-- === Applicative to construct products
--
-- > stringIntPair :: Decoder (String, Int)
-- > stringIntPair = (,) <$> index 0 string
-- >                     <*> index 1 int
--
-- > >>> decode stringIntPair "[\"hello\", 42]"
-- > Just ("hello", 42)
--
-- === Alternative to construct sums
--
-- > eitherTextOrInt :: Decoder (Either Text Int)
-- > eitherTextOrInt = Left  <$> Decode.text
-- >               <|> Right <$> Decode.int
--
-- > >>> decode eitherTextOrInt "\"Lorem Ipsum\""
-- > Just (Left "Lorem Ipsum")
-- > >>> decode eitherTextOrInt "42"
-- > Just (Right 42)
--
-- === Monad for 'Decoder' chaining
--
-- > odd :: Decoder Int
-- > odd = do
-- >   val <- int
-- >   if val `mod` 2 == 1
-- >   then $ return val
-- >   else fail $ "Expected odd value, got " <> show val
--
-- > >>> eitherDecode odd "3"
-- > Right 3
-- > >>> eitherDecode odd "4"
-- > Left "Error in $: Expected odd value, got 4"
newtype Decoder a =
  Decoder (Value -> Parser a)

instance Functor Decoder where
  fmap :: (a -> b) -> Decoder a -> Decoder b
fmap a -> b
f (Decoder Value -> Parser a
d) = (Value -> Parser b) -> Decoder b
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser b) -> Decoder b)
-> (Value -> Parser b) -> Decoder b
forall a b. (a -> b) -> a -> b
$ (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f (Parser a -> Parser b) -> (Value -> Parser a) -> Value -> Parser b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Parser a
d
  {-# INLINE fmap #-}

instance Applicative Decoder where
  pure :: a -> Decoder a
pure a
val = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser a) -> Decoder a)
-> (Value -> Parser a) -> Decoder a
forall a b. (a -> b) -> a -> b
$ \Value
_ -> a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
val
  {-# INLINE pure #-}
  (Decoder Value -> Parser (a -> b)
f') <*> :: Decoder (a -> b) -> Decoder a -> Decoder b
<*> (Decoder Value -> Parser a
d) = (Value -> Parser b) -> Decoder b
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser b) -> Decoder b)
-> (Value -> Parser b) -> Decoder b
forall a b. (a -> b) -> a -> b
$
    \Value
val ->
        (\a -> b
f -> (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f (Value -> Parser a
d Value
val)) ((a -> b) -> Parser b) -> Parser (a -> b) -> Parser b
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Value -> Parser (a -> b)
f' Value
val
  {-# INLINE (<*>) #-}

instance Monad Decoder where
  return :: a -> Decoder a
return = a -> Decoder a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  (Decoder Value -> Parser a
a) >>= :: Decoder a -> (a -> Decoder b) -> Decoder b
>>= a -> Decoder b
f = (Value -> Parser b) -> Decoder b
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser b) -> Decoder b)
-> (Value -> Parser b) -> Decoder b
forall a b. (a -> b) -> a -> b
$
    \Value
val -> case (Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
a Value
val of
      Success a
v -> let (Decoder Value -> Parser b
res) = a -> Decoder b
f a
v
                   in Value -> Parser b
res Value
val
      Result a
_ -> Value -> Parser b
forall a. Value -> Parser a
unexpected Value
val
  {-# INLINE (>>=) #-}
#if !(MIN_VERSION_base(4,13,0))
  fail = Fail.fail
#endif

instance Alternative Decoder where
  empty :: Decoder a
empty = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder Value -> Parser a
forall a. Value -> Parser a
unexpected
  {-# INLINE empty #-}
  Decoder Value -> Parser a
a <|> :: Decoder a -> Decoder a -> Decoder a
<|> Decoder Value -> Parser a
b = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser a) -> Decoder a)
-> (Value -> Parser a) -> Decoder a
forall a b. (a -> b) -> a -> b
$ \Value
v -> Value -> Parser a
a Value
v Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Value -> Parser a
b Value
v
  {-# INLINE (<|>) #-}

instance MonadFail Decoder where
  fail :: String -> Decoder a
fail String
s = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser a) -> Decoder a)
-> (Value -> Parser a) -> Decoder a
forall a b. (a -> b) -> a -> b
$ \Value
_ -> String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
Fail.fail String
s
  {-# INLINE fail #-}


-- | 'Decoder' is compatible with Aeson's 'FromJSON' class.
-- 'auto' decoder acts like a proxy to instance implementation.
-- Any type that is an instance of this class is automatically compatible.
--
-- While 'auto' is universally usable for all primitive values,
-- this library provides individual type constraint functions
-- for decoding most common primitives and combinators for decoding larger structure from these primitives.
auto :: FromJSON a => Decoder a
auto :: Decoder a
auto = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder Value -> Parser a
forall a. FromJSON a => Value -> Parser a
parseJSON
{-# INLINE auto #-}


-- Continer Decoders

-- | Decode JSON null and other JSON value to 'Data.Maybe'.
-- JSON null will be decoded to 'Nothing'.
-- Other value decoded by provided 'Decoder' to 'Just'
nullable :: Decoder a -> Decoder (Maybe a)
nullable :: Decoder a -> Decoder (Maybe a)
nullable (Decoder Value -> Parser a
d) = (Value -> Parser (Maybe a)) -> Decoder (Maybe a)
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser (Maybe a)) -> Decoder (Maybe a))
-> (Value -> Parser (Maybe a)) -> Decoder (Maybe a)
forall a b. (a -> b) -> a -> b
$ \case
  Value
Null  -> Maybe a -> Parser (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
  Value
other -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> Parser a -> Parser (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser a
d Value
other
{-# INLINE nullable #-}


-- | Decode JSON array of values to '[a]' of values
-- using provided 'Decoder'.
list :: Decoder a -> Decoder [a]
list :: Decoder a -> Decoder [a]
list (Decoder Value -> Parser a
d) = (Value -> Parser [a]) -> Decoder [a]
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser [a]) -> Decoder [a])
-> (Value -> Parser [a]) -> Decoder [a]
forall a b. (a -> b) -> a -> b
$
  (Value -> Parser a) -> Value -> Parser [a]
forall a. (Value -> Parser a) -> Value -> Parser [a]
listParser Value -> Parser a
d
{-# INLINE list #-}


-- | Decode JSON array of values to 'Vector' of values
-- using provided 'Decoder'.
vector :: Decoder a -> Decoder (Vector a)
vector :: Decoder a -> Decoder (Vector a)
vector (Decoder Value -> Parser a
d) = (Value -> Parser (Vector a)) -> Decoder (Vector a)
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser (Vector a)) -> Decoder (Vector a))
-> (Value -> Parser (Vector a)) -> Decoder (Vector a)
forall a b. (a -> b) -> a -> b
$ \case
  Array Array
v -> (Value -> Parser a) -> Array -> Parser (Vector a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Vector a -> m (Vector b)
Vector.mapM Value -> Parser a
d Array
v
  Value
other   -> String -> Value -> Parser (Vector a)
forall a. String -> Value -> Parser a
typeMismatch String
"Array" Value
other
{-# INLINE vector #-}


-- | Decode JSON object to 'HL.HashMap' with 'Data.Text' key
-- using provided 'Decoder'.
hashMapLazy :: Decoder a -> Decoder (HL.HashMap Text a)
hashMapLazy :: Decoder a -> Decoder (HashMap Text a)
hashMapLazy (Decoder Value -> Parser a
d) = (Value -> Parser (HashMap Text a)) -> Decoder (HashMap Text a)
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser (HashMap Text a)) -> Decoder (HashMap Text a))
-> (Value -> Parser (HashMap Text a)) -> Decoder (HashMap Text a)
forall a b. (a -> b) -> a -> b
$ \case
  Object Object
xs -> (Value -> Parser a) -> Object -> Parser (HashMap Text a)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Value -> Parser a
d Object
xs
  Value
val       -> String -> Value -> Parser (HashMap Text a)
forall a. String -> Value -> Parser a
typeMismatch String
"Array" Value
val
{-# INLINE hashMapLazy #-}


-- | Decode JSON object to 'HS.HashMap' with 'Data.Text' key
-- using provided 'Decoder'.
hashMapStrict :: Decoder a -> Decoder (HS.HashMap Text a)
hashMapStrict :: Decoder a -> Decoder (HashMap Text a)
hashMapStrict (Decoder Value -> Parser a
d) = (Value -> Parser (HashMap Text a)) -> Decoder (HashMap Text a)
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser (HashMap Text a)) -> Decoder (HashMap Text a))
-> (Value -> Parser (HashMap Text a)) -> Decoder (HashMap Text a)
forall a b. (a -> b) -> a -> b
$ \case
  Object Object
xs -> (Value -> Parser a) -> Object -> Parser (HashMap Text a)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Value -> Parser a
d Object
xs
  Value
val       -> String -> Value -> Parser (HashMap Text a)
forall a. String -> Value -> Parser a
typeMismatch String
"Array" Value
val
{-# INLINE hashMapStrict #-}


-- | Decode JSON object to 'ML.Map' with 'Data.Text' key
-- using provided 'Decoder'.
mapLazy :: Decoder a -> Decoder (ML.Map Text a)
mapLazy :: Decoder a -> Decoder (Map Text a)
mapLazy Decoder a
dec = [(Text, a)] -> Map Text a
forall k a. Ord k => [(k, a)] -> Map k a
ML.fromList ([(Text, a)] -> Map Text a)
-> (HashMap Text a -> [(Text, a)]) -> HashMap Text a -> Map Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Text a -> [(Text, a)]
forall k v. HashMap k v -> [(k, v)]
HL.toList (HashMap Text a -> Map Text a)
-> Decoder (HashMap Text a) -> Decoder (Map Text a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder a -> Decoder (HashMap Text a)
forall a. Decoder a -> Decoder (HashMap Text a)
hashMapLazy Decoder a
dec
{-# INLINE mapLazy #-}


-- | Decode JSON object to 'MS.Map' with 'Data.Text' key
-- using provided 'Decoder'.
mapStrict :: Decoder a -> Decoder (MS.Map Text a)
mapStrict :: Decoder a -> Decoder (Map Text a)
mapStrict Decoder a
dec = [(Text, a)] -> Map Text a
forall k a. Ord k => [(k, a)] -> Map k a
MS.fromList ([(Text, a)] -> Map Text a)
-> (HashMap Text a -> [(Text, a)]) -> HashMap Text a -> Map Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Text a -> [(Text, a)]
forall k v. HashMap k v -> [(k, v)]
HL.toList (HashMap Text a -> Map Text a)
-> Decoder (HashMap Text a) -> Decoder (Map Text a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder a -> Decoder (HashMap Text a)
forall a. Decoder a -> Decoder (HashMap Text a)
hashMapLazy Decoder a
dec
{-# INLINE mapStrict #-}


-- Combinators

-- | Decode JSON null to any value.
-- This function is useful for decoding
-- constructors which represented by null in JSON.
--
-- > data Codomain = NotSet | Foo | Bar
-- >
-- > myDomainDecoder :: Decoder Codomain
-- > myDomainDecoder = jsonNull NotSet
-- >               <|> (text >>= fooBar)
-- >    where fooBar "foo"   = return Foo
-- >          fooBar "bar"   = return Bar
-- >          fooBar unknown = fail $ "Unknown value " <> show unknown
jsonNull :: a -> Decoder a
jsonNull :: a -> Decoder a
jsonNull a
a = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser a) -> Decoder a)
-> (Value -> Parser a) -> Decoder a
forall a b. (a -> b) -> a -> b
$ \case
  Value
Null -> a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
  Value
val  -> String -> Value -> Parser a
forall a. String -> Value -> Parser a
typeMismatch String
"null" Value
val
{-# INLINE jsonNull #-}


-- | Extract JSON value from JSON object key
--
-- >>> decode (key "data" int) "{\"data\": 42}"
-- Just 42
key :: Text -> Decoder a -> Decoder a
key :: Text -> Decoder a -> Decoder a
key Text
t (Decoder Value -> Parser a
d) = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser a) -> Decoder a)
-> (Value -> Parser a) -> Decoder a
forall a b. (a -> b) -> a -> b
$ \case
  Object Object
v -> Value -> Parser a
d (Value -> Parser a) -> Parser Value -> Parser a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Object
v Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
t
  Value
val      -> String -> Value -> Parser a
forall a. String -> Value -> Parser a
typeMismatch String
"Object" Value
val
{-# INLINE key #-}


-- | Extract JSON value from JSON object keys
--
-- >>> decode (at ["data", "value"] int) "{\"data\": {\"value\": 42}}"
-- Just 42
at :: [Text] -> Decoder a -> Decoder a
at :: [Text] -> Decoder a -> Decoder a
at [Text]
pth Decoder a
d = (Text -> Decoder a -> Decoder a)
-> Decoder a -> [Text] -> Decoder a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Text -> Decoder a -> Decoder a
forall a. Text -> Decoder a -> Decoder a
key Decoder a
d [Text]
pth
{-# INLINE at #-}


-- | Extract JSON value from JSON array index
--
-- >>> decode (index 2 int) "[0,1,2,3,4]"
-- Just 2
index :: Int -> Decoder a -> Decoder a
index :: Int -> Decoder a -> Decoder a
index Int
i (Decoder Value -> Parser a
d) = (Value -> Parser a) -> Decoder a
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser a) -> Decoder a)
-> (Value -> Parser a) -> Decoder a
forall a b. (a -> b) -> a -> b
$ \Value
val ->
  case Value
val of
    Array Array
vec -> case Array
vec Array -> Int -> Maybe Value
forall a. Vector a -> Int -> Maybe a
!? Int
i of
                    Just Value
v  -> Value -> Parser a
d Value
v
                    Maybe Value
Nothing -> Value -> Parser a
forall a. Value -> Parser a
unexpected Value
val
    Value
_         -> String -> Value -> Parser a
forall a. String -> Value -> Parser a
typeMismatch String
"Array" Value
val
{-# INLINE index #-}


-- | Extract JSON value from JSON array indexes
--
-- > >>> decode (indexes [0,1,0] int) "[[true, [42]]]"
-- > Just 42
indexes :: [Int] -> Decoder a -> Decoder a
indexes :: [Int] -> Decoder a -> Decoder a
indexes [Int]
pth Decoder a
d = (Int -> Decoder a -> Decoder a) -> Decoder a -> [Int] -> Decoder a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Int -> Decoder a -> Decoder a
forall a. Int -> Decoder a -> Decoder a
index Decoder a
d [Int]
pth
{-# INLINE indexes #-}


-- $jsonpath
-- Combinators using Aeson's 'JSONPathElement' and 'JSONPath' types.
-- This makes it possible to combine object keys and array index accessors.

-- | Decode value from JSON structure.
--
-- From object key:
--
-- >>> decode (element (Key "data") text) "{\"data\": \"foo\"}"
-- Just "foo"
--
-- From array index:
--
-- >>> decode (element (Index 1) int) "[0,1,2]"
-- Just 1
element :: JSONPathElement -> Decoder a -> Decoder a
element :: JSONPathElement -> Decoder a -> Decoder a
element (Key Text
txt) = Text -> Decoder a -> Decoder a
forall a. Text -> Decoder a -> Decoder a
key Text
txt
element (Index Int
i) = Int -> Decoder a -> Decoder a
forall a. Int -> Decoder a -> Decoder a
index Int
i
{-# INLINE element #-}


-- | Decode value from deep JSON structure.
--
-- >>> decode (path [Key "data", Index 0] bool) "{\"data\":[true, false, false]}"
-- Just True
path :: JSONPath -> Decoder a -> Decoder a
path :: JSONPath -> Decoder a -> Decoder a
path JSONPath
pth Decoder a
d = (JSONPathElement -> Decoder a -> Decoder a)
-> Decoder a -> JSONPath -> Decoder a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr JSONPathElement -> Decoder a -> Decoder a
forall a. JSONPathElement -> Decoder a -> Decoder a
element Decoder a
d JSONPath
pth
{-# INLINE path #-}


-- | Try a decoder and get back a 'Just a' if it succeeds and 'Nothing' if it fails.
-- In other words, this decoder always succeeds with a 'Maybe a' value.
--
-- >>> decode (maybe string) "42"
-- Just Nothing
-- >>> decode (maybe int) "42"
-- Just (Just 42)
maybe :: Decoder a -> Decoder (Maybe a)
maybe :: Decoder a -> Decoder (Maybe a)
maybe (Decoder Value -> Parser a
d) =
  (Value -> Parser (Maybe a)) -> Decoder (Maybe a)
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser (Maybe a)) -> Decoder (Maybe a))
-> (Value -> Parser (Maybe a)) -> Decoder (Maybe a)
forall a b. (a -> b) -> a -> b
$ \Value
val ->
    case (Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
d Value
val of
      Success a
x -> Maybe a -> Parser (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> Maybe a
forall a. a -> Maybe a
Just a
x)
      Error String
_   -> Maybe a -> Parser (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
{-# INLINE maybe #-}


-- | Try a decoder and get back a 'Right a' if it succeeds and a 'Left String' if it fails.
-- In other words, this decoder always succeeds with an 'Either String a' value.
--
-- >>> decode (either string) "42"
-- Just (Left "expected String, but encountered Number")
-- >>> decode (either int) "42"
-- Just (Right 42)
either :: Decoder a -> Decoder (Either String a)
either :: Decoder a -> Decoder (Either String a)
either (Decoder Value -> Parser a
d) =
  (Value -> Parser (Either String a)) -> Decoder (Either String a)
forall a. (Value -> Parser a) -> Decoder a
Decoder ((Value -> Parser (Either String a)) -> Decoder (Either String a))
-> (Value -> Parser (Either String a)) -> Decoder (Either String a)
forall a b. (a -> b) -> a -> b
$ \Value
val ->
    case (Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
d Value
val of
      Success a
x -> Either String a -> Parser (Either String a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> Either String a
forall a b. b -> Either a b
Right a
x)
      Error String
err -> Either String a -> Parser (Either String a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Either String a
forall a b. a -> Either a b
Left String
err)
{-# INLINE either #-}


-- | Try a number of decoders in order and return the first success.
--
-- >>> import Data.List.NonEmpty
-- >>> decode (oneOf $ (words <$> string) :| [ list string ]) "\"Hello world!\""
-- Just ["Hello","world!"]
-- >>> decode (oneOf $ (list string) :| [  words <$> string ] ) "[\"Hello world!\"]"
-- Just ["Hello world!"]
-- >>> decode (oneOf $ (Right <$> bool) :| [ return (Left "Not a boolean") ]) "false"
-- Just (Right False)
-- >>> decode (oneOf $ (Right <$> bool) :| [ return (Left "Not a boolean") ]) "42"
-- Just (Left "Not a boolean")
oneOf :: NonEmpty (Decoder a) -> Decoder a
oneOf :: NonEmpty (Decoder a) -> Decoder a
oneOf (Decoder a
first :| [Decoder a]
rest) =
  (Decoder a -> Decoder a -> Decoder a)
-> Decoder a -> [Decoder a] -> Decoder a
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Decoder a -> Decoder a -> Decoder a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
(<|>) Decoder a
first [Decoder a]
rest
{-# INLINE oneOf #-}


-- Basic Decoders

-- | Decode any JSON value to 'Void' value
-- which is impossible to construct.
--
-- __This Decoder is guarenteed to fail.__
void :: Decoder Void
void :: Decoder Void
void = Decoder Void
forall a. FromJSON a => Decoder a
auto
{-# INLINE void #-}


-- | Decode JSON null into @()@
unit :: Decoder ()
unit :: Decoder ()
unit = Decoder ()
forall a. FromJSON a => Decoder a
auto
{-# INLINE unit #-}


-- | Decode JSON booleans to Haskell 'Data.Bool'
bool :: Decoder Bool
bool :: Decoder Bool
bool = Decoder Bool
forall a. FromJSON a => Decoder a
auto
{-# INLINE bool #-}


-- | Decode JSON number to 'Data.Int.Int'
int :: Decoder Int
int :: Decoder Int
int = Decoder Int
forall a. FromJSON a => Decoder a
auto
{-# INLINE int #-}


-- | Decode JSON number to 'Data.Int.Int8'
int8 :: Decoder Int8
int8 :: Decoder Int8
int8 = Decoder Int8
forall a. FromJSON a => Decoder a
auto
{-# INLINE int8 #-}


-- | Decode JSON number to 'Data.Int.Int16'
int16 :: Decoder Int16
int16 :: Decoder Int16
int16 = Decoder Int16
forall a. FromJSON a => Decoder a
auto
{-# INLINE int16 #-}


-- | Decode JSON number to 'Data.Int.Int32'
int32 :: Decoder Int32
int32 :: Decoder Int32
int32 = Decoder Int32
forall a. FromJSON a => Decoder a
auto
{-# INLINE int32 #-}


-- | Decode JSON number to 'Data.Int.Int64'
int64 :: Decoder Int64
int64 :: Decoder Int64
int64 = Decoder Int64
forall a. FromJSON a => Decoder a
auto
{-# INLINE int64 #-}


-- | Decode JSON number to unbounded 'Integer'
integer :: Decoder Integer
integer :: Decoder Integer
integer = Decoder Integer
forall a. FromJSON a => Decoder a
auto
{-# INLINE integer #-}


#if (MIN_VERSION_base(4,8,0))
-- | Decode JSON number to GHC's 'GHC.Natural' (non negative)
--
-- This function requires 'base' >= 4.8.0
natural :: Decoder Natural
natural :: Decoder Natural
natural = Decoder Natural
forall a. FromJSON a => Decoder a
auto
{-# INLINE natural #-}
#endif


-- | Decode JSON number to bounded 'Data.Word.Word'
word :: Decoder Word
word :: Decoder Word
word = Decoder Word
forall a. FromJSON a => Decoder a
auto
{-# INLINE word #-}


-- | Decode JSON number to bounded 'Data.Word.Word8'
word8 :: Decoder Word8
word8 :: Decoder Word8
word8 = Decoder Word8
forall a. FromJSON a => Decoder a
auto
{-# INLINE word8 #-}


-- | Decode JSON number to bounded 'Data.Word.Word16'
word16 :: Decoder Word16
word16 :: Decoder Word16
word16 = Decoder Word16
forall a. FromJSON a => Decoder a
auto
{-# INLINE word16 #-}


-- | Decode JSON number to bounded 'Data.Word.Word32'
word32 :: Decoder Word32
word32 :: Decoder Word32
word32 = Decoder Word32
forall a. FromJSON a => Decoder a
auto
{-# INLINE word32 #-}


-- | Decode JSON number to bounded 'Data.Word.Word64'
word64 :: Decoder Word64
word64 :: Decoder Word64
word64 = Decoder Word64
forall a. FromJSON a => Decoder a
auto
{-# INLINE word64 #-}


-- | Decode JSON number to 'Float'
float :: Decoder Float
float :: Decoder Float
float = Decoder Float
forall a. FromJSON a => Decoder a
auto
{-# INLINE float #-}


-- | Decode JSON number to 'Double'
double :: Decoder Double
double :: Decoder Double
double = Decoder Double
forall a. FromJSON a => Decoder a
auto
{-# INLINE double #-}


-- | Decode JSON number to arbitrary precision 'Scientific'
scientific :: Decoder Scientific
scientific :: Decoder Scientific
scientific = Decoder Scientific
forall a. FromJSON a => Decoder a
auto
{-# INLINE scientific #-}


-- | Decode single character JSON string to 'Data.Char'
char :: Decoder Char
char :: Decoder Char
char = Decoder Char
forall a. FromJSON a => Decoder a
auto
{-# INLINE char #-}


-- | Decode JSON string to 'Data.String'
string :: Decoder String
string :: Decoder String
string = Decoder String
forall a. FromJSON a => Decoder a
auto
{-# INLINE string #-}


-- | Decode JSON string to 'Data.Text'
text :: Decoder Text
text :: Decoder Text
text = Decoder Text
forall a. FromJSON a => Decoder a
auto
{-# INLINE text #-}


-- | Decode JSON string to 'Data.UUID.Types.UUID'
uuid :: Decoder UUID
uuid :: Decoder UUID
uuid = Decoder UUID
forall a. FromJSON a => Decoder a
auto
{-# INLINE uuid #-}


-- | Decode JSON string to 'Data.Version'
version :: Decoder Version
version :: Decoder Version
version = Decoder Version
forall a. FromJSON a => Decoder a
auto
{-# INLINE version #-}


-- | Decode JSON string to 'Data.Local.Time.ZonedTime'
-- using Aeson's instance implementation.
--
-- Supported string formats:
--
-- YYYY-MM-DD HH:MM Z YYYY-MM-DD HH:MM:SS Z YYYY-MM-DD HH:MM:SS.SSS Z
--
-- The first space may instead be a T, and the second space is optional. The Z represents UTC. The Z may be replaced with a time zone offset of the form +0000 or -08:00, where the first two digits are hours, the : is optional and the second two digits (also optional) are minutes.
zonedTime :: Decoder ZonedTime
zonedTime :: Decoder ZonedTime
zonedTime = Decoder ZonedTime
forall a. FromJSON a => Decoder a
auto
{-# INLINE zonedTime #-}


-- | Decode JSON string to 'Data.Local.Time.LocalTime'
-- using Aeson's instance implementation.
localTime :: Decoder LocalTime
localTime :: Decoder LocalTime
localTime = Decoder LocalTime
forall a. FromJSON a => Decoder a
auto
{-# INLINE localTime #-}


-- | Decode JSON string to 'Data.Local.Time.TimeOfDay'
-- using Aeson's instance implementation.
timeOfDay :: Decoder TimeOfDay
timeOfDay :: Decoder TimeOfDay
timeOfDay = Decoder TimeOfDay
forall a. FromJSON a => Decoder a
auto
{-# INLINE timeOfDay #-}


-- | Decode JSON string to 'Data.Time.Clock.UTCTime'
-- using Aesons's instance implementation
utcTime :: Decoder UTCTime
utcTime :: Decoder UTCTime
utcTime = Decoder UTCTime
forall a. FromJSON a => Decoder a
auto
{-# INLINE utcTime #-}


-- | Decode JSON string to 'Data.Time.Calendar.Day'
-- using Aesons's instance implementation
day :: Decoder Day
day :: Decoder Day
day = Decoder Day
forall a. FromJSON a => Decoder a
auto
{-# INLINE day #-}


#if (MIN_VERSION_time_compat(1,9,2))
-- | Decode JSON string to 'Data.Time.Calendar.Compat.DayOfWeek'
-- using Aesons's instance implementation
--
-- This function requires 'time-compat' >= 1.9.2
dayOfWeek :: Decoder DayOfWeek
dayOfWeek :: Decoder DayOfWeek
dayOfWeek = Decoder DayOfWeek
forall a. FromJSON a => Decoder a
auto
{-# INLINE dayOfWeek #-}
#endif



-- Decoding


-- $decoding
--
-- Following functions are evivalent to ones provided by Aeson itself.
-- The only difference is that versions implemented by Aeson
-- work only with instances of 'FromJSON' class.
-- Functions defines in this module are using 'Decoder' argument
-- instead of instance implementation.

-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
-- If this fails due to incomplete or invalid input, 'Nothing' is
-- returned.
--
-- The input must consist solely of a JSON document, with no trailing
-- data except for whitespace.
--
-- This function parses immediately, but defers conversion. See
-- 'Data.Aeson.json' for details.
decode :: Decoder a -> LB.ByteString -> Maybe a
decode :: Decoder a -> ByteString -> Maybe a
decode (Decoder Value -> Parser a
d) =
  Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
forall a.
Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
Parser.decodeWith Parser Value
ParserI.jsonEOF ((Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
d)
{-# INLINE decode #-}


-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
-- If this fails due to incomplete or invalid input, 'Nothing' is
-- returned.
--
-- The input must consist solely of a JSON document, with no trailing
-- data except for whitespace.
--
-- This function parses and performs conversion immediately. See
-- 'Data.Aeson.json'' for details.
decode' :: Decoder a -> LB.ByteString -> Maybe a
decode' :: Decoder a -> ByteString -> Maybe a
decode' (Decoder Value -> Parser a
d) =
  Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
forall a.
Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
Parser.decodeWith Parser Value
ParserI.jsonEOF' ((Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
d)
{-# INLINE decode' #-}


-- | Like 'decode' but returns an error message when decoding fails.
eitherDecode :: Decoder a -> LB.ByteString -> Either String a
eitherDecode :: Decoder a -> ByteString -> Either String a
eitherDecode (Decoder Value -> Parser a
d) =
  Either (JSONPath, String) a -> Either String a
forall a. Either (JSONPath, String) a -> Either String a
eitherFormatError (Either (JSONPath, String) a -> Either String a)
-> (ByteString -> Either (JSONPath, String) a)
-> ByteString
-> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
forall a.
Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
Parser.eitherDecodeWith Parser Value
ParserI.jsonEOF ((Value -> Parser a) -> Value -> IResult a
forall a b. (a -> Parser b) -> a -> IResult b
AI.iparse Value -> Parser a
d)
{-# INLINE eitherDecode #-}


-- | Like 'decode'' but returns an error message when decoding fails.
eitherDecode' :: Decoder a -> LB.ByteString -> Either String a
eitherDecode' :: Decoder a -> ByteString -> Either String a
eitherDecode' (Decoder Value -> Parser a
d) =
  Either (JSONPath, String) a -> Either String a
forall a. Either (JSONPath, String) a -> Either String a
eitherFormatError (Either (JSONPath, String) a -> Either String a)
-> (ByteString -> Either (JSONPath, String) a)
-> ByteString
-> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
forall a.
Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
Parser.eitherDecodeWith Parser Value
ParserI.jsonEOF' ((Value -> Parser a) -> Value -> IResult a
forall a b. (a -> Parser b) -> a -> IResult b
AI.iparse Value -> Parser a
d)
{-# INLINE eitherDecode' #-}


-- Strict Decoding


-- | Efficiently deserialize a JSON value from a strict 'B.ByteString'.
-- If this fails due to incomplete or invalid input, 'Nothing' is
-- returned.
--
-- The input must consist solely of a JSON document, with no trailing
-- data except for whitespace.
--
-- This function parses immediately, but defers conversion. See
-- 'Data.Aeson.json' for details.
decodeStrict :: Decoder a -> B.ByteString -> Maybe a
decodeStrict :: Decoder a -> ByteString -> Maybe a
decodeStrict (Decoder Value -> Parser a
d) =
  Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
forall a.
Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
Parser.decodeStrictWith Parser Value
ParserI.jsonEOF ((Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
d)
{-# INLINE decodeStrict #-}


-- | Efficiently deserialize a JSON value from a strict 'B.ByteString'.
-- If this fails due to incomplete or invalid input, 'Nothing' is
-- returned.
--
-- The input must consist solely of a JSON document, with no trailing
-- data except for whitespace.
--
-- This function parses and performs conversion immediately.  See
-- 'Data.Aeson.json'' for details.
decodeStrict' :: Decoder a -> B.ByteString -> Maybe a
decodeStrict' :: Decoder a -> ByteString -> Maybe a
decodeStrict' (Decoder Value -> Parser a
d) =
  Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
forall a.
Parser Value -> (Value -> Result a) -> ByteString -> Maybe a
Parser.decodeStrictWith Parser Value
ParserI.jsonEOF' ((Value -> Parser a) -> Value -> Result a
forall a b. (a -> Parser b) -> a -> Result b
parse Value -> Parser a
d)
{-# INLINE decodeStrict' #-}


-- | Like 'decodeStrict' but returns an error message when decoding fails.
eitherDecodeStrict :: Decoder a -> B.ByteString -> Either String a
eitherDecodeStrict :: Decoder a -> ByteString -> Either String a
eitherDecodeStrict (Decoder Value -> Parser a
d) =
  Either (JSONPath, String) a -> Either String a
forall a. Either (JSONPath, String) a -> Either String a
eitherFormatError (Either (JSONPath, String) a -> Either String a)
-> (ByteString -> Either (JSONPath, String) a)
-> ByteString
-> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
forall a.
Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
Parser.eitherDecodeStrictWith Parser Value
ParserI.jsonEOF ((Value -> Parser a) -> Value -> IResult a
forall a b. (a -> Parser b) -> a -> IResult b
AI.iparse Value -> Parser a
d)
{-# INLINE eitherDecodeStrict #-}


-- | Like 'decodeStrict'' but returns an error message when decoding fails.
eitherDecodeStrict' :: Decoder a -> B.ByteString -> Either String a
eitherDecodeStrict' :: Decoder a -> ByteString -> Either String a
eitherDecodeStrict' (Decoder Value -> Parser a
d) =
  Either (JSONPath, String) a -> Either String a
forall a. Either (JSONPath, String) a -> Either String a
eitherFormatError (Either (JSONPath, String) a -> Either String a)
-> (ByteString -> Either (JSONPath, String) a)
-> ByteString
-> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
forall a.
Parser Value
-> (Value -> IResult a)
-> ByteString
-> Either (JSONPath, String) a
Parser.eitherDecodeStrictWith Parser Value
ParserI.jsonEOF' ((Value -> Parser a) -> Value -> IResult a
forall a b. (a -> Parser b) -> a -> IResult b
AI.iparse Value -> Parser a
d)
{-# INLINE eitherDecodeStrict' #-}


-- File Decoding


-- | Efficiently deserialize a JSON value from a file.
-- If this fails due to incomplete or invalid input, 'Nothing' is
-- returned.
--
-- The input file's content must consist solely of a JSON document,
-- with no trailing data except for whitespace.
--
-- This function parses immediately, but defers conversion. See
-- 'Data.Aeson.json' for details.
decodeFileStrict :: Decoder a -> FilePath -> IO (Maybe a)
decodeFileStrict :: Decoder a -> String -> IO (Maybe a)
decodeFileStrict Decoder a
dec =
  (ByteString -> Maybe a) -> IO ByteString -> IO (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Decoder a -> ByteString -> Maybe a
forall a. Decoder a -> ByteString -> Maybe a
decodeStrict Decoder a
dec) (IO ByteString -> IO (Maybe a))
-> (String -> IO ByteString) -> String -> IO (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ByteString
B.readFile
{-# INLINE decodeFileStrict #-}


-- | Efficiently deserialize a JSON value from a file.
-- If this fails due to incomplete or invalid input, 'Nothing' is
-- returned.
--
-- The input file's content must consist solely of a JSON document,
-- with no trailing data except for whitespace.
--
-- This function parses and performs conversion immediately.  See
-- 'Data.Aeson.json'' for details.
decodeFileStrict' :: Decoder a -> FilePath -> IO (Maybe a)
decodeFileStrict' :: Decoder a -> String -> IO (Maybe a)
decodeFileStrict' Decoder a
dec =
  (ByteString -> Maybe a) -> IO ByteString -> IO (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Decoder a -> ByteString -> Maybe a
forall a. Decoder a -> ByteString -> Maybe a
decodeStrict' Decoder a
dec) (IO ByteString -> IO (Maybe a))
-> (String -> IO ByteString) -> String -> IO (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ByteString
B.readFile
{-# INLINE decodeFileStrict' #-}


-- | Like 'decodeFileStrict' but returns an error message when decoding fails.
eitherDecodeFileStrict :: Decoder a -> FilePath -> IO (Either String a)
eitherDecodeFileStrict :: Decoder a -> String -> IO (Either String a)
eitherDecodeFileStrict Decoder a
dec =
  (ByteString -> Either String a)
-> IO ByteString -> IO (Either String a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Decoder a -> ByteString -> Either String a
forall a. Decoder a -> ByteString -> Either String a
eitherDecodeStrict Decoder a
dec) (IO ByteString -> IO (Either String a))
-> (String -> IO ByteString) -> String -> IO (Either String a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ByteString
B.readFile
{-# INLINE eitherDecodeFileStrict #-}


-- | Like 'decodeFileStrict'' but returns an error message when decoding fails.
eitherDecodeFileStrict' :: Decoder a -> FilePath -> IO (Either String a)
eitherDecodeFileStrict' :: Decoder a -> String -> IO (Either String a)
eitherDecodeFileStrict' Decoder a
dec =
  (ByteString -> Either String a)
-> IO ByteString -> IO (Either String a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Decoder a -> ByteString -> Either String a
forall a. Decoder a -> ByteString -> Either String a
eitherDecodeStrict' Decoder a
dec) (IO ByteString -> IO (Either String a))
-> (String -> IO ByteString) -> String -> IO (Either String a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ByteString
B.readFile
{-# INLINE eitherDecodeFileStrict' #-}


-- Parsing


-- | Run decoder over 'Value'.
-- Returns 'Nothing' in case of failure
parseMaybe :: Decoder a -> Value -> Maybe a
parseMaybe :: Decoder a -> Value -> Maybe a
parseMaybe (Decoder Value -> Parser a
f) = (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
ATypes.parseMaybe Value -> Parser a
f
{-# INLINE parseMaybe #-}


-- | Run decoder over 'Value'.
-- Returns 'Left' with error message in case of failure
parseEither :: Decoder a -> Value -> Either String a
parseEither :: Decoder a -> Value -> Either String a
parseEither (Decoder Value -> Parser a
f) = (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
ATypes.parseEither Value -> Parser a
f
{-# INLINE parseEither #-}


-- Private functions Aeson doesn't expose


eitherFormatError :: Either (JSONPath, String) a -> Either String a
eitherFormatError :: Either (JSONPath, String) a -> Either String a
eitherFormatError = ((JSONPath, String) -> Either String a)
-> (a -> Either String a)
-> Either (JSONPath, String) a
-> Either String a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Prelude.either (String -> Either String a
forall a b. a -> Either a b
Left (String -> Either String a)
-> ((JSONPath, String) -> String)
-> (JSONPath, String)
-> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JSONPath -> String -> String) -> (JSONPath, String) -> String
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry JSONPath -> String -> String
AI.formatError) a -> Either String a
forall a b. b -> Either a b
Right
{-# INLINE eitherFormatError #-}


#if !(MIN_VERSION_aeson(1,4,3))
-- These functions are not exposed in aeson 1.4.2.0
-- implementation is copied from
-- https://hackage.haskell.org/package/aeson-1.4.6.0/docs/src/Data.Aeson.Types.FromJSON.html#unexpected

unexpected :: Value -> Parser a
unexpected actual = Fail.fail $ "unexpected " ++ typeOf actual
{-# INLINE unexpected #-}


typeOf :: Value -> String
typeOf v = case v of
    Object _ -> "Object"
    Array _  -> "Array"
    String _ -> "String"
    Number _ -> "Number"
    Bool _   -> "Boolean"
    Null     -> "Null"
{-# INLINE typeOf #-}
#endif