File tree Expand file tree Collapse file tree 4 files changed +107
-2
lines changed Expand file tree Collapse file tree 4 files changed +107
-2
lines changed Original file line number Diff line number Diff line change 1-
21(library
32 (name decoders_otoml)
43 (public_name decoders-otoml)
Original file line number Diff line number Diff line change @@ -329,6 +329,38 @@ module Make (Decodeable : Decodeable) :
329329 (fail " Expected a list" ).dec value
330330
331331
332+ let ( >>=:: ) fst rest = uncons rest fst
333+
334+ let empty_list =
335+ Decoder. of_decode_fun
336+ @@ fun value ->
337+ match Decodeable. get_list value with
338+ | Some [] ->
339+ Ok ()
340+ | Some _ ->
341+ (fail " Expected an empty list" ).dec value
342+ | None ->
343+ (fail " Expected a list" ).dec value
344+
345+
346+ let tuple2 d0 d1 =
347+ d0 >> =:: fun arg0 -> d1 >> =:: fun arg1 -> succeed (arg0, arg1)
348+
349+
350+ let tuple3 d0 d1 d2 =
351+ d0
352+ >> =:: fun arg0 ->
353+ d1 >> =:: fun arg1 -> d2 >> =:: fun arg2 -> succeed (arg0, arg1, arg2)
354+
355+
356+ let tuple4 d0 d1 d2 d3 =
357+ d0
358+ >> =:: fun arg0 ->
359+ d1
360+ >> =:: fun arg1 ->
361+ d2 >> =:: fun arg2 -> d3 >> =:: fun arg3 -> succeed (arg0, arg1, arg2, arg3)
362+
363+
332364 let rec at : string list -> 'a decoder -> 'a decoder =
333365 fun path decoder ->
334366 match path with
Original file line number Diff line number Diff line change @@ -117,7 +117,36 @@ module type S = sig
117117
118118 (If you squint, the uncons operator [>>=::] kind of looks like the cons
119119 operator [::].)
120- *)
120+ *)
121+
122+ val empty_list : unit decoder
123+
124+ val tuple2 : 'a decoder -> 'b decoder -> ('a * 'b ) decoder
125+ (* * Decode a collection into an OCaml 2-tuple.
126+
127+ For example, to decode this json:
128+
129+ {[
130+ [true, "string"]
131+ ]}
132+
133+ we can use this decoder:
134+
135+ {[
136+ tuple2 bool string
137+ ]}
138+ *)
139+
140+ val tuple3 : 'a decoder -> 'b decoder -> 'c decoder -> ('a * 'b * 'c ) decoder
141+ (* * Decode a collection into an OCaml 3-tuple. *)
142+
143+ val tuple4 :
144+ 'a decoder
145+ -> 'b decoder
146+ -> 'c decoder
147+ -> 'd decoder
148+ -> ('a * 'b * 'c * 'd ) decoder
149+ (* * Decode a collection into an OCaml 4-tuple. *)
121150
122151 (* * {1 Object primitives} *)
123152
Original file line number Diff line number Diff line change @@ -172,13 +172,58 @@ let yojson_basic_suite =
172172 Format. asprintf " @,@[%a@]" pp_error e )
173173 in
174174
175+ let tupleN_test =
176+ " TupleN"
177+ > :: fun _ ->
178+ let module M = struct
179+ type t2 = int * string
180+
181+ let t2_to_string ((i , s ) : t2 ) = Printf. sprintf " (%i, %s)" i s
182+ end in
183+ let open M in
184+ decoder_test
185+ ()
186+ ~decoder: (tuple2 int string )
187+ ~input: {| [149 , " my string" ]| }
188+ ~expected: (149 , " my string" )
189+ ~printer: t2_to_string
190+ in
191+ let empty_list_test =
192+ " empty_list"
193+ > :: fun _ ->
194+ decoder_test
195+ ()
196+ ~decoder: empty_list
197+ ~input: {| [] | }
198+ ~expected: ()
199+ ~printer: (fun () -> Printf. sprintf " ()" )
200+ in
201+ let empty_list_nonempty_test =
202+ " empty_list_enforced"
203+ > :: fun _ ->
204+ let input = {| [1 , 2 ]| } in
205+ let expected_error =
206+ let open Decoders in
207+ Error. make ~context: (`List [ `Int 1 ; `Int 2 ]) " Expected an empty list"
208+ in
209+ match decode_string empty_list input with
210+ | Ok _ ->
211+ assert_string " Expected an error"
212+ | Error error ->
213+ assert_equal expected_error error ~printer: (fun e ->
214+ Format. asprintf " @,@[%a@]" pp_error e )
215+ in
216+
175217 " Yojson.Basic"
176218 > ::: [ list_string_test
177219 ; array_string_test
178220 ; fix_one_of_test
179221 ; mut_rec_test
180222 ; string_or_floatlit_test
181223 ; grouping_errors_test
224+ ; tupleN_test
225+ ; empty_list_test
226+ ; empty_list_nonempty_test
182227 ]
183228
184229
You can’t perform that action at this time.
0 commit comments