Section PositiveInductionPrinciple.
Variable P : positive -> Prop.
Proof using.
induction q;
intros;
inversion H1;
auto;
apply H0;
apply IHq.
Qed.
Proof using.
intros.
apply (H p p).
constructor.
Qed.
Proof using.
intros.
apply weaken_pos.
now apply strongind_pos_aux.
Qed.
End PositiveInductionPrinciple.
Local Open Scope char_scope.
Fixpoint positive_serialize p :=
match p with
| xI (xI (xI p)) => IOStreamWriter.append (fun _ => serialize x0e)
(fun _ => positive_serialize p)
| xI (xI (xO p)) => IOStreamWriter.append (fun _ => serialize x0d)
(fun _ => positive_serialize p)
| xI (xO (xI p)) => IOStreamWriter.append (fun _ => serialize x0c)
(fun _ => positive_serialize p)
| xI (xO (xO p)) => IOStreamWriter.append (fun _ => serialize x0b)
(fun _ => positive_serialize p)
| xO (xI (xI p)) => IOStreamWriter.append (fun _ => serialize x0a)
(fun _ => positive_serialize p)
| xO (xI (xO p)) => IOStreamWriter.append (fun _ => serialize x09)
(fun _ => positive_serialize p)
| xO (xO (xI p)) => IOStreamWriter.append (fun _ => serialize x08)
(fun _ => positive_serialize p)
| xO (xO (xO p)) => IOStreamWriter.append (fun _ => serialize x07)
(fun _ => positive_serialize p)
| xI (xI p) => IOStreamWriter.append (fun _ => serialize x06)
(fun _ => positive_serialize p)
| xI (xO p) => IOStreamWriter.append (fun _ => serialize x05)
(fun _ => positive_serialize p)
| xO (xI p) => IOStreamWriter.append (fun _ => serialize x04)
(fun _ => positive_serialize p)
| xO (xO p) => IOStreamWriter.append (fun _ => serialize x03)
(fun _ => positive_serialize p)
| xI p => IOStreamWriter.append (fun _ => serialize x02)
(fun _ => positive_serialize p)
| xO p => IOStreamWriter.append (fun _ => serialize x01)
(fun _ => positive_serialize p)
| XH => serialize x00
end.
Definition positive_deserialize_step
(b : byte)
(s : positive -> positive) :=
match b with
| x0e => More (fun p => s (xI (xI (xI p))))
| x0d => More (fun p => s (xI (xI (xO p))))
| x0c => More (fun p => s (xI (xO (xI p))))
| x0b => More (fun p => s (xI (xO (xO p))))
| x0a => More (fun p => s (xO (xI (xI p))))
| x09 => More (fun p => s (xO (xI (xO p))))
| x08 => More (fun p =>  s (xO (xO (xI p))))
| x07 => More (fun p => s (xO (xO (xO p))))
| x06 => More (fun p => s (xI (xI p)))
| x05 => More (fun p => s (xI (xO p)))
| x04 => More (fun p => s (xO (xI p)))
| x03 => More (fun p => s (xO (xO p)))
| x02 => More (fun p => s (xI p))
| x01 => More (fun p => s (xO p))
| x00 => Done (s xH)
| _ => Error
end.
Definition positive_step_aux p :=
forall (k : positive -> positive) (bytes : list byte),
ByteListReader.unwrap (ByteListReader.fold positive_deserialize_step k)
(IOStreamWriter.unwrap (positive_serialize p) ++ bytes)
= Some(k p, bytes).
Definition positive_deserialize :=
ByteListReader.fold positive_deserialize_step (fun p => p).
Instance positive_Serializer : Serializer positive.
(* This is the first example of a "typical" serializer: it combines more primitive serializers (in this case, just for byte and positive) together in order to serialize a Z. *)
Definition Z_serialize (z : Z) : IOStreamWriter.t :=
match z with
| Z0 => serialize x00
| Zpos p => IOStreamWriter.append (fun _ => serialize x01)
(fun _ => serialize p)
| Zneg p => IOStreamWriter.append (fun _ => serialize x02)
(fun _ => serialize p)
end.
Definition Z_deserialize : ByteListReader.t Z :=
tag <- deserialize ;;
match tag with
| x02 => Zneg <$> deserialize
| x01 => Zpos <$> deserialize
| x00 => ByteListReader.ret Z0
| _ => ByteListReader.error
end.
Instance Z_Serializer : Serializer Z :=
{| serialize := Z_serialize;
deserialize := Z_deserialize;
serialize_deserialize_id := Z_serialize_deserialize_id
|}.
Definition N_serialize n :=
match n with
| N0 => serialize false
| Npos p => IOStreamWriter.append (fun _ => serialize true)
(fun _ => serialize p)
end.
Definition N_deserialize : ByteListReader.t N :=
tag <- deserialize ;;
match tag with
| false => ByteListReader.ret N0
| true => Npos <$> deserialize
end.
Instance N_Serializer : Serializer N.
(* The other main way to define a serializer is to use an isomorphism to another type that is already serializable. *)
Definition nat_serialize n : IOStreamWriter.t := serialize (N.of_nat n).
Definition nat_deserialize : ByteListReader.t nat := N.to_nat <$> deserialize.

(* This proof is typical for serializers defined by converting to and from a type that is already serializable. Unfold the serializer and deserializer, call serialize_deserialize_id_crush, and then use the proof that the conversion functions are inverses. *)
Lemma nat_serialize_deserialize_id :
serialize_deserialize_id_spec nat_serialize nat_deserialize.