Section BasicCombinators.
Variables A B : Type.
Variable sA : Serializer A.
Variable sB : Serializer B.
Definition option_serialize (x : option A) : IOStreamWriter.t :=
match x with
| Some a => IOStreamWriter.append (fun _ => serialize true)
(fun _ => serialize a)
| None => serialize false
end.
Definition option_deserialize : ByteListReader.t (option A) :=
b <- deserialize ;;
match b with
| true => Some <$> deserialize
| false => ByteListReader.ret None
end.
Proof using.
intros.
unfold option_serialize, option_deserialize.
destruct a;
repeat (cheerios_crush; simpl).
Qed.
Global Instance option_Serializer : Serializer (option A).
Definition pair_serialize (x : A * B) : IOStreamWriter.t :=
let (a, b) := x in IOStreamWriter.append (fun _ => serialize a)
(fun _ => serialize b).
Definition pair_deserialize : ByteListReader.t (A * B) :=
a <- deserialize ;;
b <- deserialize ;;
ByteListReader.ret (a, b).
Proof using.
intros.
unfold pair_serialize, pair_deserialize.
destruct a.
cheerios_crush.
Qed.
Global Instance pair_Serializer : Serializer (A * B).
Definition sum_serialize (x : A + B) : IOStreamWriter.t :=
match x with
| inl a => IOStreamWriter.append (fun _ => serialize true)
(fun _ => serialize a)
| inr b => IOStreamWriter.append (fun _ => serialize false)
(fun _ => serialize b)
end.
Definition sum_deserialize : ByteListReader.t (A + B) :=
b <- deserialize ;;
match b with
| true => inl <$> deserialize
| false => inr <$> deserialize
end.
Proof using.
unfold sum_serialize, sum_deserialize.
destruct a; cheerios_crush.
Qed.
Global Instance sum_Serializer : Serializer (A + B).
Fixpoint list_serialize_rec (l : list A) : IOStreamWriter.t :=
match l with
| [] => IOStreamWriter.empty
| a :: l' => IOStreamWriter.append (fun _ => serialize a)
(fun _ => list_serialize_rec l')
end.
Definition list_serialize (l : list A) : IOStreamWriter.t :=
IOStreamWriter.append (fun _ => serialize (length l))
(fun _ => list_serialize_rec l).
Fixpoint list_deserialize_rec (n : nat) : ByteListReader.t (list A) :=
match n with
| 0 => ByteListReader.ret []
| S n' => cons <$> deserialize <*> list_deserialize_rec n'
end.
Definition list_deserialize : ByteListReader.t (list A) :=
deserialize >>= list_deserialize_rec.
Proof using.
intros.
unfold list_serialize_rec.
cheerios_crush. simpl.
induction l.
- simpl. cheerios_crush.
- simpl.
rewrite sequence_rewrite.
rewrite ByteListReader.bind_unwrap.
rewrite ByteListReader.map_unwrap.
rewrite IOStreamWriter.append_unwrap.
rewrite app_ass.
rewrite serialize_deserialize_id.
rewrite ByteListReader.bind_unwrap.
rewrite IHl.
cheerios_crush.
Qed.
Proof using.
intros.
induction l.
- simpl. cheerios_crush.
rewrite app_nil_r.
reflexivity.
- simpl.
cheerios_crush.
rewrite IHl.
reflexivity.
Qed.
Proof using.
unfold list_serialize, list_deserialize.
cheerios_crush.
now rewrite list_serialize_deserialize_id_rec.
Qed.
Global Instance list_Serializer : Serializer (list A).
Fixpoint vector_serialize {n} (v : Vector.t A n) : IOStreamWriter.t :=
match v with
| Vector.nil => IOStreamWriter.empty
| Vector.cons a v' => IOStreamWriter.append (fun _ => serialize a)
(fun _ => vector_serialize v')
end.
Fixpoint vector_deserialize {n} : ByteListReader.t (Vector.t A n) :=
match n as n0 return ByteListReader.t (Vector.t A n0) with
| 0 => ByteListReader.ret Vector.nil
| S n' => a <- deserialize ;;
v <- vector_deserialize ;;
ByteListReader.ret (Vector.cons a v)
end.
Proof using.
induction n; intros.
- destruct a using Vector.case0. auto. unfold vector_serialize,  vector_deserialize.
cheerios_crush.
- destruct a using Vector.caseS'.
simpl.
cheerios_crush.
rewrite IHn.
cheerios_crush.
Qed.
Global Instance vector_Serializer n : Serializer (Vector.t A n).
End BasicCombinators.
(* This has to go here because it depends on having a serializer for lists available. *)
Fixpoint string_to_list s :=
match s with
| String.EmptyString => nil
| String.String c s' => c :: (string_to_list s')
end.
Fixpoint list_to_string l :=
match l with
| nil => String.EmptyString
| h::l' => String.String h (list_to_string l')
end.
Definition string_serialize (s : String.string) :=
serialize (string_to_list s).
Definition string_deserialize : ByteListReader.t String.string :=
list_to_string <$> deserialize.

Lemma string_serialize_deserialize_id :
serialize_deserialize_id_spec string_serialize string_deserialize.