123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.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. *)(* *)(*****************************************************************************)moduleStringMap=Map.Make(String)type'keyt='keydescriptionrefand'keydescription=|Empty:'keydescription|Value:{get:'key->'aoptiontzresultLwt.t;encoding:'aData_encoding.t}->'keydescription|NamedDir:'keytStringMap.t->'keydescription|IndexedDir:{arg:'aRPC_arg.t;arg_encoding:'aData_encoding.t;list:'key->'alisttzresultLwt.t;subdir:('key*'a)t}->'keydescriptionletrecregister_named_subcontext:typer.rt->stringlist->rt=fundirnames->match!dir,nameswith|_,[]->dir|Value_,_->invalid_arg""|IndexedDir_,_->invalid_arg""|Empty,name::names->letsubdir=refEmptyindir:=NamedDir(StringMap.singletonnamesubdir);register_named_subcontextsubdirnames|NamedDirmap,name::names->letsubdir=matchStringMap.find_optnamemapwith|Somesubdir->subdir|None->letsubdir=refEmptyindir:=NamedDir(StringMap.addnamesubdirmap);subdirinregister_named_subcontextsubdirnamestype(_,_,_)args=|One:{rpc_arg:'aRPC_arg.t;encoding:'aData_encoding.t;compare:'a->'a->int}->('key,'a,'key*'a)args|Pair:('key,'a,'inter_key)args*('inter_key,'b,'sub_key)args->('key,'a*'b,'sub_key)argsletrecunpack:typeabc.(a,b,c)args->c->a*b=function|One_->(funx->x)|Pair(l,r)->letunpack_l=unpacklinletunpack_r=unpackrinfunx->letc,d=unpack_rxinletb,a=unpack_lcin(b,(a,d))letrecpack:typeabc.(a,b,c)args->a->b->c=function|One_->(funba->(b,a))|Pair(l,r)->letpack_l=packlinletpack_r=packrinfunb(a,d)->letc=pack_lbainpack_rcdletreccompare:typeabc.(a,b,c)args->b->b->int=function|One{compare;_}->compare|Pair(l,r)->letcompare_l=comparelinletcompare_r=comparerinfun(a1,b1)(a2,b2)->matchcompare_la1a2with|0->compare_rb1b2|x->xletdestutterequall=matchlwith|[]->[]|(i,_)::l->letrecloopacci=function|[]->acc|(j,_)::l->ifequalijthenloopaccilelseloop(j::acc)jlinloop[i]illetrecregister_indexed_subcontext:typerab.rt->list:(r->alisttzresultLwt.t)->(r,a,b)args->bt=fundir~listpath->matchpathwith|Pair(left,right)->letcompare_left=compareleftinletequal_leftxy=Compare.Int.(compare_leftxy=0)inletlist_leftr=listr>>=?funl->return(destutterequal_leftl)inletlist_rightr=leta,k=unpackleftrinlista>>=?funl->return(List.mapsnd(List.filter(fun(x,_)->equal_leftxk)l))inregister_indexed_subcontext(register_indexed_subcontextdir~list:list_leftleft)~list:list_rightright|One{rpc_arg=arg;encoding=arg_encoding;_}->match!dirwith|Value_->invalid_arg""|NamedDir_->invalid_arg""|Empty->letsubdir=refEmptyindir:=IndexedDir{arg;arg_encoding;list;subdir};subdir|IndexedDir{arg=inner_arg;subdir;_}->matchRPC_arg.eqarginner_argwith|None->invalid_arg""|SomeRPC_arg.Eq->subdirletregister_value:typeab.at->get:(a->boptiontzresultLwt.t)->bData_encoding.t->unit=fundir~getencoding->match!dirwith|Empty->dir:=Value{get;encoding}|_->invalid_arg""letcreate()=refEmptyletrecpp:typea.Format.formatter->at->unit=funppfdir->match!dirwith|Empty->Format.fprintfppf"EMPTY"|Value_e->Format.fprintfppf"Value"|NamedDirmap->Format.fprintfppf"@[<v>%a@]"(Format.pp_print_listpp_item)(StringMap.bindingsmap)|IndexedDir{arg;subdir;_}->letname=Format.asprintf"<%s>"(RPC_arg.descrarg).nameinpp_itemppf(name,subdir)andpp_item:typea.Format.formatter->(string*at)->unit=funppf(name,dir)->Format.fprintfppf"@[<v 2>%s@ %a@]"nameppdirmoduletypeINDEX=sigtypetvalpath_length:intvalto_path:t->stringlist->stringlistvalof_path:stringlist->toptionvalrpc_arg:tRPC_arg.tvalencoding:tData_encoding.tvalcompare:t->t->intendtype_handler=Handler:{encoding:'aData_encoding.t;get:'key->int->'atzresultLwt.t}->'keyhandlertype_opt_handler=Opt_handler:{encoding:'aData_encoding.t;get:'key->int->'aoptiontzresultLwt.t}->'keyopt_handlerletreccombine_object=function|[]->Handler{encoding=Data_encoding.unit;get=fun__->return_unit}|(name,Opt_handlerhandler)::fields->letHandlerhandlers=combine_objectfieldsinHandler{encoding=Data_encoding.merge_objsData_encoding.(obj1(optname(dynamic_sizehandler.encoding)))handlers.encoding;get=funki->handler.getki>>=?funv1->handlers.getki>>=?funv2->return(v1,v2)}typequery={depth:int;}letdepth_query=letopenRPC_queryinquery(fundepth->{depth})|+field"depth"RPC_arg.int0(funt->t.depth)|>sealletbuild_directory:typekey.keyt->keyRPC_directory.t=fundir->letrpc_dir=ref(RPC_directory.empty:keyRPC_directory.t)inletregister:typeikey.(key,ikey)RPC_path.t->ikeyopt_handler->unit=funpath(Opt_handler{encoding;get})->letservice=RPC_service.get_service~query:depth_query~output:encodingpathinrpc_dir:=RPC_directory.register!rpc_dirservicebeginfunkq()->getk(q.depth+1)>>=?function|None->raiseNot_found|Somex->returnxendinletrecbuild_handler:typeikey.ikeyt->(key,ikey)RPC_path.t->ikeyopt_handler=fundirpath->match!dirwith|Empty->Opt_handler{encoding=Data_encoding.unit;get=fun__->return_none}|Value{get;encoding}->lethandler=Opt_handler{encoding;get=funki->ifCompare.Int.(i<0)thenreturn_noneelsegetk}inregisterpathhandler;handler|NamedDirmap->letfields=StringMap.bindingsmapinletfields=List.map(fun(name,dir)->(name,build_handlerdirRPC_path.(path/name)))fieldsinletHandlerhandler=combine_objectfieldsinlethandler=Opt_handler{encoding=handler.encoding;get=funki->ifCompare.Int.(i<0)thenreturn_noneelsehandler.getk(i-1)>>=?funv->return_somev}inregisterpathhandler;handler|IndexedDir{arg;arg_encoding;list;subdir}->letOpt_handlerhandler=build_handlersubdirRPC_path.(path/:arg)inletencoding=letopenData_encodinginunion[case(Tag0)~title:"Leaf"(dynamic_sizearg_encoding)(function(key,None)->Somekey|_->None)(funkey->(key,None));case(Tag1)~title:"Dir"(tup2(dynamic_sizearg_encoding)(dynamic_sizehandler.encoding))(function(key,Somevalue)->Some(key,value)|_->None)(fun(key,value)->(key,Somevalue));]inletgetki=ifCompare.Int.(i<0)thenreturn_noneelseifCompare.Int.(i=0)thenreturn_some[]elselistk>>=?funkeys->map_s(funkey->ifCompare.Int.(i=1)thenreturn(key,None)elsehandler.get(k,key)(i-1)>>=?funvalue->return(key,value))keys>>=?funvalues->return_somevaluesinlethandler=Opt_handler{encoding=Data_encoding.(list(dynamic_sizeencoding));get;}inregisterpathhandler;handlerinignore(build_handlerdirRPC_path.open_root:keyopt_handler);!rpc_dir