123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337typenonrec('v,'e)result=('v,'e)resultmoduleRecord_in=structtype(_,_,_)t=|Cons:(string*('t->'a)*'aoption)*('t,'b,'c)t->('t,'a->'b,'c)t|Nil:('t,'a,'a)tlet(^::)ab=Cons(a,b)endmoduleRecord_out=structtype(_,_,_)t=|Cons:(string*('a->'t)*'aoption)*('t,'b,'c)t->('t,'a->'b,'c)t|Nil:('t,'a,'a)tlet(^::)ab=Cons(a,b)endmoduleTuple_in=structtype(_,_,_)t=|Cons:('t->'a)*('t,'b,'c)t->('t,'a->'b,'c)t|Nil:('t,'a,'a)tlet(^::)ab=Cons(a,b)endmoduleTuple_out=structtype(_,_,_)t=|Cons:('a->'t)*('t,'b,'c)t->('t,'a->'b,'c)t|Nil:('t,'a,'a)tlet(^::)ab=Cons(a,b)endmoduleVariant_in=structtype(_,_)t=Variant:string*('a,'constr,'c)Tuple_in.t*'constr->('a,'c)tend(** Signature for a driver. Serialization function are on the form [of_XXX] and
deserialization function are on the form [to_XXX].
All deserialization functions should only raise [Protocol_error] is the type could not be desrialized.
*)moduletypeDriver=sig(** Serialized type. This type should not be opaque, so it is recommended that
drivers implement the signature as [Runtime.Driver with type t = ... ]
*)typet(** Opaque error type *)typeerror(** Exception for protocol errors. The driver should make sure that
this is the only exception raised when deserializing *)exceptionProtocol_erroroferror(** Construct an error to be raised from a custom parser. *)valmake_error:?value:t->string->error(** Convert an error type to a human readable string *)valerror_to_string_hum:error->string(** Convert t to a string *)valto_string_hum:t->string(** Wrap deserialization function to convert exceptions into an result type *)valtry_with:(t->'v)->t->('v,error)resultvalto_variant:(t,'a)Variant_in.tlist->t->'avalof_variant:string->(t,'a,t)Tuple_out.t->'avalto_record:(t,'constr,'b)Record_in.t->'constr->t->'bvalof_record:(t,'a,t)Record_out.t->'avalto_tuple:(t,'constr,'b)Tuple_in.t->'constr->t->'bvalof_tuple:(t,'a,t)Tuple_out.t->'avalto_option:(t->'a)->t->'aoptionvalof_option:('a->t)->'aoption->tvalto_ref:(t->'a)->t->'arefvalof_ref:('a->t)->'aref->tvalto_list:(t->'a)->t->'alistvalof_list:('a->t)->'alist->tvalto_array:(t->'a)->t->'aarrayvalof_array:('a->t)->'aarray->tvalto_lazy_t:(t->'a)->t->'alazy_tvalof_lazy_t:('a->t)->'alazy_t->tvalto_result:(t->'a)->(t->'b)->t->('a,'b)resultvalof_result:('a->t)->('b->t)->('a,'b)result->tvalto_int:t->intvalof_int:int->tvalto_int32:t->int32valof_int32:int32->tvalto_int64:t->int64valof_int64:int64->tvalto_nativeint:t->nativeintvalof_nativeint:nativeint->tvalto_char:t->charvalof_char:char->tvalto_string:t->stringvalof_string:string->tvalto_float:t->floatvalof_float:float->tvalto_bool:t->boolvalof_bool:bool->tvalto_bytes:t->bytesvalof_bytes:bytes->tvalto_unit:t->unitvalof_unit:unit->tend(** Module contains helper function for serializing and deserializing tuples, records and variants.
Deserialization functions may raise [Helper.Protocol] exception. It is recommended that the calling functions
convert this exception into a [Driver.Protocol_exception]
*)moduleHelper=structopenStdLabels(** Tail recursive version of map *)letlist_map~fl=letslow_map~ftl=List.rev_map~ftl|>List.revinletreccount_map~flctr=matchlwith|[]->[]|[x1]->letf1=fx1in[f1]|[x1;x2]->letf1=fx1inletf2=fx2in[f1;f2]|[x1;x2;x3]->letf1=fx1inletf2=fx2inletf3=fx3in[f1;f2;f3]|[x1;x2;x3;x4]->letf1=fx1inletf2=fx2inletf3=fx3inletf4=fx4in[f1;f2;f3;f4]|x1::x2::x3::x4::x5::tl->letf1=fx1inletf2=fx2inletf3=fx3inletf4=fx4inletf5=fx5inf1::f2::f3::f4::f5::(ifctr>1000thenslow_map~ftlelsecount_map~ftl(ctr+1))incount_map~fl0let()=letl=[1;2;3;4;5]inletl'=list_map~f:(funx->x+2)linletl''=List.map~f:(funx->x+2)linassert(l'=l'');(** Excpetion raised if the type could not be serialized *)exceptionProtocol_errorofstring(**/**)moduletypeLookup=sigvalof_alist:(string*'a)list->string->'aoptionendmoduleHashtbl_lookup:Lookup=struct(* 20.22% *)letof_alistalist=lettbl=Hashtbl.create0inList.iter~f:(fun(k,v)->Hashtbl.addtblkv)alist;funk->matchHashtbl.findtblkwith|k->Somek|exceptionNot_found->NoneendmoduleLookup=Hashtbl_lookupletraise_errorf:('a,unit,string,'b)format4->'a=funfmt->Printf.ksprintf(funs->raise(Protocol_errors))fmt(**/**)(** Map fields names of a [Record_in] structure *)letrecmap_record_in:typetab.(string->string)->(t,a,b)Record_in.t->(t,a,b)Record_in.t=funfield->function|Record_in.Cons((field_name,to_value_func,default),xs)->Record_in.Cons((fieldfield_name,to_value_func,default),map_record_infieldxs)|Record_in.Nil->Record_in.Nil(** {!to_record spec constructor ts} returns the constructed value.
[ts] is a associative array [(string * t)] list, mapping fields to the deserialized value [t]
if [strict] is true, an error will be raised if input contains an unknown field.
If dublicate fields are found in the input, an error is raised
*)letto_record:typetconstrb.?strict:bool->(t,constr,b)Record_in.t->constr->(string*t)list->b=letrecto_alist:typeabc.int->(a,b,c)Record_in.t->(string*int)list=funidx->function|Record_in.Cons((field,_,_),xs)->(field,idx)::to_alist(idx+1)xs|Record_in.Nil->[]inletrecinner:typeconstr.int->(t,constr,b)Record_in.t->constr->toptionarray->b=funidx->letopenRecord_ininletvalue_ofto_vfielddefaultt=matcht,defaultwith|Somet,_->to_vt|None,Somed->d|None,None->raise_errorf"Missing record field: %s"fieldinfunction|(Cons((n1,f1,d1),xs))->letcont=inner(idx+1)xsinfunconstrvalues->letv1=value_off1n1d1values.(idx+0)incont(constrv1)values|Nil->funa_values->ainfun?(strict=false)specconstr->letlookup,count=letalist=to_alist0specinLookup.of_alistalist,List.lengthalistinletf=inner0specconstrinfunvalues->letvalue_array=Array.makecountNoneinList.iter~f:(fun(field,t)->matchlookupfieldwith|Nonewhenstrict->raise_errorf"Unused field when deserialising record: %s"field|None->()|Someidx->beginmatchvalue_array.(idx)with|Some_->raise_errorf"Multiple fields with the same name: %s"field|None->value_array.(idx)<-Sometend)values;fvalue_array(** Map fields names of a [Record_out] structure *)letrecmap_record_out:typeta.(string->string)->(t,a,t)Record_out.t->(t,a,t)Record_out.t=funfield->letopenRecord_outinfunction|Cons((field_name,to_t,default),xs)->Cons((fieldfield_name,to_t,default),map_record_outfieldxs)|Nil->Niltype'tserialize_record=(string*'t)list->'t(** {!of_record map_f spec} produces a valid deserialisation function for a record type
The [map_f] function is called to produce the serialized result from a field_name, t association list.
If [omit_default] is true, then default values are omitted from the output
*)letof_record:typetat.omit_default:bool->tserialize_record->(t,a,t)Record_out.t->a=fun~omit_defaultserialize_record->letrecinner:typea.(t,a,t)Record_out.t->(string*t)list->a=letopenRecord_outinfunction|Cons((n1,f1,Somed1),xs)whenomit_default->beginletcont=innerxsinfunaccv1->matchd1=v1with|true->contacc|false->cont((n1,f1v1)::acc)end|Cons((n1,f1,_),xs)->letcont=innerxsinfunaccv1->cont((n1,f1v1)::acc)|Record_out.Nil->funacc->serialize_recordaccinfunspec->innerspec[](** {!to_tuple spec tlist} produces a tuple from the serialized values in [tlist] *)letrecto_tuple:typetab.(t,a,b)Tuple_in.t->a->tlist->b=letopenTuple_ininfunction|Cons(f1,xs)->beginletcont=to_tuplexsinfunconstructor->function|v1::ts->cont(constructor(f1v1))ts|_->raise_errorf"Too few elements when parsing tuple"end|Nil->funa->beginfunction|[]->a|_->raise_errorf"Too many elements when parsing tuple"endtype'tserialize_tuple='tlist->'tletof_tuple:typeta.tserialize_tuple->(t,a,t)Tuple_out.t->a=funserialize_tuple->letrecinner:typea.(t,a,t)Tuple_out.t->tlist->a=letopenTuple_outinfunction|Cons(f1,Cons(f2,(Cons(f3,(Cons(f4,Nil))))))->funaccv1v2v3v4->List.rev_appendacc[f1v1;f2v2;f3v3;f4v4]|>serialize_tuple|Cons(f1,Cons(f2,(Cons(f3,Nil))))->funaccv1v2v3->List.rev_appendacc[f1v1;f2v2;f3v3]|>serialize_tuple|Cons(f1,Cons(f2,Nil))->funaccv1v2->List.rev_appendacc[f1v1;f2v2]|>serialize_tuple|Cons(f1,Nil)->funaccv1->List.rev_appendacc[f1v1]|>serialize_tuple|Nil->funacc->List.revacc|>serialize_tuple|Cons(f1,Cons(f2,(Cons(f3,(Cons(f4,Cons(f5,xs)))))))->letcont=innerxsinfunaccv1v2v3v4v5->cont(f5v5::f4v4::f3v3::f2v2::f1v1::acc)infunspec->innerspec[]type'tserialize_variant=string->'tlist->'t(** {!of_variant spec v} serializes v and returns the serialized values
as a list or map
*)letof_variant:typet.tserialize_variant->string->(t,'a,t)Tuple_out.t->'a=funserialize_variantnamespec->of_tuple(serialize_variantname)spec(** Map field names in all inline records of the spec *)letmap_constructor_names:(string->string)->('t,'a)Variant_in.tlist->('t,'a)Variant_in.tlist=funconstructorvariant->List.mapvariant~f:(fun(Variant_in.Variant(name,spec,constr))->Variant_in.Variant(constructorname,spec,constr))letto_variant:('t,'a)Variant_in.tlist->string->'tlist->'a=funspec->letlookup=List.mapspec~f:(fun(Variant_in.Variant(name,spec,constr))->name,to_tuplespecconstr)|>Lookup.of_alistinfunnameargs->matchlookupnamewith|None->raise_errorf"Unknown variant name: %s"name|Somef->fargsend