Module ByteListReader : READER.
Definition t (A : Type) := list byte -> option (A * list byte).
Definition unwrap {A} (x : t A) := x.
Definition getByte (l : list byte) :=
match l with
| [] => None
| b :: l => Some (b, l)
end.
Definition ret {A} (a : A) : t A := fun s => Some (a, s).
Definition bind {A B} (m : t A) (f : A -> t B) : t B :=
fun s => match m s with None => None
| Some (a, s') => f a s'
end.
Definition map {A B} (f : A -> B) (d : t A) : t B :=
bind d (fun a => ret (f a)).
Definition error {A} : t A :=
fun l => None.
Fixpoint fold {S A}
(f : byte -> S -> fold_state S A) (s : S) (l : list byte) :=
match l with
| [] => None
| b :: l => match f b s with
| Done a => Some (a, l)
| More s => fold f s l
| Error => None
end
end.
End ByteListReader.
Arguments ByteListReader.error {_}.
Notation serialize_deserialize_id_spec s d :=
(forall a bytes,
ByteListReader.unwrap d (IOStreamWriter.unwrap (s a) ++ bytes) = Some(a, bytes)).
(* This is the class of serializable types, which is the main entrypoint to Cheerios. Instances are required to show that `deserialize` can correctly recognize a piece of `serialize`d data at the prefix of an arbitrary bitstream. *)
Class Serializer (A : Type) : Type :=
{
serialize : A -> IOStreamWriter.t;
deserialize : ByteListReader.t A;
serialize_deserialize_id : serialize_deserialize_id_spec serialize deserialize
}.
Hint Rewrite @serialize_deserialize_id : cheerios.

(* In particular, if there is nothing else in the bitsream, then deserialize and serialize are inverses. *)
Lemma serialize_deserialize_id_nil :
forall A (sA : Serializer A) a,
ByteListReader.unwrap deserialize (IOStreamWriter.unwrap (serialize a)) = Some (a, []).