typed-protocols-stateful
Safe HaskellNone
LanguageHaskell2010

Network.TypedProtocol.Stateful.Codec

Description

Stateful codec. This module is intended to be imported qualified.

Synopsis

Defining and using Codecs

data Codec ps failure (f :: ps -> Type) (m :: Type -> Type) bytes Source #

A stateful codec.

Constructors

Codec 

Fields

hoistCodec :: forall n m ps failure (f :: ps -> Type) bytes. Functor n => (forall x. m x -> n x) -> Codec ps failure f m bytes -> Codec ps failure f n bytes Source #

isoCodec :: forall (m :: Type -> Type) bytes bytes' ps failure (f :: ps -> Type). Functor m => (bytes -> bytes') -> (bytes' -> bytes) -> Codec ps failure f m bytes -> Codec ps failure f m bytes' Source #

mapFailureCodec :: forall (m :: Type -> Type) failure failure' ps (f :: ps -> Type) bytes. Functor m => (failure -> failure') -> Codec ps failure f m bytes -> Codec ps failure' f m bytes Source #

liftCodec :: forall ps failure (m :: Type -> Type) bytes (f :: ps -> Type). Codec ps failure m bytes -> Codec ps failure f m bytes Source #

Incremental decoding

data DecodeStep bytes failure (m :: Type -> Type) a #

An incremental decoder with return a value of type a.

This interface is not designed to be used directly for implementing decoders, only for running them. In real applications it is expected to use libraries for text or binary decoding and to implement appropriate wrappers to match up with this incremental decoder interface.

This style of interface already closely matches that provided by libraries such as attoparsec for text formats, and binary, cereal and cborg for binary formats.

Constructors

DecodePartial (Maybe bytes -> m (DecodeStep bytes failure m a))

The decoder has consumed the available input and needs more to continue. Provide Just if more input is available and Nothing otherwise, and you will get a new DecodeStep.

DecodeDone a (Maybe bytes)

The decoder has successfully finished. This provides the decoded result value plus any unused input.

DecodeFail failure

The decoder ran into an error. The decoder either used fail or was not provided enough input.

runDecoder #

Arguments

:: Monad m 
=> [bytes]

bytes to be fed into the incremental DecodeStep

-> DecodeStep bytes failure m a

decoder

-> m (Either failure a) 

Run a codec incremental decoder DecodeStep against a list of input.

It ignores any unused trailing data. This is useful for demos, quick experiments and tests.

See also runDecoderWithChannel

runDecoderPure #

Arguments

:: Monad m 
=> (forall b. m b -> b)

run monad m in a pure way, e.g. runIdentity

-> m (DecodeStep bytes failure m a) 
-> [bytes]

input bytes

-> Either failure a 

A variant of runDecoder that is suitable for "pure" monads that have a run function. This includes ST, using runST.

Related types

SomeMessage

data SomeMessage (st :: ps) where #

When decoding a Message we only know the expected "from" state. We cannot know the "to" state as this depends on the message we decode. To resolve this we use the SomeMessage wrapper which uses an existential type to hide the "to" state.

Constructors

SomeMessage :: forall ps (st :: ps) (st' :: ps). (StateTokenI st, StateTokenI st', ActiveState st) => Message ps st st' -> SomeMessage st 

StateToken

type family StateToken :: ps -> Type #

A type family for protocol state token, e.g. term level representation of type level state (also known as singleton).

This type family is similar to Sing type class in the "singletons" package, but specific for protocol states.

class StateTokenI (st :: ps) where #

A type class which hides a state token / singleton inside a class dictionary.

This is similar to the SingI instance, but specific to protocol state singletons.

Methods

stateToken :: StateToken st #

ActiveState

type ActiveState (st :: ps) = IsActiveState st (StateAgency st) #

A constraint which provides an evidence that the protocol isn't in a terminal state.

PeerRole

data PeerRole #

Types for client and server peer roles. As protocol can be viewed from either client or server side.

Note that technically "client" and "server" are arbitrary labels. The framework is completely symmetric between the two peers.

This definition is only used as promoted types and kinds, never as values.

Constructors

AsClient 
AsServer 

Instances

Instances details
SingI 'AsClient 
Instance details

Defined in Network.TypedProtocol.Core

Methods

sing :: Sing 'AsClient #

SingI 'AsServer 
Instance details

Defined in Network.TypedProtocol.Core

Methods

sing :: Sing 'AsServer #

type Sing 
Instance details

Defined in Network.TypedProtocol.Core

CodecFailure

data CodecFailure #

Each Codec can use whatever failure type is appropriate. This simple exception type is provided for use by simple codecs (e.g. "identity") when nothing more than a String is needed. It is an instance of Exception.

Testing codec properties

data AnyMessage ps (f :: ps -> Type) where Source #

Any message for a protocol, with a StateTokenI constraint which gives access to protocol state.

Used where we don't know statically what the state type is, but need the agency and message to match each other.

Constructors

AnyMessage 

Fields

Bundled Patterns

pattern AnyMessageAndAgency :: forall ps f (st :: ps) (st' :: ps). () => (StateTokenI st, ActiveState st) => StateToken st -> f st -> Message ps st st' -> AnyMessage ps f

A convenient pattern synonym which unwrap AnyMessage giving both the singleton for the state and the message.

showAnyMessage :: forall ps (f :: ps -> Type). (forall (st :: ps) (st' :: ps). Show (Message ps st st'), forall (st :: ps). Show (f st)) => AnyMessage ps f -> String Source #

showAnyMessage is can be used to provide Show instance for AnyMessage if showing Message is independent of the state or one accepts showing only partial information included in message constructors or accepts message constructors to carry Show instances for its arguments. Note that the proper solution is to define a custom `Show (AnyMessage ps f)` instance for a protocol ps, which give access to the state functor f in scope of show.

prop_codecM :: forall ps failure (f :: ps -> Type) m bytes. (Monad m, Eq (AnyMessage ps f)) => Codec ps failure f m bytes -> AnyMessage ps f -> m Bool Source #

The Codec round-trip property: decode after encode gives the same message. Every codec must satisfy this property.

prop_codec :: forall ps failure (f :: ps -> Type) m bytes. (Monad m, Eq (AnyMessage ps f)) => (forall a. m a -> a) -> Codec ps failure f m bytes -> AnyMessage ps f -> Bool Source #

The Codec round-trip property in a pure monad.

prop_codec_splitsM Source #

Arguments

:: forall ps failure (f :: ps -> Type) m bytes. (Monad m, Eq (AnyMessage ps f)) 
=> (bytes -> [[bytes]])

alternative re-chunkings of serialised form

-> Codec ps failure f m bytes 
-> AnyMessage ps f 
-> m Bool 

A variant on the codec round-trip property: given the encoding of a message, check that decode always gives the same result irrespective of how the chunks of input are fed to the incremental decoder.

This property guards against boundary errors in incremental decoders. It is not necessary to check this for every message type, just for each generic codec construction. For example given some binary serialisation library one would write a generic adaptor to the codec interface. This adaptor has to deal with the incremental decoding and this is what needs to be checked.

prop_codec_splits :: forall ps failure (f :: ps -> Type) m bytes. (Monad m, Eq (AnyMessage ps f)) => (bytes -> [[bytes]]) -> (forall a. m a -> a) -> Codec ps failure f m bytes -> AnyMessage ps f -> Bool Source #

Like prop_codec_splitsM but run in a pure monad m, e.g. Identity.

prop_codecs_compatM :: forall ps failure (f :: ps -> Type) m bytes. (Monad m, Eq (AnyMessage ps f), forall a. Monoid a => Monoid (m a)) => Codec ps failure f m bytes -> Codec ps failure f m bytes -> AnyMessage ps f -> m Bool Source #

Compatibility between two codecs of the same protocol. Encode a message with one codec and decode it with the other one, then compare if the result is the same as initial message.

prop_codecs_compat :: forall ps failure (f :: ps -> Type) m bytes. (Monad m, Eq (AnyMessage ps f), forall a. Monoid a => Monoid (m a)) => (forall a. m a -> a) -> Codec ps failure f m bytes -> Codec ps failure f m bytes -> AnyMessage ps f -> Bool Source #

Like prop_codecs_compatM but run in a pure monad m, e.g. Identity.