{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Waargonaut.Encode.Types
(
EncoderFns (..)
, Encoder
, Encoder'
, ObjEncoder
, ObjEncoder'
, runEncoder
, runPureEncoder
, jsonEncoder
, objEncoder
, generaliseEncoder
) where
import Control.Monad (Monad)
import Control.Monad.Morph (MFunctor (..),
generalize)
import Control.Applicative (Applicative, liftA2,
pure)
import Control.Category (id, (.))
import Control.Lens (( # ))
import Data.Either (either)
import Data.Function (const, ($))
import Data.Functor (Functor)
import Data.Functor.Contravariant (Contravariant (..))
import Data.Functor.Contravariant.Divisible (Decidable (..),
Divisible (..))
import Data.Monoid (mempty)
import Data.Semigroup ((<>))
import Data.Void (absurd)
import Data.Functor (fmap)
import Data.Functor.Identity (Identity (..))
import Waargonaut.Types (JObject, Json, WS, _JObj)
data EncoderFns i f a = EncoderFns
{ finaliseEncoding :: i -> Json
, initialEncoding :: a -> f i
}
instance MFunctor (EncoderFns i) where
hoist nat (EncoderFns f i) = EncoderFns f (nat . i)
generaliseEncoder :: Monad f => EncoderFns i Identity a -> EncoderFns i f a
generaliseEncoder (EncoderFns f i) = EncoderFns f (generalize . i)
instance Contravariant (EncoderFns o f) where
contramap f e = EncoderFns (finaliseEncoding e) (initialEncoding e . f)
{-# INLINE contramap #-}
instance Applicative f => Divisible (EncoderFns (JObject WS Json) f) where
conquer = objEncoder (const (pure mempty))
{-# INLINE conquer #-}
divide atobc (EncoderFns _ oB) (EncoderFns _ oC) = objEncoder $ \a ->
let
(b,c) = atobc a
in
liftA2 (<>) (oB b) (oC c)
{-# INLINE divide #-}
instance Applicative f => Decidable (EncoderFns (JObject WS Json) f) where
lose f = objEncoder $ \a -> absurd (f a)
{-# INLINE lose #-}
choose split (EncoderFns _ oB) (EncoderFns _ oC) = objEncoder $ \a ->
either oB oC (split a)
{-# INLINE choose #-}
type Encoder f a = EncoderFns Json f a
type ObjEncoder f a = EncoderFns (JObject WS Json) f a
type Encoder' a = EncoderFns Json Identity a
type ObjEncoder' a = EncoderFns (JObject WS Json) Identity a
runEncoder :: Functor f => EncoderFns i f a -> a -> f Json
runEncoder e = fmap (finaliseEncoding e) . initialEncoding e
{-# INLINE runEncoder #-}
runPureEncoder :: EncoderFns i Identity a -> a -> Json
runPureEncoder e = runIdentity . fmap (finaliseEncoding e) . initialEncoding e
{-# INLINE runPureEncoder #-}
jsonEncoder :: (a -> f Json) -> EncoderFns Json f a
jsonEncoder = EncoderFns id
{-# INLINE jsonEncoder #-}
objEncoder :: (a -> f (JObject WS Json)) -> EncoderFns (JObject WS Json) f a
objEncoder = EncoderFns (\o -> _JObj # (o, mempty))
{-# INLINE objEncoder #-}