@@ -101,17 +101,29 @@ module type Driver = sig
101101 val of_unit : unit -> t
102102end
103103
104- (* * This module contains helper functions for serializing and deserializing
105- tuples, records and variants. *)
104+ (* * Module contains helper function for serializing and deserializing tuples, records and variants.
105+ Deserialization functions may raise [Helper.Protocol] exception. It is recommended that the calling functions
106+ convert this exception into a [Driver.Protocol_exception]
107+ *)
106108module Helper = struct
109+
110+ (* * Excpetion raised if the type could not be serialized *)
107111 exception Protocol_error of string
108112
109113 (* */**)
114+ module type Lookup = sig
115+ val of_alist : (string * 'a ) list -> string -> 'a option
116+ end
117+ module Hashtbl_lookup : Lookup = struct (* 20.22% *)
118+ let of_alist alist =
119+ let tbl = Hashtbl. of_alist_exn (module String ) alist in
120+ Hashtbl. find tbl
121+ end
122+ module Lookup = Hashtbl_lookup
123+
110124 let raise_errorf: ('a, unit , string , 'b) format4 -> 'a = fun fmt -> Printf. ksprintf (fun s -> raise (Protocol_error s)) fmt
111125 (* */**)
112126
113- type 'a variant = Record of (string * 'a ) list | Tuple of 'a list | Nil
114-
115127 (* * Map fields names of a [Record_in] structure *)
116128 let rec map_record_in : type t a b. (string -> string) -> (t, a, b) Record_in.t -> (t, a, b) Record_in.t = fun field -> function
117129 | Record_in. Cons ((field_name , to_value_func , default ), xs ) ->
@@ -130,37 +142,32 @@ module Helper = struct
130142 | Record_in. Nil -> []
131143 in
132144 let rec inner : type constr. int -> (t, constr, b) Record_in.t -> constr -> t option array -> b = fun idx ->
145+ let open Record_in in
146+ let value_of to_v field default t = match t, default with
147+ | Some t , _ -> to_v t
148+ | None , Some d -> d
149+ | None , None -> raise_errorf " Missing record field: %s" field
150+ in
133151 function
134- | Record_in. Cons ((_field , to_value_func , Some default ), xs ) ->
152+ | ( Cons ((n1 , f1 , d1 ), xs ) ) ->
135153 let cont = inner (idx + 1 ) xs in
136154 fun constr values ->
137- let v = match values.(idx) with
138- | None -> default
139- | Some t -> to_value_func t
140- in
141- cont (constr v) values
142- | Record_in. Cons ((field , to_value_func , None), xs ) ->
143- let cont = inner (idx + 1 ) xs in
144- fun constr values ->
145- let v = match values.(idx) with
146- | None -> raise_errorf " Missing record field: %s" field
147- | Some t -> to_value_func t
148- in
149- cont (constr v) values
150- | Record_in. Nil -> fun a _map -> a
155+ let v1 = value_of f1 n1 d1 values.(idx + 0 ) in
156+ cont (constr v1) values
157+
158+ | Nil -> fun a _values -> a
151159 in
152160 fun ?(strict =false ) spec constr ->
153- let table =
154- to_alist 0 spec
155- |> Hashtbl. of_alist_exn ( module String )
161+ let lookup, count =
162+ let alist = to_alist 0 spec in
163+ Lookup. of_alist alist, List. length alist
156164 in
157- let count = Hashtbl. length table in
158165 let f = inner 0 spec constr in
159166
160167 fun values ->
161168 let value_array = Array. create ~len: count None in
162169 List. iter ~f: (fun (field , t ) ->
163- match Hashtbl. find table field with
170+ match lookup field with
164171 | None when strict -> raise_errorf " Unused field when deserialising record: %s" field
165172 | None -> ()
166173 | Some idx -> begin
@@ -186,47 +193,100 @@ module Helper = struct
186193 *)
187194 let of_record: type t a t. omit_default:bool -> t serialize_record -> (t, a, t) Record_out. t -> a =
188195 fun ~omit_default serialize_record ->
189- let rec inner : type a. (t, a, t) Record_out.t -> (string * t) list -> a = function
190- | Record_out. Cons (( field , to_t , default ), xs ) ->
191- let cont = inner xs in
192- let f = match omit_default, default with
193- | true , Some d -> begin
194- fun acc -> function
195- | v when Poly. equal v d -> cont acc
196- | v -> cont ((field, to_t v) :: acc)
196+ let value =
197+ match omit_default with
198+ | false -> fun n f _d -> fun v acc -> (n, f v) :: acc
199+ | true -> fun n f d -> begin match d with
200+ | Some d -> begin
201+ fun v acc -> match Poly. equal v d with
202+ | true -> acc
203+ | false -> (n, f v) :: acc
197204 end
198- | _ , _ -> fun acc v -> cont ((field, to_t v) :: acc)
199- in
200- f
205+ | None -> fun v acc -> (n, f v) :: acc
206+ end
207+ in
208+ let rec inner : type a. (t, a, t) Record_out.t -> (string * t) list -> a =
209+ let open Record_out in
210+ function
211+ | Cons ((n1 , f1 , d1 ), xs ) ->
212+ let cont = inner xs in
213+ let vf1 = value n1 f1 d1 in
214+ fun acc v1 ->
215+ cont (vf1 v1 acc)
216+
201217 | Record_out. Nil ->
202218 fun acc -> serialize_record acc
203219 in
204220 fun spec -> inner spec []
205221
206222 (* * {!to_tuple spec tlist} produces a tuple from the serialized values in [tlist] *)
207223 let rec to_tuple : type t a b. (t, a, b) Tuple_in.t -> a -> t list -> b =
224+ let open Tuple_in in
208225 function
209- | Tuple_in. Cons (to_value_func , xs ) ->
210- let cont = to_tuple xs in
211- fun constructor -> begin function
212- | t :: ts ->
213- let v = to_value_func t in
214- cont (constructor v) ts
215- | [] -> raise_errorf " Too few elements when parsing tuple"
216- end
217- | Tuple_in. Nil -> fun a -> function
226+ | Cons (f1 , Cons (f2 , Cons (f3 , Cons (f4 , Cons (f5 , Nil))))) -> begin
227+ fun constructor -> function
228+ | [v1; v2; v3; v4; v5] -> constructor (f1 v1) (f2 v2) (f3 v3) (f4 v4) (f5 v5)
229+ | _ :: _ :: _ :: _ :: _ :: _ :: _ -> raise_errorf " Too many elements when parsing tuple"
230+ | _ -> raise_errorf " Too few elements when parsing tuple"
231+ end
232+ | Cons (f1 , Cons (f2 , Cons (f3 , Cons (f4 , Nil)))) -> begin
233+ fun constructor -> function
234+ | [v1; v2; v3; v4] -> constructor (f1 v1) (f2 v2) (f3 v3) (f4 v4)
235+ | _ :: _ :: _ :: _ :: _ :: _ -> raise_errorf " Too many elements when parsing tuple"
236+ | _ -> raise_errorf " Too few elements when parsing tuple"
237+ end
238+ | Cons (f1 , Cons (f2 , Cons (f3 , Nil))) -> begin
239+ fun constructor -> function
240+ | [v1; v2; v3] -> constructor (f1 v1) (f2 v2) (f3 v3)
241+ | _ :: _ :: _ :: _ :: _ -> raise_errorf " Too many elements when parsing tuple"
242+ | _ -> raise_errorf " Too few elements when parsing tuple"
243+ end
244+ | Cons (f1 , Cons (f2 , Nil)) -> begin
245+ fun constructor -> function
246+ | [v1; v2] -> constructor (f1 v1) (f2 v2)
247+ | _ :: _ :: _ :: _ -> raise_errorf " Too many elements when parsing tuple"
248+ | _ -> raise_errorf " Too few elements when parsing tuple"
249+ end
250+ | Cons (f1 , Nil) -> begin
251+ fun constructor -> function
252+ | [v1] -> constructor (f1 v1)
253+ | _ :: _ :: _ -> raise_errorf " Too many elements when parsing tuple"
254+ | _ -> raise_errorf " Too few elements when parsing tuple"
255+ end
256+ | Nil -> fun a -> begin
257+ function
218258 | [] -> a
219259 | _ -> raise_errorf " Too many elements when parsing tuple"
260+ end
261+
262+ | Cons (f1 , Cons (f2 , Cons (f3 , Cons (f4 , Cons (f5 , xs ))))) -> begin
263+ let cont = to_tuple xs in
264+ fun constructor -> function
265+ | v1 :: v2 :: v3 :: v4 :: v5 :: ts -> cont (constructor (f1 v1) (f2 v2) (f3 v3) (f4 v4) (f5 v5)) ts
266+ | _ -> raise_errorf " Too few elements when parsing tuple"
267+ end
220268
221269 type 't serialize_tuple = 't list -> 't
222270 let of_tuple: type t a. t serialize_tuple -> (t, a, t) Tuple_out. t -> a = fun serialize_tuple ->
223- let rec inner : type a. (t, a, t) Tuple_out.t -> t list -> a = function
224- | Tuple_out. Cons (to_t , xs ) ->
225- let cont = inner xs in
226- fun acc v ->
227- cont (to_t v :: acc)
228- | Tuple_out. Nil ->
271+ let rec inner : type a. (t, a, t) Tuple_out.t -> t list -> a =
272+ let open Tuple_out in
273+ function
274+ | Cons (f1 , Cons (f2 , (Cons (f3 , (Cons (f4 , Cons (f5 , Nil))))))) ->
275+ fun acc v1 v2 v3 v4 v5 -> List. rev_append acc [f1 v1; f2 v2; f3 v3; f4 v4; f5 v5] |> serialize_tuple
276+ | Cons (f1 , Cons (f2 , (Cons (f3 , (Cons (f4 , Nil)))))) ->
277+ fun acc v1 v2 v3 v4 -> List. rev_append acc [f1 v1; f2 v2; f3 v3; f4 v4] |> serialize_tuple
278+ | Cons (f1 , Cons (f2 , (Cons (f3 , Nil)))) ->
279+ fun acc v1 v2 v3 -> List. rev_append acc [f1 v1; f2 v2; f3 v3] |> serialize_tuple
280+ | Cons (f1 , Cons (f2 , Nil)) ->
281+ fun acc v1 v2 -> List. rev_append acc [f1 v1; f2 v2] |> serialize_tuple
282+ | Cons (f1 , Nil) ->
283+ fun acc v1 -> List. rev_append acc [f1 v1] |> serialize_tuple
284+ | Nil ->
229285 fun acc -> List. rev acc |> serialize_tuple
286+
287+ | Cons (f1 , Cons (f2 , (Cons (f3 , (Cons (f4 , Cons (f5 , xs ))))))) ->
288+ let cont = inner xs in
289+ fun acc v1 v2 v3 v4 v5 -> cont (f5 v5 :: f4 v4 :: f3 v3 :: f2 v2 :: f1 v1 :: acc)
230290 in
231291 fun spec -> inner spec []
232292
@@ -245,12 +305,12 @@ module Helper = struct
245305 List. map variant ~f: (fun (Variant_in. Variant (name , spec , constr )) -> Variant_in. Variant (constructor name, spec, constr))
246306
247307 let to_variant: ('t, 'a) Variant_in. t list -> string -> 't list -> 'a = fun spec ->
248- let table =
308+ let lookup =
249309 List. map spec ~f: (fun (Variant_in. Variant (name , spec , constr )) -> name, to_tuple spec constr)
250- |> Hashtbl. of_alist_exn ( module String )
310+ |> Lookup. of_alist
251311 in
252312 fun name args ->
253- match Hashtbl. find table name with
313+ match lookup name with
254314 | None -> raise_errorf " Unknown variant name: %s" name
255315 | Some f -> f args
256316end
0 commit comments