1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654(*****************************************************************************)(* *)(* Open Source License *)(* Copyright 2014 OCamlPro *)(* Copyright (c) 2020 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)exceptionUnexpectedofstring*stringexceptionNo_case_matchedofexnlistexceptionBad_array_sizeofint*intexceptionMissing_fieldofstringexceptionUnexpected_fieldofstringexceptionBad_schemaofexnexceptionCannot_destructof(Json_query.path*exn)(*-- types and errors --------------------------------------------------------*)letunexpectedkindexpected=letkind=matchkindwith|`O[]->"empty object"|`A[]->"empty array"|`O_->"object"|`A_->"array"|`Null->"null"|`String_->"string"|`Float_->"number"|`Bool_->"boolean"inCannot_destruct([],Unexpected(kind,expected))type'trepr_agnostic_custom={write:'rt.(moduleJson_repr.Reprwithtypevalue='rt)->'t->'rt;read:'rf.(moduleJson_repr.Reprwithtypevalue='rf)->'rf->'t;}(* The GADT definition for encodings. This type must be kept internal
because it does not encode all invariants. Some properties are
checked at encoding construction time by smart constructors, since
checking them would either be impossible, or would make the type
too complex. In a few corners that involve custom encodings using
user defined functions, some properties cannot be checked until
construction/destruction time. If such a run time check fails, is
denotes a programmer error and an [Invalid_argument] exceptions is
thus raised. *)type_encoding=|Null:unitencoding|Empty:unitencoding|Ignore:unitencoding|Option:'aencoding->'aoptionencoding|Constant:string->unitencoding|Int:'aint_encoding->'aencoding|Bool:boolencoding|String:stringencoding|Float:boundsoption->floatencoding|Array:'aencoding->'aarrayencoding|Seq:'aencoding->'aSeq.tencoding|Obj:'afield->'aencoding|Objs:'aencoding*'bencoding->('a*'b)encoding|Tup:'aencoding->'aencoding|Tups:'aencoding*'bencoding->('a*'b)encoding|Custom:'trepr_agnostic_custom*Json_schema.schema->'tencoding|Conv:('a->'b)*('b->'a)*'bencoding*Json_schema.schemaoption->'aencoding|Describe:{id:string;title:stringoption;description:stringoption;encoding:'aencoding;}->'aencoding|Mu:{id:string;title:stringoption;description:stringoption;self:'aencoding->'aencoding;}->'aencoding|Union:'tcaselist->'tencodingand'aint_encoding={int_name:string;of_float:float->'a;to_float:'a->float;lower_bound:'a;upper_bound:'a;}andbounds={float_name:string;minimum:float;maximum:float}and_field=|Req:{name:string;encoding:'aencoding;title:stringoption;description:stringoption;}->'afield|Opt:{name:string;encoding:'aencoding;title:stringoption;description:stringoption;}->'aoptionfield|Dft:{name:string;encoding:'aencoding;title:stringoption;description:stringoption;equal:'a->'a->bool;default:'a;construct_default:bool;}->'afieldand'tcase=|Case:{encoding:'aencoding;title:stringoption;description:stringoption;proj:'t->'aoption;inj:'a->'t;}->'tcase(*-- construct / destruct / schema over the main GADT forms ------------------*)moduletypeS=sigtyperepr_valuevalconstruct:?include_default_fields:[`Always|`Auto|`Never]->'tencoding->'t->repr_valuevaldestruct:?bson_relaxation:bool->'tencoding->repr_value->'tvalcustom:('t->repr_value)->(repr_value->'t)->schema:Json_schema.schema->'tencodingendletinc_fieldinclude_default_fieldsconstruct_default=matchinclude_default_fieldswith|`Auto->construct_default|`Never->false|`Always->truemoduleMake(Repr:Json_repr.Repr):Swithtyperepr_value=Repr.value=structtyperepr_value=Repr.valueletconstruct?(include_default_fields=`Auto)encv=letrecconstruct:typet.tencoding->t->Repr.value=function|Null->fun()->Repr.repr`Null|Empty->fun()->Repr.repr(`O[])|Ignore->fun()->Repr.repr(`O[])|Optiont->(functionNone->Repr.repr`Null|Somev->constructtv)|Constantstr->fun()->Repr.repr(`Stringstr)|Int{int_name;to_float;lower_bound;upper_bound}->fun(i:t)->ifi<lower_bound||i>upper_boundtheninvalid_arg("Json_encoding.construct: "^int_name^" out of range");Repr.repr(`Float(to_floati))|Bool->fun(b:t)->Repr.repr(`Boolb)|String->funs->Repr.repr(`Strings)|Float(Some{minimum;maximum;float_name})->leterr="Json_encoding.construct: "^float_name^" out of range"infunfloat->iffloat<minimum||float>maximumtheninvalid_argerr;Repr.repr(`Floatfloat)|FloatNone->funfloat->Repr.repr(`Floatfloat)|Describe{encoding=t}->constructt|Custom({write},_)->fun(j:t)->write(moduleRepr)j|Conv(ffrom,_,t,_)->funv->constructt(ffromv)|Mu{self}asenc->construct(selfenc)|Arrayt->letwv=constructtvinfunarr->Repr.repr(`A(Array.to_list(Array.mapwarr)))|Seqt->letwv=constructtvinfuns->Repr.repr(`A(List.of_seq(Seq.mapws)))|Obj(Req{name=n;encoding=t})->letwv=constructtvinfunv->Repr.repr(`O[(n,wv)])|Obj(Dft{name=n;equal;encoding=t;default=d;construct_default})->letwv=constructtvinletinc_default=inc_fieldinclude_default_fieldsconstruct_defaultinfunv->Repr.repr(`O(ifinc_default||not(equalvd)then[(n,wv)]else[]))|Obj(Opt{name=n;encoding=t})->(letwv=constructtvinfunction|None->Repr.repr(`O[])|Somev->Repr.repr(`O[(n,wv)]))|Objs(o1,o2)->(letw1v=constructo1vinletw2v=constructo2vinfunction|v1,v2->(match(Repr.view(w1v1),Repr.view(w2v2))with|`Ol1,`Ol2->Repr.repr(`O(l1@l2))|`Null,`Null|_->invalid_arg"Json_encoding.construct: consequence of bad merge_objs"))|Tupt->letwv=constructtvinfunv->Repr.repr(`A[wv])|Tups(o1,o2)->(letw1v=constructo1vinletw2v=constructo2vinfunction|v1,v2->(match(Repr.view(w1v1),Repr.view(w2v2))with|`Al1,`Al2->Repr.repr(`A(l1@l2))|_->invalid_arg"Json_encoding.construct: consequence of bad merge_tups"))|Unioncases->funv->letrecdo_cases=function|[]->invalid_arg"Json_encoding.construct: consequence of bad union"|Case{encoding;proj}::rest->(matchprojvwith|Somev->constructencodingv|None->do_casesrest)indo_casescasesinconstructencv(* Used for bson_relaxation to convert objs to arrs *)letmaybe_array_in_disguisefs=letrecis_maybe_array_in_disguiserev_accindex=function|[]->Some(List.revrev_acc)|(s,v)::o->ifstring_of_intindex=sthenis_maybe_array_in_disguise(v::rev_acc)(index+1)oelseNoneinis_maybe_array_in_disguise[]0fs(* NOTE: bson relaxation is only an issue at top-level (see comment in
interface). Hence, we set it to false on recursive calls that are actually
nested, no matter its value. *)letrecdestruct:typet.bson_relaxation:bool->tencoding->Repr.value->t=fun~bson_relaxationenc->matchencwith|Null->(funv->matchRepr.viewvwith|`Null->()|k->raise(unexpectedk"null"))|Empty->(funv->matchRepr.viewvwith|`O[]->()|`O[(f,_)]->raise(Cannot_destruct([],Unexpected_fieldf))|k->raise@@unexpectedk"an empty object")|Ignore->(funv->matchRepr.viewvwith_->())|Optiont->(funv->matchRepr.viewvwith|`Null->None|_->Some(destruct~bson_relaxationtv))|Constantstr->(funv->matchRepr.viewvwith|`Stringswhens=str->()|x->raise@@unexpectedxstr)|Int{int_name;of_float;to_float;lower_bound;upper_bound}->(letlower_bound=to_floatlower_boundinletupper_bound=to_floatupper_boundinfunv->matchRepr.viewvwith|`Floatv->letrest,v=modfvin(ifrest<>0.thenletexn=Failure(int_name^" cannot have a fractional part")inraise(Cannot_destruct([],exn)));(ifv<lower_bound||v>upper_boundthenletexn=Failure(int_name^" out of range")inraise(Cannot_destruct([],exn)));of_floatv|k->raise(unexpectedk"number"))|Bool->(funv->matchRepr.viewvwith|`Boolb->(b:t)|k->raise(unexpectedk"boolean"))|String->(funv->matchRepr.viewvwith|`Strings->s|k->raise(unexpectedk"string"))|FloatNone->(funv->matchRepr.viewvwith|`Floatf->f|k->raise(unexpectedk"float"))|Float(Some{minimum;maximum;float_name})->(funv->matchRepr.viewvwith|`Floatf->iff<minimum||f>maximumthenletexn=Failure(float_name^" out of range")inraise(Cannot_destruct([],exn))elsef|k->raise(unexpectedk"float"))|Describe{encoding=t}->destruct~bson_relaxationt|Custom({read},_)->read(moduleRepr)|Conv(_,fto,t,_)->funv->fto(destruct~bson_relaxationtv)|Mu{self}asenc->destruct~bson_relaxation(selfenc)|Arrayt->(letarray_of_cellscells=Array.mapi(funicell->trydestruct~bson_relaxation:falsetcellwithCannot_destruct(path,err)->raise(Cannot_destruct(`Indexi::path,err)))(Array.of_listcells)infunv->matchRepr.viewvwith|`O[]->(* For backwards compatibility, we handle [[]] with the
[bson_relaxation] semantic even if it is not set. *)[||]|`Oowhenbson_relaxation->((* Weak `Repr`s like BSON don't know the difference *)matchmaybe_array_in_disguiseowith|Somecells->array_of_cellscells|None->raise@@unexpected(`Oo)"array")|`Acells->array_of_cellscells|k->raise@@unexpectedk"array")|Seqt->(letseq_of_cellscells=leti=ref(-1)inSeq.map(funcell->tryincri;destruct~bson_relaxation:falsetcellwithCannot_destruct(path,err)->raise(Cannot_destruct(`Index!i::path,err)))(List.to_seqcells)infunv->matchRepr.viewvwith|`O[]->(* For backwards compatibility, we handle [[]] with the
[bson_relaxation] semantic even if it is not set. *)Seq.empty|`Oowhenbson_relaxation->((* Weak `Repr`s like BSON don't know the difference *)matchmaybe_array_in_disguiseowith|Somecells->seq_of_cellscells|None->raise@@unexpected(`Oo)"array")|`Acells->seq_of_cellscells|k->raise@@unexpectedk"array")|Obj_ast->(letd=destruct_objtinfunv->matchRepr.viewvwith|`Ofields->(letr,rest,ign=dfieldsinmatchrestwith|(field,_)::_whennotign->raise@@Unexpected_fieldfield|_->r)|k->raise@@unexpectedk"object")|Objs_ast->(letd=destruct_objtinfunv->matchRepr.viewvwith|`Ofields->(letr,rest,ign=dfieldsinmatchrestwith|(field,_)::_whennotign->raise@@Unexpected_fieldfield|_->r)|k->raise@@unexpectedk"object")|Tup_ast->(letr,i=destruct_tup0tinlettup_of_cellscells=letcells=Array.of_listcellsinletlen=Array.lengthcellsinifi<>Array.lengthcellsthenraise(Cannot_destruct([],Bad_array_size(len,i)))elsercellsinfunv->matchRepr.viewvwith|`Oowhenbson_relaxation->((* Weak `Repr`s like BSON don't know the difference *)matchmaybe_array_in_disguiseowith|Somecells->tup_of_cellscells|None->raise@@unexpected(`Oo)"array")|`Acells->tup_of_cellscells|k->raise@@unexpectedk"array")|Tups_ast->(letr,i=destruct_tup0tinlettups_of_cellscells=letcells=Array.of_listcellsinletlen=Array.lengthcellsinifi<>Array.lengthcellsthenraise(Cannot_destruct([],Bad_array_size(len,i)))elsercellsinfunv->matchRepr.viewvwith|`Oowhenbson_relaxation->((* Weak `Repr`s like BSON don't know the difference *)matchmaybe_array_in_disguiseowith|Somecells->tups_of_cellscells|None->raise@@unexpected(`Oo)"array")|`Acells->tups_of_cellscells|k->raise@@unexpectedk"array")|Unioncases->funv->letrecdo_caseserrs=function|[]->raise(Cannot_destruct([],No_case_matched(List.reverrs)))|Case{encoding;inj}::rest->(tryinj(destruct~bson_relaxationencodingv)witherr->do_cases(err::errs)rest)indo_cases[]casesanddestruct_tup:typet.int->tencoding->(Repr.valuearray->t)*int=funit->matchtwith|Tupt->((funarr->trydestruct~bson_relaxation:falsetarr.(i)withCannot_destruct(path,err)->raise(Cannot_destruct(`Indexi::path,err))),succi)|Tups(t1,t2)->letr1,i=destruct_tupit1inletr2,i=destruct_tupit2in((funarr->(r1arr,r2arr)),i)|Conv(_,fto,t,_)->letr,i=destruct_tupitin((funarr->fto(rarr)),i)|Mu{self}asenc->destruct_tupi(selfenc)|Describe{encoding}->destruct_tupiencoding|_->invalid_arg"Json_encoding.destruct: consequence of bad merge_tups"anddestruct_obj:typet.tencoding->(string*Repr.value)list->t*(string*Repr.value)list*bool=funt->letrecassocaccn=function|[]->raiseNot_found|(f,v)::restwhenn=f->(v,List.rev_appendaccrest)|oth::rest->assoc(oth::acc)nrestinmatchtwith|Empty->funfields->((),fields,false)|Ignore->funfields->((),fields,true)|Obj(Req{name=n;encoding=t})->(funfields->tryletv,rest=assoc[]nfieldsin(destruct~bson_relaxation:falsetv,rest,false)with|Not_found->raise(Cannot_destruct([],Missing_fieldn))|Cannot_destruct(path,err)->raise(Cannot_destruct(`Fieldn::path,err)))|Obj(Opt{name=n;encoding=t})->(funfields->tryletv,rest=assoc[]nfieldsin(Some(destruct~bson_relaxation:falsetv),rest,false)with|Not_found->(None,fields,false)|Cannot_destruct(path,err)->raise(Cannot_destruct(`Fieldn::path,err)))|Obj(Dft{name=n;encoding=t;default=d})->(funfields->tryletv,rest=assoc[]nfieldsin(destruct~bson_relaxation:falsetv,rest,false)with|Not_found->(d,fields,false)|Cannot_destruct(path,err)->raise(Cannot_destruct(`Fieldn::path,err)))|Objs(o1,o2)->letd1=destruct_objo1inletd2=destruct_objo2infunfields->letr1,rest,ign1=d1fieldsinletr2,rest,ign2=d2restin((r1,r2),rest,ign1||ign2)|Conv(_,fto,t,_)->letd=destruct_objtinfunfields->letr,rest,ign=dfieldsin(ftor,rest,ign)|Mu{self}asenc->destruct_obj(selfenc)|Describe{encoding}->destruct_objencoding|Unioncases->funfields->letrecdo_caseserrs=function|[]->raise(Cannot_destruct([],No_case_matched(List.reverrs)))|Case{encoding;inj}::rest->(tryletr,rest,ign=destruct_objencodingfieldsin(injr,rest,ign)witherr->do_cases(err::errs)rest)indo_cases[]cases|_->invalid_arg"Json_encoding.destruct: consequence of bad merge_objs"letdestruct?(bson_relaxation=false)ev=destruct~bson_relaxationevletcustomwriteread~schema=letread:typetf.(moduleJson_repr.Reprwithtypevalue=tf)->tf->'t=fun(moduleRepr_f)repr->read(Json_repr.convert(moduleRepr_f)(moduleRepr)repr)inletwrite:typetf.(moduleJson_repr.Reprwithtypevalue=tf)->'t->tf=fun(moduleRepr_f)v->Json_repr.convert(moduleRepr)(moduleRepr_f)(writev)inCustom({read;write},schema)endmoduleEzjsonm_encoding=Make(Json_repr.Ezjsonm)letpatch_description?title?description(elt:Json_schema.element)=match(title,description)with|None,None->elt|Some_,None->{eltwithtitle}|None,Some_->{eltwithdescription}|Some_,Some_->{eltwithtitle;description}letschema?definitions_pathencoding=letopenJson_schemainletsch=refanyinletprodl1l2=List.concat_map(fun(l1,b1,e1)->List_map.map_pure(fun(l2,b2,e2)->(l1@l2,b1||b2,match(e1,e2)withSomee,_|_,Somee->Somee|_->None))l2)l1inletrecobject_schema:typet.tencoding->((string*element*bool*Json_repr.anyoption)list*bool*elementoption)list=function|Conv(_,_,o,None)->object_schemao|Empty->[([],false,None)]|Ignore->[([],true,None)]|Obj(Req{name=n;encoding=t;title;description})->[([(n,patch_description?title?description(schemat),true,None)],false,None);]|Obj(Opt{name=n;encoding=t;title;description})->[([(n,patch_description?title?description(schemat),false,None)],false,None);]|Obj(Dft{name=n;encoding=t;title;description;default=d})->letd=Json_repr.repr_to_any(moduleJson_repr.Ezjsonm)(Ezjsonm_encoding.constructtd)in[([(n,patch_description?title?description(schemat),false,Somed);],false,None);]|Objs(o1,o2)->prod(object_schemao1)(object_schemao2)|Union[]->invalid_arg"Json_encoding.schema: empty union in object"|Unioncases->List.concat_map(fun(Case{encoding=o;title;description})->letelt=patch_description?title?description(schemao)inmatchobject_schemaowith|[(l,b,_)]->[(l,b,Someelt)]|l->l)cases|Mu{self}asenc->object_schema(selfenc)|Describe{title;description;encoding}->(letelt=patch_description?title?description(schemaencoding)inmatchobject_schemaencodingwith|[(l,b,_)]->[(l,b,Someelt)]|l->l)|Conv(_,_,_,Some_)(* FIXME: We could do better *)|_->invalid_arg"Json_encoding.schema: consequence of bad merge_objs"andarray_schema:typet.tencoding->elementlist=function|Conv(_,_,o,None)->array_schemao|Tupt->[schemat]|Tups(t1,t2)->array_schemat1@array_schemat2|Mu{self}asenc->array_schema(selfenc)|Describe{encoding=t}->array_schemat|Conv(_,_,_,Some_)(* FIXME: We could do better *)|_->invalid_arg"Json_encoding.schema: consequence of bad merge_tups"andschema:typet.tencoding->element=function|Null->elementNull|Empty->element(Object{object_specswithadditional_properties=None})|Ignore->elementAny|Optiont->element(Combine(One_of,[schemat;elementNull]))|Int{to_float;lower_bound;upper_bound}->letminimum=Some(to_floatlower_bound,`Inclusive)inletmaximum=Some(to_floatupper_bound,`Inclusive)inelement(Integer{multiple_of=None;minimum;maximum})|Bool->elementBoolean|Constantstr->{(element(Stringstring_specs))withenum=Some[Json_repr.to_any(`Stringstr)];}|String->element(Stringstring_specs)|Float(Some{minimum;maximum})->element(Number{multiple_of=None;minimum=Some(minimum,`Inclusive);maximum=Some(maximum,`Inclusive);})|FloatNone->element(Numbernumeric_specs)|Describe{id=name;title;description;encoding}->letschema=patch_description?title?description(schemaencoding)inlets,def=add_definition?definitions_pathnameschema!schinsch:=fst(merge_definitions(!sch,s));def|Custom(_,s)->sch:=fst(merge_definitions(!sch,s));roots|Conv(_,_,_,Somes)->sch:=fst(merge_definitions(!sch,s));roots|Conv(_,_,t,None)->schemat|Mu{id=name;title;description;self=f}->letfake_schema=ifdefinition_exists?definitions_pathname!schthenupdate(definition_ref?definitions_pathname)!schelseletsch,elt=add_definition?definitions_pathname(elementDummy)!schinupdateeltschinletfake_self=Custom({write=(fun__->assertfalse);read=(fun_->assertfalse)},fake_schema)inletroot=patch_description?title?description(schema(ffake_self))inletnsch,def=add_definition?definitions_pathnameroot!schinsch:=nsch;def|Arrayt->element(Monomorphic_array(schemat,array_specs))|Seqt->element(Monomorphic_array(schemat,array_specs))|Objs_aso->(matchobject_schemaowith|[(properties,ext,elt)]->(letadditional_properties=ifextthenSome(elementAny)elseNoneinmatcheltwith|None->element(Object{object_specswithproperties;additional_properties})|Someelt->{(element(Object{object_specswithproperties;additional_properties}))withtitle=elt.title;description=elt.description;})|more->letelements=List_map.map_pure(fun(properties,ext,elt)->letadditional_properties=ifextthenSome(elementAny)elseNoneinmatcheltwith|None->element(Object{object_specswithproperties;additional_properties})|Someelt->{(element(Object{object_specswithproperties;additional_properties;}))withtitle=elt.title;description=elt.description;})moreinelement(Combine(One_of,elements)))|Obj_aso->(matchobject_schemaowith|[(properties,ext,elt)]->(letadditional_properties=ifextthenSome(elementAny)elseNoneinmatcheltwith|None->element(Object{object_specswithproperties;additional_properties})|Someelt->{(element(Object{object_specswithproperties;additional_properties}))withtitle=elt.title;description=elt.description;})|more->letelements=List_map.map_pure(fun(properties,ext,elt)->letadditional_properties=ifextthenSome(elementAny)elseNoneinmatcheltwith|None->element(Object{object_specswithproperties;additional_properties})|Someelt->{(element(Object{object_specswithproperties;additional_properties;}))withtitle=elt.title;description=elt.description;})moreinelement(Combine(One_of,elements)))|Tup_ast->element(Array(array_schemat,array_specs))|Tups_ast->element(Array(array_schemat,array_specs))|Unioncases->(* FIXME: smarter merge *)letelements=List_map.map_pure(fun(Case{encoding;title;description})->patch_description?title?description(schemaencoding))casesinelement(Combine(One_of,elements))andschema_specialization_first_pass:typet.tencoding->element=(* This function is needed as to not create a level of inderaction when creating
a top-level def. *)funencoding->matchencodingwith|Describe{title;description;encoding;_}->letschema=patch_description?title?description(schemaencoding)inschema|_->schemaencodinginletschema=schema_specialization_first_passencodinginupdateschema!sch(*-- utility wrappers over the GADT ------------------------------------------*)letreq?title?descriptionnt=Req{name=n;encoding=t;title;description}letopt?title?descriptionnt=Opt{name=n;encoding=t;title;description}letdft?title?description?(equal=(=))?(construct=false)ntd=Dft{name=n;encoding=t;title;description;equal;default=d;construct_default=construct;}letmuname?title?descriptionself=letmem=refNoneinletselfe=match!memwith|Some(e_param,e_result)whene_param==e->e_result|_->lete_result=selfeinmem:=Some(e,e_result);e_resultinMu{id=name;title;description;self}letnull=Nullletint=Int{int_name="int";of_float=int_of_float;to_float=float_of_int;(* cross-platform consistent OCaml ints *)lower_bound=-(1lsl30);upper_bound=(1lsl30)-1;}letranged_int~minimum:lower_bound~maximum:upper_boundname=ifSys.word_size=64&&(lower_bound<-(1lsl30)||upper_bound>(1lsl30)-1)theninvalid_arg"Json_encoding.ranged_int: bounds out of portable int31 range";Int{int_name=name;of_float=int_of_float;to_float=float_of_int;lower_bound;upper_bound;}letint53=Int{int_name="int53";of_float=Int64.of_float;to_float=Int64.to_float;lower_bound=Int64.neg(Int64.shift_left1L53);upper_bound=Int64.shift_left1L53;}letranged_int53~minimum:lower_bound~maximum:upper_boundname=iflower_bound<Int64.neg(Int64.shift_left1L53)||upper_bound>Int64.shift_left1L53theninvalid_arg"Json_encoding.ranged_int53: bounds out of JSON-representable integers";Int{int_name=name;of_float=Int64.of_float;to_float=Int64.to_float;lower_bound;upper_bound;}letint32=Int{int_name="int32";of_float=Int32.of_float;to_float=Int32.to_float;lower_bound=Int32.min_int;upper_bound=Int32.max_int;}letranged_int32~minimum:lower_bound~maximum:upper_boundname=Int{int_name=name;of_float=Int32.of_float;to_float=Int32.to_float;lower_bound;upper_bound;}letranged_float~minimum~maximumfloat_name=Float(Some{minimum;maximum;float_name})letfloat=FloatNoneletstring=Stringletconvffromfto?schemat=Conv(ffrom,fto,t,schema)letbytes=Conv(Bytes.to_string,Bytes.of_string,string,None)letbool=Boolletarrayt=Arraytletseqt=Seqtletobj1f1=Objf1letobj2f1f2=Objs(Objf1,Objf2)letobj3f1f2f3=conv(fun(a,b,c)->(a,(b,c)))(fun(a,(b,c))->(a,b,c))(Objs(Objf1,Objs(Objf2,Objf3)))letobj4f1f2f3f4=conv(fun(a,b,c,d)->(a,(b,(c,d))))(fun(a,(b,(c,d)))->(a,b,c,d))(Objs(Objf1,Objs(Objf2,Objs(Objf3,Objf4))))letobj5f1f2f3f4f5=conv(fun(a,b,c,d,e)->(a,(b,(c,(d,e)))))(fun(a,(b,(c,(d,e))))->(a,b,c,d,e))(Objs(Objf1,Objs(Objf2,Objs(Objf3,Objs(Objf4,Objf5)))))letobj6f1f2f3f4f5f6=conv(fun(a,b,c,d,e,f)->(a,(b,(c,(d,(e,f))))))(fun(a,(b,(c,(d,(e,f)))))->(a,b,c,d,e,f))(Objs(Objf1,Objs(Objf2,Objs(Objf3,Objs(Objf4,Objs(Objf5,Objf6))))))letobj7f1f2f3f4f5f6f7=conv(fun(a,b,c,d,e,f,g)->(a,(b,(c,(d,(e,(f,g)))))))(fun(a,(b,(c,(d,(e,(f,g))))))->(a,b,c,d,e,f,g))(letrest=Objs(Objf6,Objf7)inObjs(Objf1,Objs(Objf2,Objs(Objf3,Objs(Objf4,Objs(Objf5,rest))))))letobj8f1f2f3f4f5f6f7f8=conv(fun(a,b,c,d,e,f,g,h)->(a,(b,(c,(d,(e,(f,(g,h))))))))(fun(a,(b,(c,(d,(e,(f,(g,h)))))))->(a,b,c,d,e,f,g,h))(letrest=Objs(Objf6,Objs(Objf7,Objf8))inObjs(Objf1,Objs(Objf2,Objs(Objf3,Objs(Objf4,Objs(Objf5,rest))))))letobj9f1f2f3f4f5f6f7f8f9=conv(fun(a,b,c,d,e,f,g,h,i)->(a,(b,(c,(d,(e,(f,(g,(h,i)))))))))(fun(a,(b,(c,(d,(e,(f,(g,(h,i))))))))->(a,b,c,d,e,f,g,h,i))(letrest=Objs(Objf6,Objs(Objf7,Objs(Objf8,Objf9)))inObjs(Objf1,Objs(Objf2,Objs(Objf3,Objs(Objf4,Objs(Objf5,rest))))))letobj10f1f2f3f4f5f6f7f8f9f10=conv(fun(a,b,c,d,e,f,g,h,i,j)->(a,(b,(c,(d,(e,(f,(g,(h,(i,j))))))))))(fun(a,(b,(c,(d,(e,(f,(g,(h,(i,j)))))))))->(a,b,c,d,e,f,g,h,i,j))(letrest=Objs(Objf6,Objs(Objf7,Objs(Objf8,Objs(Objf9,Objf10))))inObjs(Objf1,Objs(Objf2,Objs(Objf3,Objs(Objf4,Objs(Objf5,rest))))))lettup1f1=Tupf1lettup2f1f2=Tups(Tupf1,Tupf2)lettup3f1f2f3=conv(fun(a,b,c)->(a,(b,c)))(fun(a,(b,c))->(a,b,c))(Tups(Tupf1,Tups(Tupf2,Tupf3)))lettup4f1f2f3f4=conv(fun(a,b,c,d)->(a,(b,(c,d))))(fun(a,(b,(c,d)))->(a,b,c,d))(Tups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tupf4))))lettup5f1f2f3f4f5=conv(fun(a,b,c,d,e)->(a,(b,(c,(d,e)))))(fun(a,(b,(c,(d,e))))->(a,b,c,d,e))(Tups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tups(Tupf4,Tupf5)))))lettup6f1f2f3f4f5f6=conv(fun(a,b,c,d,e,f)->(a,(b,(c,(d,(e,f))))))(fun(a,(b,(c,(d,(e,f)))))->(a,b,c,d,e,f))(Tups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tups(Tupf4,Tups(Tupf5,Tupf6))))))lettup7f1f2f3f4f5f6f7=conv(fun(a,b,c,d,e,f,g)->(a,(b,(c,(d,(e,(f,g)))))))(fun(a,(b,(c,(d,(e,(f,g))))))->(a,b,c,d,e,f,g))(letrest=Tups(Tupf6,Tupf7)inTups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tups(Tupf4,Tups(Tupf5,rest))))))lettup8f1f2f3f4f5f6f7f8=conv(fun(a,b,c,d,e,f,g,h)->(a,(b,(c,(d,(e,(f,(g,h))))))))(fun(a,(b,(c,(d,(e,(f,(g,h)))))))->(a,b,c,d,e,f,g,h))(letrest=Tups(Tupf6,Tups(Tupf7,Tupf8))inTups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tups(Tupf4,Tups(Tupf5,rest))))))lettup9f1f2f3f4f5f6f7f8f9=conv(fun(a,b,c,d,e,f,g,h,i)->(a,(b,(c,(d,(e,(f,(g,(h,i)))))))))(fun(a,(b,(c,(d,(e,(f,(g,(h,i))))))))->(a,b,c,d,e,f,g,h,i))(letrest=Tups(Tupf6,Tups(Tupf7,Tups(Tupf8,Tupf9)))inTups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tups(Tupf4,Tups(Tupf5,rest))))))lettup10f1f2f3f4f5f6f7f8f9f10=conv(fun(a,b,c,d,e,f,g,h,i,j)->(a,(b,(c,(d,(e,(f,(g,(h,(i,j))))))))))(fun(a,(b,(c,(d,(e,(f,(g,(h,(i,j)))))))))->(a,b,c,d,e,f,g,h,i,j))(letrest=Tups(Tupf6,Tups(Tupf7,Tups(Tupf8,Tups(Tupf9,Tupf10))))inTups(Tupf1,Tups(Tupf2,Tups(Tupf3,Tups(Tupf4,Tups(Tupf5,rest))))))letrepr_agnostic_custom{write;read}~schema=Custom({write;read},schema)letconstants=Constantsletstring_enumcases=letschema=letspecs=Json_schema.string_specsinletenum=List_map.map_pure(fun(s,_)->Json_repr.(repr_to_any(moduleEzjsonm))(`Strings))casesinJson_schema.(update{(element(Stringspecs))withenum=Someenum}any)inletlen=List.lengthcasesinletmcases=Hashtbl.createlenandrcases=Hashtbl.createleninletcases_str=matchcaseswith|[]->""|c::cs->letb=Buffer.create128inBuffer.add_charb'\'';Buffer.add_stringb(fstc);Buffer.add_charb'\'';List.iter(func->Buffer.add_charb' ';Buffer.add_charb'\'';Buffer.add_stringb(fstc);Buffer.add_charb'\'')cs;Buffer.contentsbinList.iter(fun(s,c)->ifHashtbl.memmcasesstheninvalid_arg"Json_encoding.string_enum: duplicate case";Hashtbl.addmcasessc;Hashtbl.addrcasescs)cases;conv(funv->tryHashtbl.findrcasesvwithNot_found->invalid_arg(Format.sprintf"Json_encoding.construct: consequence of non exhaustive \
Json_encoding.string_enum. Strings are: %s"cases_str))(funs->tryHashtbl.findmcasesswithNot_found->letrecorpatppf=function|[]->assertfalse|[(last,_)]->Format.fprintfppf"%S"last|[(prev,_);(last,_)]->Format.fprintfppf"%S or %S"prevlast|(prev,_)::rem->Format.fprintfppf"%S , %a"prevorpatreminletunexpected=Format.asprintf"string value %S"sinletexpected=Format.asprintf"%a"orpatcasesinraise(Cannot_destruct([],Unexpected(unexpected,expected))))~schemastringletdefid?title?descriptionencoding=Describe{id;title;description;encoding}letassoc:typet.?definitions_path:string->tencoding->(string*t)listencoding=fun?definitions_patht->Ezjsonm_encoding.custom(funl->`O(List_map.map_pure(fun(n,v)->(n,Ezjsonm_encoding.constructtv))l))(funv->matchvwith|`Ol->letdestructntv=tryEzjsonm_encoding.destructtvwithCannot_destruct(p,exn)->raise(Cannot_destruct(`Fieldn::p,exn))inList_map.map_pure(fun(n,v)->(n,destructntv))l|#Json_repr.ezjsonmask->raise(unexpectedk"asssociative object"))~schema:(lets=schema?definitions_pathtinJson_schema.(update(element(Object{object_specswithadditional_properties=Some(roots)}))s))letrecis_nullable:typet.tencoding->bool=function|Constant_->false|Int_->false|Float_->false|Array_->false|Seq_->false|Empty->false|String->false|Bool->false|Obj_->false|Tup_->false|Objs_->false|Tups_->false|Null->true|Ignore->true|Option_->true|Conv(_,_,t,_)->is_nullablet|Unioncases->List.exists(fun(Case{encoding=t})->is_nullablet)cases|Describe{encoding=t}->is_nullablet|Mu{self}asenc->is_nullable(selfenc)|Custom(_,sch)->Json_schema.is_nullableschletoption:typet.tencoding->toptionencoding=funt->ifis_nullablettheninvalid_arg"Json_encoding.option: cannot nest nullable encodings";Optiontletany_value=letreadreprv=Json_repr.repr_to_anyreprvinletwritereprv=Json_repr.any_to_reprreprvinCustom({read;write},Json_schema.any)letany_ezjson_value=letreadreprv=Json_repr.convertrepr(moduleJson_repr.Ezjsonm)vinletwritereprv=Json_repr.convert(moduleJson_repr.Ezjsonm)reprvinCustom({read;write},Json_schema.any)letany_document=letread:typett.(moduleJson_repr.Reprwithtypevalue=tt)->tt->Json_repr.any=fun(moduleRepr)v->matchRepr.viewvwith|`A_|`O_->Json_repr.repr_to_any(moduleRepr)v|k->raise@@unexpectedk"array or object"inletwritereprv=Json_repr.any_to_reprreprvinCustom({read;write},Json_schema.any)letany_schema=Ezjsonm_encoding.customJson_schema.to_json(funj->tryJson_schema.of_jsonjwitherr->raise(Cannot_destruct([],Bad_schemaerr)))~schema:Json_schema.selfletmerge_tupst1t2=letrecis_tup:typet.tencoding->bool=function|Tup_->true|Tups_(* by construction *)->true|Conv(_,_,t,None)->is_tupt|Mu{self}asenc->is_tup(selfenc)|Describe{encoding=t}->is_tupt|_->falseinifis_tupt1&&is_tupt2thenTups(t1,t2)elseinvalid_arg"Json_encoding.merge_tups"letlistt=Conv(Array.of_list,Array.to_list,Arrayt,None)letmerge_objso1o2=(* FIXME: check fields unicity *)letrecis_obj:typet.tencoding->bool=function|Obj_->true|Objs_(* by construction *)->true|Conv(_,_,t,None)->is_objt|Empty->true|Ignore->true|Unioncases->List.for_all(fun(Case{encoding=o})->is_objo)cases|Mu{self}asenc->is_obj(selfenc)|Describe{encoding=t}->is_objt|_->falseinifis_objo1&&is_objo2thenObjs(o1,o2)elseinvalid_arg"Json_encoding.merge_objs"letempty=Emptyletunit=Ignoreletcase?title?descriptionencodingprojinj=Case{encoding;proj;inj;title;description}letunion=function|[]->invalid_arg"Json_encoding.union"|cases->(* FIXME: check mutual exclusion *)Unioncasesletrecprint_error?print_unknownppf=function|Cannot_destruct([],exn)->print_error?print_unknownppfexn|Cannot_destruct(path,Unexpected(unex,ex))->Format.fprintfppf"At %a, unexpected %s instead of %s"(Json_query.print_path_as_json_path~wildcards:true)pathunexex|Cannot_destruct(path,No_case_matchederrs)->Format.fprintfppf"@[<v 2>At %a, no case matched:@,%a@]"(Json_query.print_path_as_json_path~wildcards:true)path(Format.pp_print_list(print_error?print_unknown))errs|Cannot_destruct(path,Bad_array_size(unex,ex))->Format.fprintfppf"At %a, unexpected array of size %d instead of %d"(Json_query.print_path_as_json_path~wildcards:true)pathunexex|Cannot_destruct(path,Missing_fieldn)->Format.fprintfppf"At %a, missing object field %s"(Json_query.print_path_as_json_path~wildcards:true)pathn|Cannot_destruct(path,Unexpected_fieldn)->Format.fprintfppf"At %a, unexpected object field %s"(Json_query.print_path_as_json_path~wildcards:true)pathn|Cannot_destruct(path,Bad_schemaexn)->Format.fprintfppf"@[<v 2>At %a, bad custom schema:@,%a@]"(Json_query.print_path_as_json_path~wildcards:true)path(print_error?print_unknown)exn|Unexpected(unex,ex)->Format.fprintfppf"Unexpected %s instead of %s"unexex|No_case_matchederrs->Format.fprintfppf"@[<v 2>No case matched:@,%a@]"(Format.pp_print_list(print_error?print_unknown))errs|Bad_array_size(unex,ex)->Format.fprintfppf"Unexpected array of size %d instead of %d"unexex|Missing_fieldn->Format.fprintfppf"Missing object field %s"n|Unexpected_fieldn->Format.fprintfppf"Unexpected object field %s"n|Bad_schemaexn->Format.fprintfppf"@[<v 2>bad custom schema:@,%a@]"(print_error?print_unknown)exn|Cannot_destruct(path,exn)->Format.fprintfppf"@[<v 2>At %a:@,%a@]"(Json_query.print_path_as_json_path~wildcards:true)path(print_error?print_unknown)exn|exn->Json_schema.print_error?print_unknownppfexnincludeEzjsonm_encoding(* An alternative construction method that produces a [Seq.t] of Json lexeme
(compatible with [Jsonm.lexeme Seq.t]).
This alternative gives a lazy construction where the consumer of the returned
value requests further chunks as needed. This in turns allows for yielding in
Lwt/Async contexts. *)(* [jsonm_lexeme] is the type of json lexeme compatible with [Jsonm.lexeme].
Note that [Jsonm] was made before the [Seq.t] type was available in the
OCaml's standard-library.
@see https://erratique.ch/software/jsonm/doc/Jsonm/ Jsonm documentation *)typejsonm_lexeme=[`Null|`Boolofbool|`Stringofstring|`Floatoffloat|`Nameofstring|`As|`Ae|`Os|`Oe]moduleJsonmLexemeSeq=struct(* First, a few helper functions for operating on [Seq.t] *)(* [++] is a constructor: [x ++ xs] is the sequence that starts with [x] and
continues with [xs], it is equivalent to [Seq.cons] (available in OCaml
4.11). *)let(++)vs()=Seq.Cons(v,s)(* [@] concatenates two sequences together. [xs @ ys] is a sequence that
contains the elements from the seuqence [xs] followed by the elements of
the sequence [ys]. It is equivalent to [Seq.append] (available in OCaml
4.11). *)letrec(@)(s1:'aSeq.t)(s2:'aSeq.t):'aSeq.t=fun()->matchs1()with|Seq.Nil->s2()|Seq.Cons(v,s1)->Seq.Cons(v,s1@s2)(* [s +< c +> e] is a sequence that starts with [s], continues with [c] and
ends with [e]. Below, this form is used to add object (resp. array)
delimiters ([`Os]/[`Oe]) (resp. ([`As]/[`Ae])) around the sequence of
lexemes that represents the contents of the object (resp. array). *)let(+<)=(++)let(+@)=(@)let(+>)sv=s@Seq.returnv(* [null] is a lexeme sequence representation of the null json value ([null]) *)letnull=Seq.return`Null(* [empty_obj] is a lexeme sequence representation of the empty json object ([{}]). *)letempty_obj=letopenSeqinfun()->Cons(`Os,fun()->Cons(`Oe,empty))(* [empty_arr] is a lexeme sequence representation of the empty json array ([[]]). *)letempty_arr=letopenSeqinfun()->Cons(`As,fun()->Cons(`Ae,empty))(* convert an ezjsonm object into a lexeme sequence. This is useful for the
[Custom] tag.
An alternative is to have a [Json_repr.JsonmLexemeSeq] module to have a
direct [Custom]-to-jsonm-lexeme function. However, the specifics of the
[Repr] is not friendly to the jsonm-lexeme. Specifically the function
[view: value -> value view] requires to force the whole of the sequence. We
do not use [view] for writing so we might provide this in the future.
The implementation is rather straightforward, except that empty objects and
empty arrays are special-cased for performance. In the future, more
specific objects/arrays might also be (e.g., objects that contain a single
field with an immediate (non-nested) value). *)letrecjsonm_lexeme_seq_of_ezjsonezj=matchezjwith|`O[]->empty_obj|`Okvs->`Os+<jsonm_lexeme_seq_of_ezjson_kvskvs+>`Oe|`A[]->empty_arr|`Avs->`As+<jsonm_lexeme_seq_of_ezjson_vsvs+>`Ae|`Boolb->Seq.return(`Boolb)|`Floatf->Seq.return(`Floatf)|`Strings->Seq.return(`Strings)|`Null->null(* we extract the two following sub-functions because we need them for
special cases when constructing objects/tups *)andjsonm_lexeme_seq_of_ezjson_kvskvs=Seq.flat_map(fun(k,v)->`Namek++jsonm_lexeme_seq_of_ezjsonv)(List.to_seqkvs)andjsonm_lexeme_seq_of_ezjson_vsvs=Seq.flat_map(funv->jsonm_lexeme_seq_of_ezjsonv)(List.to_seqvs)letconstruct_seq?(include_default_fields=`Auto)encv=(* The main entry-point, it is mutually recursive with some other entry
points for specific "states" of the "state-machine" that this function
represents.
Note that this function mimics the {!Make}[.construct] function above in
this module. There are a few entries that differ, this is due to the
different target of the function (a sequence of lexeme vs an AST). In
those cases, comments are provided. *)letrecconstruct:typet.tencoding->t->jsonm_lexemeSeq.t=function|Null->fun(():t)->null|Empty->fun()->empty_obj|Ignore->fun()->empty_obj|Optiont->(functionNone->null|Somev->(construct[@ocaml.tailcall])tv)|Constantstr->fun()->Seq.return(`Stringstr)|Int{int_name;to_float;lower_bound;upper_bound}->fun(i:t)->ifi<lower_bound||i>upper_boundtheninvalid_arg("Json_encoding.construct_seq: "^int_name^" out of range");Seq.return(`Float(to_floati))|Bool->fun(b:t)->Seq.return(`Boolb)|String->funs->Seq.return(`Strings)|Float(Some{minimum;maximum;float_name})->funfloat->iffloat<minimum||float>maximumtheninvalid_arg("Json_encoding.construct_seq: "^float_name^" out of range");Seq.return(`Floatfloat)|FloatNone->funfloat->Seq.return(`Floatfloat)|Describe{encoding=t}->funv->(construct[@ocaml.tailcall])tv|Custom({write},_)->funv->letezjson=write(moduleJson_repr.Ezjsonm)vinjsonm_lexeme_seq_of_ezjsonezjson|Conv(ffrom,_,t,_)->funv->(construct[@ocaml.tailcall])t(ffromv)|Mu{self}asenc->funv->(construct[@ocaml.tailcall])(selfenc)v|Arrayt->(function[||]->empty_arr|vs->`As+<construct_arrtvs+>`Ae)|Seqt->funs->`As+<construct_seq_ts+>`Ae|Obj(Req{name=n;encoding=t})->funv->`Os+<construct_namedntv+>`Oe|Obj(Dft{name=n;equal;encoding=t;default=d;construct_default})->funv->letinc_default=inc_fieldinclude_default_fieldsconstruct_defaultinifinc_default||not(equalvd)then`Os+<construct_namedntv+>`Oeelseempty_obj|Obj(Opt{name=n;encoding=t})->(function|None->empty_obj|Somev->`Os+<construct_namedntv+>`Oe)|Objs(o1,o2)->(* For the objects inside an [Objs] we go to a different state of
the state-machine: we call the entry-point [construct_obj].
Note that the non-seq construction simply builds the
sub-objects and pops the content out of the object AST node.
This is not viable here because it'd force the sequence to
remove the last lexeme ([`Oe]). Trying a hybrid approach of
doing standard construction followed by a lazy Object delimiter
popping is more complicated than shifting to a different
state/entry-point. *)fun(v1,v2)->`Os+<construct_objo1v1+@construct_objo2v2+>`Oe|Tupt->funv->`As+<constructtv+>`Ae|Tups(o1,o2)->fun(v1,v2)->(* Similar to the Objs construction *)`As+<construct_tupo1v1+@construct_tupo2v2+>`Ae|Unioncases->funv->letrecdo_cases=function|[]->invalid_arg"Json_encoding.construct_seq: consequence of bad union"|Case{encoding;proj}::rest->(matchprojvwith|Somev->(construct[@ocaml.tailcall])encodingv|None->do_casesrest)indo_casescasesandconstruct_arr:typet.tencoding->tarray->jsonm_lexemeSeq.t=funtvs->(* TODO: optimise this one for tailcall ? *)Seq.flat_map(funv->constructtv)(Array.to_seqvs)andconstruct_seq_:typet.tencoding->tSeq.t->jsonm_lexemeSeq.t=funtvs->Seq.flat_map(funv->constructtv)vsandconstruct_named:typet.string->tencoding->t->jsonm_lexemeSeq.t=funntv->`Namen++constructtvandconstruct_obj(* NOTE: we recurse on [construct_obj] (i.e., we stay in the same state
of the same machine) for all the constructors present in [is_obj]. *):typet.tencoding->t->jsonm_lexemeSeq.t=function|Obj(Req{name=n;encoding=t})->funv->construct_namedntv|Obj(Dft{name=n;equal;encoding=t;default=d;construct_default})->funv->letinc_default=inc_fieldinclude_default_fieldsconstruct_defaultinifinc_default||not(equalvd)thenconstruct_namedntvelseSeq.empty|Obj(Opt{name=n;encoding=t})->(functionNone->Seq.empty|Somev->construct_namedntv)|Obj_->.(* asserting we have covered all Obj cases to ensure that it cannot
go through the wildcard [_] below. *)|Objs(o1,o2)->fun(v1,v2)->construct_objo1v1@construct_objo2v2|Conv(ffrom,_,t,_)->funv->construct_objt(ffromv)|Empty->fun()->Seq.empty|Ignore->fun()->Seq.empty|Mu{self}asenc->funv->construct_obj(selfenc)v|Describe{encoding=t}->funv->construct_objtv|Unioncases->funv->letrecdo_cases=function|[]->invalid_arg"Json_encoding.construct_seq: consequence of bad union"|Case{encoding;proj}::rest->(matchprojvwith|Somev->construct_objencodingv|None->do_casesrest)indo_casescases|Custom({write},_)->(funv->(* NOTE: This constructor is not in [is_obj] (because it is not
possible to statically determine whether it always produces
object) but it must be special-cased anyway. *)matchwrite(moduleJson_repr.Ezjsonm)vwith|`Okvs->jsonm_lexeme_seq_of_ezjson_kvskvs|`A_|`Bool_|`Float_|`String_|`Null->invalid_arg"Json_encoding.construct_seq: consequence of bad merge_objs")|_->(* In all other cases we raise a runtime exception. This is similar
to the way vanilla [construct] handles recursive calls returning
non-objects in the construction of an [Objs]. *)invalid_arg"Json_encoding.construct_seq: consequence of bad merge_objs"andconstruct_tup(* Similar to construct_obj, but for tups *):typet.tencoding->t->jsonm_lexemeSeq.t=function|Tupt->funv->(construct[@ocaml.tailcall])tv|Tups(o1,o2)->fun(v1,v2)->construct_tupo1v1@construct_tupo2v2|Conv(ffrom,_,t,_)->funv->construct_tupt(ffromv)|Mu{self}asenc->funv->construct_tup(selfenc)v|Describe{encoding=t}->funv->construct_tuptv|Custom({write},_)->(funv->matchwrite(moduleJson_repr.Ezjsonm)vwith|`Avs->jsonm_lexeme_seq_of_ezjson_vsvs|`O_|`Bool_|`Float_|`String_|`Null->invalid_arg"Json_encoding.construct_seq: consequence of bad merge_tups")|_->invalid_arg"Json_encoding.construct_seq: consequence of bad merge_tups"inconstructencvend(* Exporting the important values from [JsonmLexemeSeq] *)letconstruct_seq:?include_default_fields:[`Always|`Auto|`Never]->'tencoding->'t->jsonm_lexemeSeq.t=JsonmLexemeSeq.construct_seqletjsonm_lexeme_seq_of_ezjson=JsonmLexemeSeq.jsonm_lexeme_seq_of_ezjson