(* Auto-generated from "doc.atd" by atdml. *)

(** Module-level documentation. *)

(** An internal tree node. *)
type node = {
  value: int;
  left: tree;
  right: tree;
}

(** A binary tree. *)
and tree =
  | Leaf
  | Node of node

val create_node : value:int -> left:tree -> right:tree -> unit -> node
val node_of_yojson : Yojson.Safe.t -> node
val node_of_jsonlike : Atd_jsonlike.AST.t -> node
val yojson_of_node : node -> Yojson.Safe.t
val node_of_json : string -> node
val json_of_node : node -> string

val tree_of_yojson : Yojson.Safe.t -> tree
val tree_of_jsonlike : Atd_jsonlike.AST.t -> tree
val yojson_of_tree : tree -> Yojson.Safe.t
val tree_of_json : string -> tree
val json_of_tree : tree -> string

module Node : sig
  type nonrec t = node
  val create : value:int -> left:tree -> right:tree -> unit -> t
  val of_yojson : Yojson.Safe.t -> t
  val of_jsonlike : Atd_jsonlike.AST.t -> t
  val to_yojson : t -> Yojson.Safe.t
  val of_json : string -> t
  val to_json : t -> string
end

module Tree : sig
  type nonrec t = tree
  val of_yojson : Yojson.Safe.t -> t
  val of_jsonlike : Atd_jsonlike.AST.t -> t
  val to_yojson : t -> Yojson.Safe.t
  val of_json : string -> t
  val to_json : t -> string
end

(**
   A person record.

   Second paragraph.
*)
type person = {
  name: string;  (** The person's name. *)
  age: int;  (** Age in years. *)
  email: string option;
}

val create_person : name:string -> age:int -> ?email:string -> unit -> person
val person_of_yojson : Yojson.Safe.t -> person
val person_of_jsonlike : Atd_jsonlike.AST.t -> person
val yojson_of_person : person -> Yojson.Safe.t
val person_of_json : string -> person
val json_of_person : person -> string

module Person : sig
  type nonrec t = person
  val create : name:string -> age:int -> ?email:string -> unit -> t
  val of_yojson : Yojson.Safe.t -> t
  val of_jsonlike : Atd_jsonlike.AST.t -> t
  val to_yojson : t -> Yojson.Safe.t
  val of_json : string -> t
  val to_json : t -> string
end

(** A color value. *)
type color =
  | Red  (** The color red. *)
  | Green  (** The color green. *)
  | Blue

val color_of_yojson : Yojson.Safe.t -> color
val color_of_jsonlike : Atd_jsonlike.AST.t -> color
val yojson_of_color : color -> Yojson.Safe.t
val color_of_json : string -> color
val json_of_color : color -> string

module Color : sig
  type nonrec t = color
  val of_yojson : Yojson.Safe.t -> t
  val of_jsonlike : Atd_jsonlike.AST.t -> t
  val to_yojson : t -> Yojson.Safe.t
  val of_json : string -> t
  val to_json : t -> string
end

(** An alias for string. *)
type alias = private string

val create_alias : string -> alias
val alias_of_yojson : Yojson.Safe.t -> alias
val alias_of_jsonlike : Atd_jsonlike.AST.t -> alias
val yojson_of_alias : alias -> Yojson.Safe.t
val alias_of_json : string -> alias
val json_of_alias : alias -> string

module Alias : sig
  type nonrec t = alias
  val create : string -> t
  val of_yojson : Yojson.Safe.t -> t
  val of_jsonlike : Atd_jsonlike.AST.t -> t
  val to_yojson : t -> Yojson.Safe.t
  val of_json : string -> t
  val to_json : t -> string
end

--- ml ---
(* Auto-generated from "doc.atd" by atdml. *)
[@@@ocaml.warning "-27-32-33-35-39"]

(** Module-level documentation. *)

(* Inlined runtime — no external dependency needed. *)
module Atdml_runtime = struct
  (* Returns true iff the list has strictly more than [n] elements,
     without traversing past element n+1. *)
  let rec list_length_gt n = function
    | _ :: rest -> if n = 0 then true else list_length_gt (n - 1) rest
    | [] -> false

  module Yojson = struct
    let bad_type expected_type x =
      Printf.ksprintf failwith "expected %s, got: %s"
        expected_type (Yojson.Safe.to_string x)

    let bad_sum type_name x =
      Printf.ksprintf failwith "invalid variant for type '%s': %s"
        type_name (Yojson.Safe.to_string x)

    let missing_field type_name field_name =
      Printf.ksprintf failwith "missing field '%s' in object of type '%s'"
        field_name type_name

    let bool_of_yojson = function
      | `Bool b -> b
      | x -> bad_type "bool" x

    let yojson_of_bool b = `Bool b

    let int_of_yojson = function
      | `Int n -> n
      | x -> bad_type "int" x

    let yojson_of_int n = `Int n

    let float_of_yojson = function
      | `Float f -> f
      | `Int n -> Float.of_int n
      | x -> bad_type "float" x

    let yojson_of_float f = `Float f

    let string_of_yojson = function
      | `String s -> s
      | x -> bad_type "string" x

    let yojson_of_string s = `String s

    let unit_of_yojson = function
      | `Null -> ()
      | x -> bad_type "null" x

    let yojson_of_unit () = `Null

    let list_of_yojson f = function
      | `List xs -> List.map f xs
      | x -> bad_type "array" x

    let yojson_of_list f xs = `List (List.map f xs)

    let option_of_yojson f = function
      | `String "None" -> None
      | `List [`String "Some"; x] -> Some (f x)
      | x -> bad_type "option" x

    let yojson_of_option f = function
      | None -> `String "None"
      | Some x -> `List [`String "Some"; f x]

    let nullable_of_yojson f = function
      | `Null -> None
      | x -> Some (f x)

    let yojson_of_nullable f = function
      | None -> `Null
      | Some x -> f x

    let assoc_of_yojson f = function
      | `Assoc pairs -> List.map (fun (k, v) -> (k, f v)) pairs
      | x -> bad_type "object" x

    let yojson_of_assoc f xs =
      `Assoc (List.map (fun (k, v) -> (k, f v)) xs)
  end

  module Jsonlike = struct
    let bad_type expected_type x =
      Printf.ksprintf failwith "%sexpected %s"
        (Atd_jsonlike.AST.loc_msg x) expected_type

    let bad_sum type_name x =
      Printf.ksprintf failwith "%sinvalid variant for type '%s'"
        (Atd_jsonlike.AST.loc_msg x) type_name

    let missing_field node type_name field_name =
      Printf.ksprintf failwith "%smissing field '%s' in object of type '%s'"
        (Atd_jsonlike.AST.loc_msg node) field_name type_name

    let bool_of_jsonlike = function
      | Atd_jsonlike.AST.Bool (_, b) -> b
      | x -> bad_type "bool" x

    let int_of_jsonlike = function
      | Atd_jsonlike.AST.Number (_, n) as node ->
          (match n.Atd_jsonlike.Number.int with
          | Some i -> i
          | None -> bad_type "integer" node)
      | x -> bad_type "int" x

    let float_of_jsonlike = function
      | Atd_jsonlike.AST.Number (_, n) as node ->
          (match n.Atd_jsonlike.Number.float with
          | Some f -> f
          | None -> bad_type "float" node)
      | x -> bad_type "float" x

    let string_of_jsonlike = function
      | Atd_jsonlike.AST.String (_, s) -> s
      | x -> bad_type "string" x

    let unit_of_jsonlike = function
      | Atd_jsonlike.AST.Null _ -> ()
      | x -> bad_type "null" x

    let list_of_jsonlike f = function
      | Atd_jsonlike.AST.Array (_, xs) -> List.map f xs
      | x -> bad_type "array" x

    let option_of_jsonlike f = function
      | Atd_jsonlike.AST.String (_, "None") -> None
      | Atd_jsonlike.AST.Array (_, [Atd_jsonlike.AST.String (_, "Some"); x]) -> Some (f x)
      | x -> bad_type "option" x

    let nullable_of_jsonlike f = function
      | Atd_jsonlike.AST.Null _ -> None
      | x -> Some (f x)

    let assoc_of_jsonlike f = function
      | Atd_jsonlike.AST.Object (_, pairs) ->
          List.map (fun (_, k, v) -> (k, f v)) pairs
      | x -> bad_type "object" x
  end
end

(** An internal tree node. *)
type node = {
  value: int;
  left: tree;
  right: tree;
}

(** A binary tree. *)
and tree =
  | Leaf
  | Node of node

let create_node ~value ~left ~right () : node =
  { value; left; right }

let rec node_of_yojson (x : Yojson.Safe.t) : node =
  match x with
  | `Assoc fields ->
    (* Duplicate JSON keys: behavior is unspecified (RFC 8259 §4 says keys SHOULD
       be unique). Below the threshold, List.assoc_opt returns the first binding;
       above it, the hashtable returns the last. *)
    let assoc_ =
      if Atdml_runtime.list_length_gt 5 fields then
        let tbl = Hashtbl.create 16 in
        List.iter (fun (k, v) -> Hashtbl.add tbl k v) fields;
        (fun key -> Hashtbl.find_opt tbl key)
      else (fun key -> List.assoc_opt key fields)
    in
    let value =
      match assoc_ "value" with
      | Some v -> Atdml_runtime.Yojson.int_of_yojson v
      | None -> Atdml_runtime.Yojson.missing_field "node" "value"
    in
    let left =
      match assoc_ "left" with
      | Some v -> tree_of_yojson v
      | None -> Atdml_runtime.Yojson.missing_field "node" "left"
    in
    let right =
      match assoc_ "right" with
      | Some v -> tree_of_yojson v
      | None -> Atdml_runtime.Yojson.missing_field "node" "right"
    in
    { value; left; right }
  | _ -> Atdml_runtime.Yojson.bad_type "node" x

and tree_of_yojson (x : Yojson.Safe.t) : tree =
  match x with
  | `String "Leaf" -> Leaf
  | `List [`String "Node"; v] -> Node (node_of_yojson v)
  | _ -> Atdml_runtime.Yojson.bad_sum "tree" x

let rec node_of_jsonlike (x : Atd_jsonlike.AST.t) : node =
  match x with
  | Atd_jsonlike.AST.Object (_, fields) ->
    let atdml_node_ = x in
    let assoc_ =
      if Atdml_runtime.list_length_gt 5 fields then
        let tbl = Hashtbl.create 16 in
        List.iter (fun (_, k, v) -> Hashtbl.add tbl k v) fields;
        (fun key -> Hashtbl.find_opt tbl key)
      else
        (fun key ->
          match List.find_opt (fun (_, k, _) -> k = key) fields with
          | None -> None | Some (_, _, v) -> Some v)
    in
    let value =
      match assoc_ "value" with
      | Some v -> Atdml_runtime.Jsonlike.int_of_jsonlike v
      | None -> Atdml_runtime.Jsonlike.missing_field atdml_node_ "node" "value"
    in
    let left =
      match assoc_ "left" with
      | Some v -> tree_of_jsonlike v
      | None -> Atdml_runtime.Jsonlike.missing_field atdml_node_ "node" "left"
    in
    let right =
      match assoc_ "right" with
      | Some v -> tree_of_jsonlike v
      | None -> Atdml_runtime.Jsonlike.missing_field atdml_node_ "node" "right"
    in
    { value; left; right }
  | _ -> Atdml_runtime.Jsonlike.bad_type "node" x

and tree_of_jsonlike (x : Atd_jsonlike.AST.t) : tree =
  match x with
  | Atd_jsonlike.AST.String (_, "Leaf") -> Leaf
  | Atd_jsonlike.AST.Array (_, [Atd_jsonlike.AST.String (_, "Node"); v]) -> Node (node_of_jsonlike v)
  | _ -> Atdml_runtime.Jsonlike.bad_sum "tree" x

let rec yojson_of_node (x : node) : Yojson.Safe.t =
  `Assoc (List.concat [
    [("value", Atdml_runtime.Yojson.yojson_of_int x.value)];
    [("left", yojson_of_tree x.left)];
    [("right", yojson_of_tree x.right)];
  ])

and yojson_of_tree (x : tree) : Yojson.Safe.t =
  match x with
  | Leaf -> `String "Leaf"
  | Node v -> `List [`String "Node"; yojson_of_node v]

let node_of_json s =
  node_of_yojson (Yojson.Safe.from_string s)

let json_of_node x =
  Yojson.Safe.to_string (yojson_of_node x)

let tree_of_json s =
  tree_of_yojson (Yojson.Safe.from_string s)

let json_of_tree x =
  Yojson.Safe.to_string (yojson_of_tree x)

module Node = struct
  type nonrec t = node
  let create = create_node
  let of_yojson = node_of_yojson
  let of_jsonlike = node_of_jsonlike
  let to_yojson = yojson_of_node
  let of_json = node_of_json
  let to_json = json_of_node
end

module Tree = struct
  type nonrec t = tree
  let of_yojson = tree_of_yojson
  let of_jsonlike = tree_of_jsonlike
  let to_yojson = yojson_of_tree
  let of_json = tree_of_json
  let to_json = json_of_tree
end

(**
   A person record.

   Second paragraph.
*)
type person = {
  name: string;  (** The person's name. *)
  age: int;  (** Age in years. *)
  email: string option;
}

let create_person ~name ~age ?email () : person =
  { name; age; email }

let person_of_yojson (x : Yojson.Safe.t) : person =
  match x with
  | `Assoc fields ->
    (* Duplicate JSON keys: behavior is unspecified (RFC 8259 §4 says keys SHOULD
       be unique). Below the threshold, List.assoc_opt returns the first binding;
       above it, the hashtable returns the last. *)
    let assoc_ =
      if Atdml_runtime.list_length_gt 5 fields then
        let tbl = Hashtbl.create 16 in
        List.iter (fun (k, v) -> Hashtbl.add tbl k v) fields;
        (fun key -> Hashtbl.find_opt tbl key)
      else (fun key -> List.assoc_opt key fields)
    in
    let name =
      match assoc_ "name" with
      | Some v -> Atdml_runtime.Yojson.string_of_yojson v
      | None -> Atdml_runtime.Yojson.missing_field "person" "name"
    in
    let age =
      match assoc_ "age" with
      | Some v -> Atdml_runtime.Yojson.int_of_yojson v
      | None -> Atdml_runtime.Yojson.missing_field "person" "age"
    in
    let email =
      match assoc_ "email" with
      | None | Some `Null -> None
      | Some v -> Some (Atdml_runtime.Yojson.string_of_yojson v)
    in
    { name; age; email }
  | _ -> Atdml_runtime.Yojson.bad_type "person" x

let person_of_jsonlike (x : Atd_jsonlike.AST.t) : person =
  match x with
  | Atd_jsonlike.AST.Object (_, fields) ->
    let atdml_node_ = x in
    let assoc_ =
      if Atdml_runtime.list_length_gt 5 fields then
        let tbl = Hashtbl.create 16 in
        List.iter (fun (_, k, v) -> Hashtbl.add tbl k v) fields;
        (fun key -> Hashtbl.find_opt tbl key)
      else
        (fun key ->
          match List.find_opt (fun (_, k, _) -> k = key) fields with
          | None -> None | Some (_, _, v) -> Some v)
    in
    let name =
      match assoc_ "name" with
      | Some v -> Atdml_runtime.Jsonlike.string_of_jsonlike v
      | None -> Atdml_runtime.Jsonlike.missing_field atdml_node_ "person" "name"
    in
    let age =
      match assoc_ "age" with
      | Some v -> Atdml_runtime.Jsonlike.int_of_jsonlike v
      | None -> Atdml_runtime.Jsonlike.missing_field atdml_node_ "person" "age"
    in
    let email =
      match assoc_ "email" with
      | None | Some (Atd_jsonlike.AST.Null _) -> None
      | Some v -> Some (Atdml_runtime.Jsonlike.string_of_jsonlike v)
    in
    { name; age; email }
  | _ -> Atdml_runtime.Jsonlike.bad_type "person" x

let yojson_of_person (x : person) : Yojson.Safe.t =
  `Assoc (List.concat [
    [("name", Atdml_runtime.Yojson.yojson_of_string x.name)];
    [("age", Atdml_runtime.Yojson.yojson_of_int x.age)];
    (match x.email with None -> [] | Some v -> [("email", Atdml_runtime.Yojson.yojson_of_string v)]);
  ])

let person_of_json s =
  person_of_yojson (Yojson.Safe.from_string s)

let json_of_person x =
  Yojson.Safe.to_string (yojson_of_person x)

module Person = struct
  type nonrec t = person
  let create = create_person
  let of_yojson = person_of_yojson
  let of_jsonlike = person_of_jsonlike
  let to_yojson = yojson_of_person
  let of_json = person_of_json
  let to_json = json_of_person
end

(** A color value. *)
type color =
  | Red  (** The color red. *)
  | Green  (** The color green. *)
  | Blue

let color_of_yojson (x : Yojson.Safe.t) : color =
  match x with
  | `String "Red" -> Red
  | `String "Green" -> Green
  | `String "Blue" -> Blue
  | _ -> Atdml_runtime.Yojson.bad_sum "color" x

let color_of_jsonlike (x : Atd_jsonlike.AST.t) : color =
  match x with
  | Atd_jsonlike.AST.String (_, "Red") -> Red
  | Atd_jsonlike.AST.String (_, "Green") -> Green
  | Atd_jsonlike.AST.String (_, "Blue") -> Blue
  | _ -> Atdml_runtime.Jsonlike.bad_sum "color" x

let yojson_of_color (x : color) : Yojson.Safe.t =
  match x with
  | Red -> `String "Red"
  | Green -> `String "Green"
  | Blue -> `String "Blue"

let color_of_json s =
  color_of_yojson (Yojson.Safe.from_string s)

let json_of_color x =
  Yojson.Safe.to_string (yojson_of_color x)

module Color = struct
  type nonrec t = color
  let of_yojson = color_of_yojson
  let of_jsonlike = color_of_jsonlike
  let to_yojson = yojson_of_color
  let of_json = color_of_json
  let to_json = json_of_color
end

(** An alias for string. *)
type alias = string

let create_alias (x : string) : alias = x


let alias_of_yojson (x : Yojson.Safe.t) : alias =
  Atdml_runtime.Yojson.string_of_yojson x

let alias_of_jsonlike (x : Atd_jsonlike.AST.t) : alias =
  Atdml_runtime.Jsonlike.string_of_jsonlike x

let yojson_of_alias (x : alias) : Yojson.Safe.t =
  Atdml_runtime.Yojson.yojson_of_string x

let alias_of_json s =
  alias_of_yojson (Yojson.Safe.from_string s)

let json_of_alias x =
  Yojson.Safe.to_string (yojson_of_alias x)

module Alias = struct
  type nonrec t = alias
  let create = create_alias
  let of_yojson = alias_of_yojson
  let of_jsonlike = alias_of_jsonlike
  let to_yojson = yojson_of_alias
  let of_json = alias_of_json
  let to_json = json_of_alias
end

