Proof using.
induction t using tree_rect with
(P_list := fun l =>
(* We need to extend the statement to a list of subtrees for the mutual induction hypothesis. It says that serializing and then deserializing a list of trees `l` is the same as `List.map (map (fun _ => tt) l)`. `deserialize_list_tree_shape'` is always called with at least one element on the accumulator, so there's no need for a match like there was above. *)
forall ts acc bytes,
ByteListReader.unwrap
(ByteListReader.fold deserialize_tree_shape_step (ts :: acc))
(IOStreamWriter.unwrap (serialize_list_tree_shape l) ++ bytes) =
ByteListReader.unwrap
(ByteListReader.fold
deserialize_tree_shape_step
((rev (List.map shape l) ++ ts) :: acc)) bytes);
intros;
try (unfold serialize_list_tree_shape;
rewrite IOStreamWriter.append_unwrap, app_ass, IHt, IHt0;
simpl;
now rewrite app_ass).
(cheerios_crush; simpl; cheerios_crush; simpl).
-  destruct acc;
repeat (cheerios_crush;
simpl).
- destruct acc;
simpl;
rewrite IOStreamWriter.append_unwrap,
ByteListReader.fold_unwrap,
IOStreamWriter.append_unwrap,
IOStreamWriter.putByte_unwrap;
simpl;
fold serialize_list_tree_shape;
rewrite app_ass, IHt, ByteListReader.fold_unwrap,
IOStreamWriter.putByte_unwrap;
simpl;
rewrite app_nil_r, rev'_spec, rev_involutive;
reflexivity.
Qed.
Definition deserialize_tree_shape : ByteListReader.t (tree unit) :=
ByteListReader.fold deserialize_tree_shape_step [].

(* Specifications: *)
(* This is the top level statement about serializing and deserializing tree shapes: it results in `shape` of the original tree. *)
Lemma serialize_deserialize_shape_id :
forall t bytes,
ByteListReader.unwrap deserialize_tree_shape
(IOStreamWriter.unwrap (serialize_tree_shape t) ++ bytes)
= Some (shape t, bytes).