(* Hierarchical data structure *) type value = | Int of int | Float of float | String of string | Data of t | Array of value array and field = { key : string; pretty_key : string option; format : string option; value : value; } and t = field list let make items = List.map (fun (key, pretty_key, value) -> { key; pretty_key; format = None; value }) items let int key ?pretty ?format value = { key; pretty_key = pretty; format; value = Int value } let float key ?pretty ?format value = { key; pretty_key = pretty; format; value = Float value } let string key ?pretty ?format value = { key; pretty_key = pretty; format; value = String value } let data key ?pretty value = { key; pretty_key = pretty; format = None; value = Data value } let array key ?pretty value = { key; pretty_key = pretty; format = None; value = Array value } let hex key ?pretty bytes len = let s = Rtl433_util.bytes_to_hex bytes len in { key; pretty_key = pretty; format = None; value = String s } let find key data = List.find_opt (fun f -> f.key = key) data let get_int key data = match find key data with Some { value = Int i; _ } -> Some i | _ -> None let get_float key data = match find key data with Some { value = Float f; _ } -> Some f | _ -> None let get_string key data = match find key data with Some { value = String s; _ } -> Some s | _ -> None let rec pp_value fmt = function | Int i -> Format.fprintf fmt "%d" i | Float f -> Format.fprintf fmt "%g" f | String s -> Format.fprintf fmt "%S" s | Data d -> pp fmt d | Array a -> Format.fprintf fmt "[%a]" (Format.pp_print_list ~pp_sep:(fun fmt () -> Format.fprintf fmt ", ") pp_value) (Array.to_list a) and pp fmt data = Format.fprintf fmt "{%a}" (Format.pp_print_list ~pp_sep:(fun fmt () -> Format.fprintf fmt ", ") (fun fmt f -> Format.fprintf fmt "%s: %a" f.key pp_value f.value)) data let to_json data = let buf = Buffer.create 256 in let rec emit_value = function | Int i -> Buffer.add_string buf (string_of_int i) | Float f -> Buffer.add_string buf (string_of_float f) | String s -> Buffer.add_char buf '"'; Buffer.add_string buf (String.escaped s); Buffer.add_char buf '"' | Data d -> emit_data d | Array a -> Buffer.add_char buf '['; Array.iteri (fun i v -> if i > 0 then Buffer.add_char buf ','; emit_value v) a; Buffer.add_char buf ']' and emit_data fields = Buffer.add_char buf '{'; List.iteri (fun i f -> if i > 0 then Buffer.add_char buf ','; Buffer.add_char buf '"'; Buffer.add_string buf f.key; Buffer.add_string buf "\":"; emit_value f.value) fields; Buffer.add_char buf '}' in emit_data data; Buffer.contents buf (* Mutable storage for last decoded output *) let last_output : t option ref = ref None let set_last_output data = last_output := Some data let get_last_output () = !last_output let clear_last_output () = last_output := None