{-# OPTIONS_HADDOCK ignore-exports #-}
{-|
Module      : Data.Aeson.Safe
Copyright   : (c) 2019 Felix Paulusma
License     : MIT
Maintainer  : felix.paulusma@gmail.com
Stability   : experimental

This module contains homonyms of the "Data.Aeson" library's
encoding and decoding functions that, instead, use
"Data.SafeJSON"'s conversions.
This way, switching from "Data.Aeson" to "Data.SafeJSON" is
very easy. After any "Data.Aeson" imports, just add @.Safe@.

It also exports "Data.Aeson" and "Data.SafeJSON" itself for
convenience, but still hides 'parseJSON' and 'toJSON' so you
will get errors if you use them anywhere. That way you can
explicitly decide where to switch to 'safeFromJSON' or
'safeToJSON', or keep the current "Data.Aeson" functions.
-}
module Data.Aeson.Safe (
    module Data.SafeJSON
  , module Aeson
  , decode
  , decode'
  , eitherDecode
  , eitherDecode'
  , encode
  , encodeFile

  , decodeStrict
  , decodeStrict'
  , eitherDecodeStrict
  , eitherDecodeStrict'
  , decodeFileStrict
  , decodeFileStrict'
  , eitherDecodeFileStrict
  , eitherDecodeFileStrict'
  , encodeStrict

  , Parser
  , parseEither
  , parseMaybe
  ) where


import Data.Aeson as Aeson hiding (
    decode
  , decode'
  , decodeFileStrict
  , decodeFileStrict'
  , decodeStrict
  , decodeStrict'
  , eitherDecode
  , eitherDecode'
  , eitherDecodeFileStrict
  , eitherDecodeFileStrict'
  , eitherDecodeStrict
  , eitherDecodeStrict'
  , encode
  , encodeFile

  , parseJSON
  , toJSON
  )
import qualified Data.Aeson as A (
    decode
  , decode'
  , decodeFileStrict
  , decodeFileStrict'
  , decodeStrict
  , decodeStrict'
  , eitherDecode
  , eitherDecode'
  , eitherDecodeFileStrict
  , eitherDecodeFileStrict'
  , eitherDecodeStrict
  , eitherDecodeStrict'
  , encode
  , encodeFile
  )
import Data.Aeson.Types (Parser, parseEither, parseMaybe)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.SafeJSON


-- These definitions might not be the most efficient way to
-- encode/decode JSON values (especially not as efficient as
-- Aeson itself), but that can be addressed later if needed.
--
-- Aeson does the majority of the work encoding to and decoding
-- from 'ByteString's anyway.

-- * Decoding and encoding of SafeJSON types

-- ** Lazy ByteString variants

-- | Try to decode a 'LBS.ByteString' to a 'SafeJSON' value.
decode :: SafeJSON a => LBS.ByteString -> Maybe a
decode :: ByteString -> Maybe a
decode ByteString
lbs = ByteString -> Maybe Value
forall a. FromJSON a => ByteString -> Maybe a
A.decode ByteString
lbs Maybe Value -> (Value -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a 'LBS.ByteString' to a 'SafeJSON' value.
decode' :: SafeJSON a => LBS.ByteString -> Maybe a
decode' :: ByteString -> Maybe a
decode' ByteString
lbs = ByteString -> Maybe Value
forall a. FromJSON a => ByteString -> Maybe a
A.decode' ByteString
lbs Maybe Value -> (Value -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a 'LBS.ByteString' to a 'SafeJSON' value.
--   Produces an error message on failure.
eitherDecode :: SafeJSON a => LBS.ByteString -> Either String a
eitherDecode :: ByteString -> Either String a
eitherDecode ByteString
lbs = ByteString -> Either String Value
forall a. FromJSON a => ByteString -> Either String a
A.eitherDecode ByteString
lbs Either String Value
-> (Value -> Either String a) -> Either String a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a 'LBS.ByteString' to a 'SafeJSON' value.
--   Produces an error message on failure.
eitherDecode' :: SafeJSON a => LBS.ByteString -> Either String a
eitherDecode' :: ByteString -> Either String a
eitherDecode' ByteString
lbs = ByteString -> Either String Value
forall a. FromJSON a => ByteString -> Either String a
A.eitherDecode' ByteString
lbs Either String Value
-> (Value -> Either String a) -> Either String a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Encode a 'SafeJSON' value to a 'LBS.ByteString'.
encode :: SafeJSON a => a -> LBS.ByteString
encode :: a -> ByteString
encode = Value -> ByteString
forall a. ToJSON a => a -> ByteString
A.encode (Value -> ByteString) -> (a -> Value) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
forall a. SafeJSON a => a -> Value
safeToJSON

------------------------------------------------------
-- Strict variants
------------------------------------------------------

-- ** Strict ByteString variants

-- | Try to decode a 'BS.ByteString' to a 'SafeJSON' value.
decodeStrict :: SafeJSON a => BS.ByteString -> Maybe a
decodeStrict :: ByteString -> Maybe a
decodeStrict ByteString
lbs = ByteString -> Maybe Value
forall a. FromJSON a => ByteString -> Maybe a
A.decodeStrict ByteString
lbs Maybe Value -> (Value -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a 'BS.ByteString' to a 'SafeJSON' value.
decodeStrict' :: SafeJSON a => BS.ByteString -> Maybe a
decodeStrict' :: ByteString -> Maybe a
decodeStrict' ByteString
lbs = ByteString -> Maybe Value
forall a. FromJSON a => ByteString -> Maybe a
A.decodeStrict' ByteString
lbs Maybe Value -> (Value -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a 'BS.ByteString' to a 'SafeJSON' value.
--   Produces an error message on failure.
eitherDecodeStrict :: SafeJSON a => BS.ByteString -> Either String a
eitherDecodeStrict :: ByteString -> Either String a
eitherDecodeStrict ByteString
lbs = ByteString -> Either String Value
forall a. FromJSON a => ByteString -> Either String a
A.eitherDecodeStrict ByteString
lbs Either String Value
-> (Value -> Either String a) -> Either String a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a 'BS.ByteString' to a 'SafeJSON' value.
--   Produces an error message on failure.
eitherDecodeStrict' :: SafeJSON a => BS.ByteString -> Either String a
eitherDecodeStrict' :: ByteString -> Either String a
eitherDecodeStrict' ByteString
lbs = ByteString -> Either String Value
forall a. FromJSON a => ByteString -> Either String a
A.eitherDecodeStrict' ByteString
lbs Either String Value
-> (Value -> Either String a) -> Either String a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Same as 'encode', but also calls 'LBS.toStrict', for convenience.
encodeStrict :: SafeJSON a => a -> BS.ByteString
encodeStrict :: a -> ByteString
encodeStrict = ByteString -> ByteString
LBS.toStrict (ByteString -> ByteString) -> (a -> ByteString) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ByteString
forall a. SafeJSON a => a -> ByteString
encode

-- * Encoding to and decoding from files

-- | Try to decode a file to a 'SafeJSON' value.
decodeFileStrict :: SafeJSON a => FilePath -> IO (Maybe a)
decodeFileStrict :: String -> IO (Maybe a)
decodeFileStrict String
fp = do
    Maybe Value
mVal <- String -> IO (Maybe Value)
forall a. FromJSON a => String -> IO (Maybe a)
A.decodeFileStrict String
fp
    Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a -> IO (Maybe a)) -> Maybe a -> IO (Maybe a)
forall a b. (a -> b) -> a -> b
$ Maybe Value
mVal Maybe Value -> (Value -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a file to a 'SafeJSON' value.
decodeFileStrict' :: SafeJSON a => FilePath -> IO (Maybe a)
decodeFileStrict' :: String -> IO (Maybe a)
decodeFileStrict' String
fp = do
    Maybe Value
mVal <- String -> IO (Maybe Value)
forall a. FromJSON a => String -> IO (Maybe a)
A.decodeFileStrict' String
fp
    Maybe a -> IO (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a -> IO (Maybe a)) -> Maybe a -> IO (Maybe a)
forall a b. (a -> b) -> a -> b
$ Maybe Value
mVal Maybe Value -> (Value -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Maybe a
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a file to a 'SafeJSON' value.
--   Produces an error message on failure.
eitherDecodeFileStrict :: SafeJSON a => FilePath -> IO (Either String a)
eitherDecodeFileStrict :: String -> IO (Either String a)
eitherDecodeFileStrict String
fp = do
    Either String Value
eVal <- String -> IO (Either String Value)
forall a. FromJSON a => String -> IO (Either String a)
A.eitherDecodeFileStrict String
fp
    Either String a -> IO (Either String a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String a -> IO (Either String a))
-> Either String a -> IO (Either String a)
forall a b. (a -> b) -> a -> b
$ Either String Value
eVal Either String Value
-> (Value -> Either String a) -> Either String a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Try to decode a file to a 'SafeJSON' value.
--   Produces an error message on failure.
eitherDecodeFileStrict' :: SafeJSON a => FilePath -> IO (Either String a)
eitherDecodeFileStrict' :: String -> IO (Either String a)
eitherDecodeFileStrict' String
fp = do
    Either String Value
eVal <- String -> IO (Either String Value)
forall a. FromJSON a => String -> IO (Either String a)
A.eitherDecodeFileStrict' String
fp
    Either String a -> IO (Either String a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String a -> IO (Either String a))
-> Either String a -> IO (Either String a)
forall a b. (a -> b) -> a -> b
$ Either String Value
eVal Either String Value
-> (Value -> Either String a) -> Either String a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Value -> Parser a) -> Value -> Either String a
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser a
forall a. SafeJSON a => Value -> Parser a
safeFromJSON

-- | Encode a 'SafeJSON' value to a file.
encodeFile :: SafeJSON a => FilePath -> a -> IO ()
encodeFile :: String -> a -> IO ()
encodeFile String
fp = String -> Value -> IO ()
forall a. ToJSON a => String -> a -> IO ()
A.encodeFile String
fp (Value -> IO ()) -> (a -> Value) -> a -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
forall a. SafeJSON a => a -> Value
safeToJSON