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.
(* top-level interface for wire type *)
Definition serialize_top (s : IOStreamWriter.t) : IOStreamWriter.wire :=
IOStreamWriter.wire_wrap s.
Definition deserialize_top {A: Type}
(d : ByteListReader.t A) (w : IOStreamWriter.wire) : option A :=
match ByteListReader.unwrap d (IOStreamWriter.wire_unwrap w) with
| Some (a, []) => Some a
| _ => None
end.

Axiom wire_serialize : IOStreamWriter.wire -> IOStreamWriter.t.
Axiom wire_deserialize : ByteListReader.t IOStreamWriter.wire.
Axiom wire_serialize_deserialize_id :
serialize_deserialize_id_spec wire_serialize wire_deserialize.