Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | String : String.string -> t
    | Arr : list t -> t
    | Obj : list (String.string * t) -> t.Fixpoint json_rect (j : t) : P j :=
        let fix go_list (l : list t) : P_list l :=
            match l with
            | [] => P_nil
            | j :: l => P_cons (json_rect j) (go_list l)
            end in
        let fix go_list' (l : list (String.string * t)) : P_list' l :=
            match l with
            | [] => P_nil'
            | (s, j) :: l => P_cons' s (json_rect j) (go_list' l)
            end in
        match j with
        | Null => P_null
        | Bool b => P_bool b
        | Num n => P_num n
        | String s => P_string s
        | Arr l => P_arr (go_list l)
        | Obj l => P_obj (go_list' l)
        end.Definition json_ind (j : t) : P j :=
        json_rect P (List.Forall P)
                  (List.Forall (fun s => P (snd s)))
                  (List.Forall_nil _) (fun j l Pt Pl => List.Forall_cons j Pt Pl)
                  (List.Forall_nil _)
                  (fun s j l Pj Pt => List.Forall_cons (s, j) Pj Pt)
                  P_null
                  P_bool
                  P_num
                  P_string
                  P_arr
                  P_obj
                  j.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.Inductive t :=
    | Null : t
    | Bool : bool -> t
    | Num : nat -> t
    | Str : String.string -> t
    | Arr : t
    | Obj : t.(* tag serializer *)
    Definition tag_serialize (t : t) : IOStreamWriter.t :=
      match t with
      | Null => serialize x00
      | Bool b => IOStreamWriter.append (fun _ => serialize x01)
                                        (fun _ => serialize b)
      | Num n => IOStreamWriter.append (fun _ => serialize x02)
                               (fun _ => serialize n)
      | Str s => IOStreamWriter.append (fun _ => serialize x03)
                               (fun _ => serialize s)
      | Arr => serialize x04
      | Obj => serialize x05
      end.

(* Specifications: *)
Lemma tag_serialize_deserialize_id : serialize_deserialize_id_spec tag_serialize tag_deserialize.