{-# LANGUAGE CPP                   #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Trustworthy           #-}
{-# OPTIONS_GHC -Wno-orphans #-}
--------------------------------------------------------------------
-- |
-- Module    : Data.MessagePack
-- Copyright : (c) Hideyuki Tanaka, 2009-2015
-- License   : BSD3
--
-- Maintainer:  tanaka.hideyuki@gmail.com
-- Stability :  experimental
-- Portability: portable
--
-- Simple interface to pack and unpack MessagePack data.
--
--------------------------------------------------------------------

module Data.MessagePack (
  -- * Simple interface to pack and unpack msgpack binary
    pack
  , unpack
  , unpackEither
  , unpackValidate

  -- * Re-export modules
  -- $reexports
  , module X
  ) where

import           Control.Applicative    (Applicative)
import           Control.Monad          ((>=>))
import           Control.Monad.Validate (MonadValidate, refute, runValidate)
import qualified Data.ByteString.Lazy   as L
import qualified Data.Persist           as P

import           Data.MessagePack.Get   as X
import           Data.MessagePack.Put   as X
import           Data.MessagePack.Types as X


-- | Pack a Haskell value to MessagePack binary.
pack :: MessagePack a => a -> L.ByteString
pack :: a -> ByteString
pack = ByteString -> ByteString
L.fromStrict (ByteString -> ByteString) -> (a -> ByteString) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put () -> ByteString
forall a. Put a -> ByteString
P.runPut (Put () -> ByteString) -> (a -> Put ()) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Object -> Put ()
forall t. Persist t => t -> Put ()
P.put (Object -> Put ()) -> (a -> Object) -> a -> Put ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Config -> a -> Object
forall a. MessagePack a => Config -> a -> Object
toObject Config
defaultConfig

-- | Unpack MessagePack binary to a Haskell value.
--
-- On failure, returns a list of error messages.
unpackValidate :: (MonadValidate DecodeError m, MessagePack a)
               => L.ByteString -> m a
unpackValidate :: ByteString -> m a
unpackValidate ByteString
bs = (Either String Object -> m Object
forall (m :: * -> *) a.
MonadValidate DecodeError m =>
Either String a -> m a
eitherToM (Either String Object -> m Object)
-> (ByteString -> Either String Object) -> ByteString -> m Object
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get Object -> ByteString -> Either String Object
forall a. Get a -> ByteString -> Either String a
P.runGet Get Object
forall t. Persist t => Get t
P.get (ByteString -> Either String Object)
-> (ByteString -> ByteString) -> ByteString -> Either String Object
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
L.toStrict) ByteString
bs m Object -> (Object -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Config -> Object -> m a
forall a (m :: * -> *).
(MessagePack a, Applicative m, Monad m,
 MonadValidate DecodeError m) =>
Config -> Object -> m a
fromObjectWith Config
defaultConfig
  where
    eitherToM :: Either String a -> m a
eitherToM (Left  String
msg) = DecodeError -> m a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
refute (DecodeError -> m a) -> DecodeError -> m a
forall a b. (a -> b) -> a -> b
$ String -> DecodeError
decodeError String
msg
    eitherToM (Right a
res) = a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
res


unpackEither :: (MessagePack a)
             => L.ByteString -> Either DecodeError a
unpackEither :: ByteString -> Either DecodeError a
unpackEither = Validate DecodeError a -> Either DecodeError a
forall e a. Validate e a -> Either e a
runValidate (Validate DecodeError a -> Either DecodeError a)
-> (ByteString -> Validate DecodeError a)
-> ByteString
-> Either DecodeError a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Validate DecodeError a
forall (m :: * -> *) a.
(MonadValidate DecodeError m, MessagePack a) =>
ByteString -> m a
unpackValidate

-- | Unpack MessagePack binary to a Haskell value. If it fails, it fails in the
-- Monad. In the Maybe monad, failure returns Nothing.
#if (MIN_VERSION_base(4,13,0))
unpack :: (Applicative m, Monad m, MonadFail m, MessagePack a)
#else
unpack :: (Applicative m, Monad m, MessagePack a)
#endif
       => L.ByteString -> m a
unpack :: ByteString -> m a
unpack = Either DecodeError a -> m a
forall (m :: * -> *) a a.
(MonadFail m, Show a) =>
Either a a -> m a
eitherToM (Either DecodeError a -> m a)
-> (ByteString -> Either DecodeError a) -> ByteString -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either DecodeError a
forall a. MessagePack a => ByteString -> Either DecodeError a
unpackEither
  where
    eitherToM :: Either a a -> m a
eitherToM (Left a
msgs) = String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ a -> String
forall a. Show a => a -> String
show a
msgs
    eitherToM (Right a
res) = a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
res

instance P.Persist Object where
    get :: Get Object
get = Get Object
getObject
    {-# INLINE get #-}

    put :: Object -> Put ()
put = Object -> Put ()
putObject
    {-# INLINE put #-}