module Data.Codec.Codec
(
Codec'(..), Codec
, (>-<)
, ConcreteCodec, concrete, parseVal, produceVal
, PartialCodec, cbuild, assume, covered, (<->), produceMaybe
, opt, mapCodec, mapCodecF, mapCodecM
)
where
import Control.Applicative
import Control.Monad ((>=>))
import Control.Monad.Reader (ReaderT(..))
import Data.Codec.Field
import Data.Functor.Compose
import Data.Maybe (fromMaybe)
data Codec' fr fw w r = Codec
{ parse :: fr r
, produce :: w -> fw ()
}
deriving Functor
type Codec fr fw a = Codec' fr fw a a
instance (Applicative fw, Applicative fr) => Applicative (Codec' fr fw w) where
pure x = Codec (pure x) (const $ pure ())
Codec f fw <*> Codec x xw
= Codec (f <*> x) (\w -> fw w *> xw w)
(>-<) :: Functor fr => Field r a x y -> Codec fr fw a -> Build r (Codec' fr fw r) x y
Field c g >-< Codec r w
= Build (c <$> Codec r (w . g))
opt :: (Alternative fr, Applicative fw) => Codec fr fw a -> Codec fr fw (Maybe a)
opt (Codec r w) = Codec (optional r) (maybe (pure ()) w)
mapCodec :: Functor fr => (a -> b) -> (b -> a) -> Codec fr fw a -> Codec fr fw b
mapCodec to from (Codec r w)
= Codec (to <$> r) (w . from)
mapCodecM :: (Monad fr, Monad fw) => (a -> fr b) -> (b -> fw a) -> Codec fr fw a -> Codec fr fw b
mapCodecM to from (Codec r w)
= Codec (r >>= to) (from >=> w)
mapCodecF :: (fr a -> gr a) -> (fw () -> gw ()) -> Codec fr fw a -> Codec gr gw a
mapCodecF fr fw (Codec r w)
= Codec (fr r) (fw . w)
type ConcreteCodec b f a = Codec (ReaderT b f) (Const b) a
concrete :: (b -> f a) -> (a -> b) -> ConcreteCodec b f a
concrete r w = Codec (ReaderT r) (Const . w)
parseVal :: ConcreteCodec b f a -> b -> f a
parseVal (Codec r _) = runReaderT r
produceVal :: ConcreteCodec b f a -> a -> b
produceVal (Codec _ w) = getConst . w
type PartialCodec fr fw a = Codec fr (Compose Maybe fw) a
cbuild :: (Functor fr, Buildable r y)
=> Con r x -> Build r (Codec' fr fw r) x y -> PartialCodec fr fw r
cbuild (Con c p) = assume p . build c
assume :: (a -> Bool) -> Codec fr fw a -> PartialCodec fr fw a
assume p (Codec r w)
= Codec r (\x -> Compose $ if p x then Just (w x) else Nothing)
covered :: PartialCodec fr fw a -> Codec fr fw a
covered cd
= Codec (parse cd) (fromMaybe (error "Could not serialize value.") . produceMaybe cd)
(<->) :: Alternative fr => PartialCodec fr fw a -> PartialCodec fr fw a -> PartialCodec fr fw a
cd <-> acd = Codec
{ parse = parse cd <|> parse acd
, produce = \x -> Compose $ produceMaybe cd x <|> produceMaybe acd x
}
produceMaybe :: PartialCodec fr fw a -> a -> Maybe (fw ())
produceMaybe (Codec _ w) x
= getCompose (w x)