TOML 1.1 codecs for OCaml
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(** Bytesrw integration for {{:https://toml.io/en/v1.1.0}TOML 1.1} parsing
7 and encoding.
8
9 This module provides I/O operations for TOML values and codecs using
10 {{:https://erratique.ch/software/bytesrw}Bytesrw} for efficient streaming.
11
12 {2 Quick Start}
13
14 Parse a TOML string:
15 {[
16 let config = Tomlt_bytesrw.of_string {|
17 [server]
18 host = "localhost"
19 port = 8080
20 |} in
21 match config with
22 | Ok t ->
23 let server = Tomlt.Toml.find "server" t in
24 let host = Tomlt.Toml.to_string (Tomlt.Toml.find "host" server) in
25 let port = Tomlt.Toml.to_int (Tomlt.Toml.find "port" server) in
26 Printf.printf "Server: %s:%Ld\n" host port
27 | Error e -> prerr_endline (Tomlt.Toml.Error.to_string e)
28 ]}
29
30 Use with codecs:
31 {[
32 type config = { host : string; port : int }
33
34 let config_codec = Tomlt.(Table.(
35 obj (fun host port -> { host; port })
36 |> mem "host" string ~enc:(fun c -> c.host)
37 |> mem "port" int ~enc:(fun c -> c.port)
38 |> finish
39 ))
40
41 let config = Tomlt_bytesrw.decode_string config_codec toml_string
42 ]}
43
44 {2 Module Overview}
45
46 - {!section:parse} - Parsing TOML from strings and readers
47 - {!section:encode} - Encoding TOML to strings and writers
48 - {!section:codec_io} - Codec I/O operations
49 - {!section:tagged_json} - Tagged JSON for toml-test compatibility *)
50
51open Bytesrw
52
53(** {1:parse Parsing (Decoding)}
54
55 Parse TOML from various sources. *)
56
57val of_string : string -> (Tomlt.Toml.t, Tomlt.Toml.Error.t) result
58(** [of_string s] parses [s] as a TOML document. *)
59
60val of_reader : ?file:string -> Bytes.Reader.t -> (Tomlt.Toml.t, Tomlt.Toml.Error.t) result
61(** [of_reader r] parses a TOML document from reader [r].
62 @param file Optional filename for error messages. *)
63
64val parse : string -> Tomlt.Toml.t
65(** [parse s] parses [s] as a TOML document.
66 @raise Tomlt.Toml.Error.Error on parse errors. *)
67
68val parse_reader : ?file:string -> Bytes.Reader.t -> Tomlt.Toml.t
69(** [parse_reader r] parses a TOML document from reader [r].
70 @param file Optional filename for error messages.
71 @raise Tomlt.Toml.Error.Error on parse errors. *)
72
73(** {1:encode Encoding}
74
75 Encode TOML values to strings and writers. *)
76
77val to_string : Tomlt.Toml.t -> string
78(** [to_string t] encodes [t] as a TOML-formatted string.
79 @raise Invalid_argument if [t] is not a [Table]. *)
80
81val to_writer : Bytes.Writer.t -> Tomlt.Toml.t -> unit
82(** [to_writer w t] writes [t] as TOML to writer [w].
83
84 Use with {!Bytesrw.Bytes.Writer} to write to various destinations:
85 {[
86 (* To buffer *)
87 let buf = Buffer.create 256 in
88 Tomlt_bytesrw.to_writer (Bytes.Writer.of_buffer buf) value;
89 Buffer.contents buf
90
91 (* To channel *)
92 Tomlt_bytesrw.to_writer (Bytes.Writer.of_out_channel oc) value
93 ]}
94
95 @raise Invalid_argument if [t] is not a [Table]. *)
96
97(** {1:codec_io Codec I/O Operations}
98
99 Convenience functions that combine parsing/encoding with codec
100 operations. *)
101
102val decode_string : 'a Tomlt.t -> string -> ('a, Tomlt.Toml.Error.t) result
103(** [decode_string c s] parses TOML string [s] and decodes with codec [c]. *)
104
105val decode_string_exn : 'a Tomlt.t -> string -> 'a
106(** [decode_string_exn c s] is like [decode_string] but raises on error.
107 @raise Tomlt.Toml.Error.Error on parse or decode failure. *)
108
109val encode_string : 'a Tomlt.t -> 'a -> string
110(** [encode_string c v] encodes [v] using codec [c] to a TOML-formatted string. *)
111
112val decode_reader : ?file:string -> 'a Tomlt.t -> Bytes.Reader.t ->
113 ('a, Tomlt.Toml.Error.t) result
114(** [decode_reader c r] parses TOML from reader [r] and decodes with codec [c].
115 @param file Optional filename for error messages. *)
116
117val encode_writer : 'a Tomlt.t -> 'a -> Bytes.Writer.t -> unit
118(** [encode_writer c v w] encodes [v] using codec [c] and writes TOML to
119 writer [w]. *)
120
121(** {1:tagged_json Tagged JSON}
122
123 Functions for interoperating with the
124 {{:https://github.com/toml-lang/toml-test}toml-test} suite's tagged JSON
125 format. These functions are primarily for testing and validation. *)
126
127module Tagged_json : sig
128 val encode : Tomlt.Toml.t -> string
129 (** [encode t] converts TOML value [t] to tagged JSON format.
130
131 The tagged JSON format wraps each value with type information:
132 - Strings: [{"type": "string", "value": "..."}]
133 - Integers: [{"type": "integer", "value": "..."}]
134 - Floats: [{"type": "float", "value": "..."}]
135 - Booleans: [{"type": "bool", "value": "true"|"false"}]
136 - Datetimes: [{"type": "datetime", "value": "..."}]
137 - Arrays: [[...]]
138 - Tables: [{...}] *)
139
140 val decode : string -> Tomlt.Toml.t
141 (** [decode s] parses tagged JSON string [s] into a TOML value.
142 @raise Failure if the JSON is malformed or has invalid types. *)
143
144 val decode_and_encode_toml : string -> (string, string) result
145 (** [decode_and_encode_toml json] decodes tagged JSON and encodes as TOML.
146 Used by the toml-test encoder harness. *)
147end