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.

(* This proof is typical for serializing an algebraic datatype. Unfold the serializer and deserializer, then do a case analysis and call serialize_deserialize_id_crush. *)
Lemma Z_serialize_deserialize_id :
serialize_deserialize_id_spec Z_serialize Z_deserialize.