-- | JSON serialisation
--
module Cardano.Api.SerialiseJSON
  ( serialiseToJSON
  , ToJSON(..)
  , ToJSONKey
  , deserialiseFromJSON
  , prettyPrintJSON
  , FromJSON(..)
  , FromJSONKey
  , JsonDecodeError(..)
  , readFileJSON
  , writeFileJSON
  ) where

import           Control.Monad.Trans.Except (runExceptT)
import           Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, hoistEither)
import           Data.Aeson (FromJSON (..), FromJSONKey, ToJSON (..), ToJSONKey)
import qualified Data.Aeson as Aeson
import           Data.Aeson.Encode.Pretty (encodePretty)
import           Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS

import           Cardano.Api.Error
import           Cardano.Api.HasTypeProxy


newtype JsonDecodeError = JsonDecodeError String
  deriving (JsonDecodeError -> JsonDecodeError -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: JsonDecodeError -> JsonDecodeError -> Bool
$c/= :: JsonDecodeError -> JsonDecodeError -> Bool
== :: JsonDecodeError -> JsonDecodeError -> Bool
$c== :: JsonDecodeError -> JsonDecodeError -> Bool
Eq, Int -> JsonDecodeError -> ShowS
[JsonDecodeError] -> ShowS
JsonDecodeError -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [JsonDecodeError] -> ShowS
$cshowList :: [JsonDecodeError] -> ShowS
show :: JsonDecodeError -> String
$cshow :: JsonDecodeError -> String
showsPrec :: Int -> JsonDecodeError -> ShowS
$cshowsPrec :: Int -> JsonDecodeError -> ShowS
Show)

instance Error JsonDecodeError where
  displayError :: JsonDecodeError -> String
displayError (JsonDecodeError String
err) = String
err


serialiseToJSON :: ToJSON a => a -> ByteString
serialiseToJSON :: forall a. ToJSON a => a -> ByteString
serialiseToJSON = ByteString -> ByteString
LBS.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToJSON a => a -> ByteString
Aeson.encode

prettyPrintJSON :: ToJSON a => a -> ByteString
prettyPrintJSON :: forall a. ToJSON a => a -> ByteString
prettyPrintJSON = ByteString -> ByteString
LBS.toStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToJSON a => a -> ByteString
encodePretty

deserialiseFromJSON :: FromJSON a
                    => AsType a
                    -> ByteString
                    -> Either JsonDecodeError a
deserialiseFromJSON :: forall a.
FromJSON a =>
AsType a -> ByteString -> Either JsonDecodeError a
deserialiseFromJSON AsType a
_proxy = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. a -> Either a b
Left forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> JsonDecodeError
JsonDecodeError) forall a b. b -> Either a b
Right
                           forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromJSON a => ByteString -> Either String a
Aeson.eitherDecodeStrict'


readFileJSON :: FromJSON a
             => AsType a
             -> FilePath
             -> IO (Either (FileError JsonDecodeError) a)
readFileJSON :: forall a.
FromJSON a =>
AsType a -> String -> IO (Either (FileError JsonDecodeError) a)
readFileJSON AsType a
ttoken String
path =
    forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$ do
      ByteString
content <- forall (m :: * -> *) x a.
MonadIO m =>
(IOException -> x) -> IO a -> ExceptT x m a
handleIOExceptT (forall e. String -> IOException -> FileError e
FileIOError String
path) forall a b. (a -> b) -> a -> b
$ String -> IO ByteString
BS.readFile String
path
      forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT (forall e. String -> e -> FileError e
FileError String
path) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) x a. Monad m => Either x a -> ExceptT x m a
hoistEither forall a b. (a -> b) -> a -> b
$
        forall a.
FromJSON a =>
AsType a -> ByteString -> Either JsonDecodeError a
deserialiseFromJSON AsType a
ttoken ByteString
content

writeFileJSON :: ToJSON a
              => FilePath
              -> a
              -> IO (Either (FileError ()) ())
writeFileJSON :: forall a. ToJSON a => String -> a -> IO (Either (FileError ()) ())
writeFileJSON String
path a
x =
    forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$
      forall (m :: * -> *) x a.
MonadIO m =>
(IOException -> x) -> IO a -> ExceptT x m a
handleIOExceptT (forall e. String -> IOException -> FileError e
FileIOError String
path) forall a b. (a -> b) -> a -> b
$
        String -> ByteString -> IO ()
BS.writeFile String
path (forall a. ToJSON a => a -> ByteString
serialiseToJSON a
x)