Safe Haskell | Safe-Inferred |
---|---|

Language | Haskell2010 |

## Synopsis

- data Decode (w ∷ Wrapped) t where
- RecD ∷ t → Decode ('Closed 'Dense) t
- SumD ∷ t → Decode 'Open t
- Summands ∷ Text → (Word → Decode 'Open t) → Decode ('Closed 'Dense) t
- SparseKeyed ∷ Typeable t ⇒ String → t → (Word → Field t) → [(Word, String)] → Decode ('Closed 'Dense) t
- KeyedD ∷ t → Decode ('Closed 'Sparse) t
- From ∷ DecCBOR t ⇒ Decode w t
- D ∷ (∀ s. Decoder s t) → Decode ('Closed 'Dense) t
- ApplyD ∷ Decode w1 (a → t) → Decode ('Closed d) a → Decode w1 t
- Invalid ∷ Word → Decode w t
- Map ∷ (a → b) → Decode w a → Decode w b
- TagD ∷ Word → Decode ('Closed x) t → Decode ('Closed x) t
- Emit ∷ t → Decode w t
- Ann ∷ Decode w t → Decode w (Annotator t)
- ApplyAnn ∷ Decode w1 (Annotator (a → t)) → Decode ('Closed d) (Annotator a) → Decode w1 (Annotator t)
- ApplyErr ∷ Decode w1 (a → Either String t) → Decode ('Closed d) a → Decode w1 t

- (<!) ∷ Decode w1 (a → t) → Decode ('Closed w) a → Decode w1 t
- (<*!) ∷ Decode w1 (Annotator (a → t)) → Decode ('Closed d) (Annotator a) → Decode w1 (Annotator t)
- (<?) ∷ Decode w1 (a → Either String t) → Decode ('Closed d) a → Decode w1 t
- decode ∷ Decode w t → Decoder s t
- decodeSparse ∷ Typeable a ⇒ String → a → (Word → Field a) → [(Word, String)] → Decoder s a
- data Density
- data Wrapped where
- data Field t where
- ofield ∷ (StrictMaybe x → t → t) → Decode ('Closed d) x → Field t
- invalidField ∷ ∀ t. Word → Field t
- field ∷ (x → t → t) → Decode ('Closed d) x → Field t
- fieldGuarded ∷ String → (x → Bool) → (x → t → t) → Decode ('Closed d) x → Field t
- fieldA ∷ Applicative ann ⇒ (x → t → t) → Decode ('Closed d) x → Field (ann t)
- fieldAA ∷ Applicative ann ⇒ (x → t → t) → Decode ('Closed d) (ann x) → Field (ann t)
- decodeDual ∷ ∀ t. (EncCBOR t, DecCBOR t) ⇒ Decode ('Closed 'Dense) t
- listDecodeA ∷ Decode ('Closed 'Dense) (Annotator x) → Decode ('Closed 'Dense) (Annotator [x])
- mapDecodeA ∷ Ord k ⇒ Decode ('Closed 'Dense) (Annotator k) → Decode ('Closed 'Dense) (Annotator v) → Decode ('Closed 'Dense) (Annotator (Map k v))
- setDecodeA ∷ Ord x ⇒ Decode ('Closed 'Dense) (Annotator x) → Decode ('Closed 'Dense) (Annotator (Set x))
- decodeRecordNamed ∷ Text → (a → Int) → Decoder s a → Decoder s a
- decodeRecordNamedT ∷ (MonadTrans m, Monad (m (Decoder s))) ⇒ Text → (a → Int) → m (Decoder s) a → m (Decoder s) a
- decodeRecordSum ∷ Text → (Word → Decoder s (Int, a)) → Decoder s a
- invalidKey ∷ MonadFail m ⇒ Word → m a
- unusedRequiredKeys ∷ Set Word → [(Word, String)] → String → Decoder s a
- duplicateKey ∷ String → Word → Decoder s a
- guardUntilAtLeast ∷ DecCBOR a ⇒ String → Version → Decode ('Closed 'Dense) a

# Creating decoders.

data Decode (w ∷ Wrapped) t where Source #

The type `(`

is designed to be dual to `Decode`

t)`(`

. It was designed so that
in many cases a decoder can be extracted from an encoder by visual inspection. We now give some
example of `Encode`

t)`(Decode t)`

and `(Encode t)`

pairs.

An example with 1 constructor (a record) uses `Rec`

and `RecD`

In this example, let `Int`

and `C`

have `EncCBOR`

instances.

data C = C { unC :: Text.Text } instance EncCBOR C where encCBOR (C t) = encCBOR t instance DecCBOR C where decCBOR = C $ decCBOR data B = B { unB :: Text.Text } data A = ACon Int B C encodeA :: A -> Encode ('Closed 'Dense) A encodeA (ACon i b c) = Rec ACon !> To i !> E (encCBOR . unB) b !> To c decodeA :: Decode ('Closed 'Dense) A decodeA = RecD ACon From <! D (B <$ decCBOR) <! From instance EncCBOR A where encCBOR = encode . encodeA instance DecCBOR A where decCBOR = decode decodeA

An example with multiple constructors uses `Sum`

, `SumD`

, and `Summands`

.

data N = N1 Int | N2 B Bool | N3 A encodeN :: N -> Encode 'Open N encodeN (N1 i) = Sum N1 0 !> To i encodeN (N2 b tf) = Sum N2 1 !> E (encCBOR . unB) b !> To tf encodeN (N3 a) = Sum N3 2 !> To a decodeN :: Decode ('Closed 'Dense) N -- Note each clause has an 'Open decoder, decodeN = Summands N decodeNx -- But Summands returns a ('Closed 'Dense) decoder where decodeNx 0 = SumD N1 <! From decodeNx 1 = SumD N2 D (B <$ decCBOR) <! From decodeNx 3 = SumD N3 <! From decodeNx k = Invalid k instance EncCBOR N where encCBOR x = encode(encodeN x) instance DecCBOR N where decCBOR = decode decodeN

Two examples using variants of sparse encoding for records, i.e. those datatypes with only one constructor.
The Virtual constructor approach using `Summands`

, `OmitC`

, `Emit`

.
The Sparse field approach using `Keyed`

, `Key`

and `Omit`

. The approaches work
because encoders and decoders don't put
fields with default values in the Encoding, and reconstruct the default values on the decoding side.
We will illustrate the two approaches using the datatype M

data M = M Int [Bool] Text.Text deriving (Show, Typeable) a0, a1, a2, a3 :: M -- Some illustrative examples, using things that might be given default values. a0 = M 0 [] ABC a1 = M 0 [True] ABC a2 = M 9 [] ABC a3 = M 9 [False] ABC

The virtual constructor strategy pretends there are mutiple constructors
Even though there is only one. We use invariants about the data to avoid
encoding some of the values. Note the use of `Sum`

with virtual constructor tags 0,1,2,3

```
encM :: M -> Encode 'Open M
encM (M 0 [] t) = Sum M 0 !> OmitC 0 !> OmitC [] !> To t
encM (M 0 bs t) = Sum M 1 !> OmitC 0 !> To bs !> To t
encM (M n [] t) = Sum M 2 !> To n !> OmitC [] !> To t
encM (M n bs t) = Sum M 3 !> To n !> To bs !> To t
decM :: Word -> Decode 'Open M
decM 0 = SumD M <! Emit 0 <! Emit [] <! From -- The virtual constructors tell which fields have been Omited
decM 1 = SumD M <! Emit 0 <! From <! From -- So those fields are reconstructed using
````Emit`

.
decM 2 = SumD M <! From <! Emit [] <! From
decM 3 = SumD M <! From <! From <! From
decM n = Invalid n
instance EncCBOR M where
encCBOR m = encode (encM m)
instance DecCBOR M where
decCBOR = decode (Summands M decM)

The Sparse field approach uses N keys, one for each field that is not defaulted. For example
`(M 9 [True] (pack "hi")))`

. Here zero fields are defaulted, so there should be 3 keys.
Encoding this example would look something like this.

[TkMapLen 3,TkInt 0,TkInt 9,TkInt 1,TkListBegin,TkBool True,TkBreak,TkInt 2,TkString "hi"] ^key ^key ^key

So the user supplies a function, that encodes every field, each field must use a unique
key, and fields with default values have Omit wrapped around the Key encoding.
The user must ensure that there is NOT an Omit on a required field. `encM2`

is an example.

encM2:: M -> Encode ('Closed 'Sparse) M encM2 (M n xs t) = Keyed M !> Omit (== 0) (Key 0 (To n)) -- Omit if n is zero !> Omit null (Key 1 (To xs)) -- Omit if xs is null !> Key 2 (To t) -- Always encode t

To write an Decoder we must pair a decoder for each field, with a function that updates only
that field. We use the `Field`

GADT to construct these pairs, and we must write a function, that
for each field tag, picks out the correct pair. If the Encode and Decode don't agree on how the
tags correspond to a particular field, things will fail.

boxM :: Word -> Field M boxM 0 = field update0 From where update0 n (M _ xs t) = M n xs t boxM 1 = field update1 From where update1 xs (M n _ t) = M n xs t boxM 2 = field update2 From where update2 t (M n xs _) = M n xs t boxM n = invalidField n

Finally there is a new constructor for `Decode`

, called `SparseKeyed`

, that decodes field
keyed sparse objects. The user supplies an initial value and field function, and a list
of tags of the required fields. The initial value should have default values and
any well type value in required fields. If the encode function (baz above) is
encoded properly the required fields in the initial value should always be over
overwritten. If it is not written properly, or a bad encoding comes from somewhere
else, the intial values in the required fields might survive decoding. The list
of required fields is checked.

instance DecCBOR M where decCBOR = decode (SparseKeyed TT -- ^ Name of the type being decoded (M 0 [] (Text.pack "a")) -- ^ The default value boxM -- ^ The Field function [(2, Stringpart)] -- ^ The required Fields ) instance EncCBOR M where encCBOR m = encode(encM2 m)

RecD ∷ t → Decode ('Closed 'Dense) t | Label the constructor of a Record-like datatype (one with exactly 1 constructor) as a Decode. |

SumD ∷ t → Decode 'Open t | Label the constructor of a Record-like datatype (one with multiple constructors) as an Decode. |

Summands ∷ Text → (Word → Decode 'Open t) → Decode ('Closed 'Dense) t | Lift a Word to Decode function into a DeCode for a type with multiple constructors. |

SparseKeyed | Lift a Word to Field function into a DeCode for a type with 1 constructor stored sparsely |

KeyedD ∷ t → Decode ('Closed 'Sparse) t | Label a (component, field, argument) as sparsely stored, which will be populated with the default value. |

From ∷ DecCBOR t ⇒ Decode w t | Label a (component, field, argument). It will be decoded using the existing
DecCBOR instance at |

D ∷ (∀ s. Decoder s t) → Decode ('Closed 'Dense) t | Label a (component, field, argument). It will be decoded using the given decoder. |

ApplyD ∷ Decode w1 (a → t) → Decode ('Closed d) a → Decode w1 t | Apply a functional decoding (arising from |

Invalid ∷ Word → Decode w t | Mark a Word as a Decoding which is not a valid Decoding. Used when decoding sums that are tagged out of range. |

Map ∷ (a → b) → Decode w a → Decode w b | Used to make (Decode w) an instance of Functor. |

TagD ∷ Word → Decode ('Closed x) t → Decode ('Closed x) t | Assert that the next thing decoded must be tagged with the given word. |

Emit ∷ t → Decode w t | Decode the next thing, not by inspecting the bytes, but pulled out of thin air,
returning |

Ann ∷ Decode w t → Decode w (Annotator t) | Lift a |

ApplyAnn | Apply a functional decoding (arising from |

ApplyErr ∷ Decode w1 (a → Either String t) → Decode ('Closed d) a → Decode w1 t | the function to Either can raise an error when applied by returning (Left errorMessage) |

#### Instances

Applicative (Decode ('Closed d)) Source # | |

Defined in Cardano.Ledger.Binary.Decoding.Coders pure ∷ a → Decode ('Closed d) a Source # (<*>) ∷ Decode ('Closed d) (a → b) → Decode ('Closed d) a → Decode ('Closed d) b Source # liftA2 ∷ (a → b → c) → Decode ('Closed d) a → Decode ('Closed d) b → Decode ('Closed d) c Source # (*>) ∷ Decode ('Closed d) a → Decode ('Closed d) b → Decode ('Closed d) b Source # (<*) ∷ Decode ('Closed d) a → Decode ('Closed d) b → Decode ('Closed d) a Source # | |

Functor (Decode w) Source # | |

(<!) ∷ Decode w1 (a → t) → Decode ('Closed w) a → Decode w1 t infixl 4 Source #

Infix form of `ApplyD`

with the same infixity and precedence as `($)`

.

(<*!) ∷ Decode w1 (Annotator (a → t)) → Decode ('Closed d) (Annotator a) → Decode w1 (Annotator t) infixl 4 Source #

Infix form of `ApplyAnn`

with the same infixity and precedence as `($)`

.

(<?) ∷ Decode w1 (a → Either String t) → Decode ('Closed d) a → Decode w1 t infixl 4 Source #

Infix form of `ApplyErr`

with the same infixity and precedence as `($)`

.

# Index types for well-formed Coders.

Some CBOR instances wrap encoding sequences with prefixes and suffixes. I.e.
prefix , encode, encode, encode , ... , suffix.
There are two kinds of wrapping coders: Nary sums, and Sparsely encoded products.
Coders in these classes can only be decoded when they are wrapped by their
closing forms `Summands`

and `SparseKeyed`

. Another dimension, where we use indexes
to maintain type safety, are records which can be
encoded densely (all their fields serialised) or sparsely (only some of their
fields). We use indexes to types to try and mark (and enforce) these distinctions.

Index for record density. Distinguishing (all the fields) from (some of the fields).

Index for a wrapped Coder. Wrapping is necessary for `Summands`

and `SparseKeyed`

.

A Field pairs an update function and a decoder for one field of a Sparse record.

invalidField ∷ ∀ t. Word → Field t Source #

fieldA ∷ Applicative ann ⇒ (x → t → t) → Decode ('Closed d) x → Field (ann t) Source #

Sparse decode something with a (DecCBOR (Annotator t)) instance
A special case of `field`

fieldAA ∷ Applicative ann ⇒ (x → t → t) → Decode ('Closed d) (ann x) → Field (ann t) Source #

Sparse decode something with a (DecCBOR (Annotator t)) instance

# Using Duals

decodeDual ∷ ∀ t. (EncCBOR t, DecCBOR t) ⇒ Decode ('Closed 'Dense) t Source #

Use `encodeDual`

and `decodeDual`

, when you want to
guarantee that a type has both `EncCBOR`

and `FromCBR`

instances.

# Containers, Combinators

listDecodeA ∷ Decode ('Closed 'Dense) (Annotator x) → Decode ('Closed 'Dense) (Annotator [x]) Source #

mapDecodeA ∷ Ord k ⇒ Decode ('Closed 'Dense) (Annotator k) → Decode ('Closed 'Dense) (Annotator v) → Decode ('Closed 'Dense) (Annotator (Map k v)) Source #

setDecodeA ∷ Ord x ⇒ Decode ('Closed 'Dense) (Annotator x) → Decode ('Closed 'Dense) (Annotator (Set x)) Source #

# Low level (Encoding/Decoder) utility functions

decodeRecordNamedT ∷ (MonadTrans m, Monad (m (Decoder s))) ⇒ Text → (a → Int) → m (Decoder s) a → m (Decoder s) a Source #

invalidKey ∷ MonadFail m ⇒ Word → m a Source #

Report an error when a numeric key of the type constructor doesn't match.