123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 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. *)(* *)(*****************************************************************************)typeerror+=Invalid_slotofintlet()=register_error_kind`Permanent~id:"slot.invalid_slot"~title:"invalid slot"~description:"Invalid slot"~pp:(funppfx->Format.fprintfppf"invalid slot: %d"x)Data_encoding.(obj1(req"bad_slot"int31))(functionInvalid_slotx->Somex|_->None)(funx->Invalid_slotx)includeCompare.Int(* TODO? should there be some assertions to verify that slots are
never too big ? Or do that in a storage module that depends on
constants ? *)letencoding=Data_encoding.uint16letpp=Format.pp_print_intletzero=0letsucc=succletto_intx=xletmax_value=(1lsl16)-1letof_int_do_not_use_except_for_parametersi=iletof_int_exni=ifCompare.Int.(i<0||i>max_value)theninvalid_arg(Format.sprintf"valid slot values are in the interval [0, %d] (%d given)"max_valuei)elseimoduleMap=Map.Make(Compare.Int)moduleSet=Set.Make(Compare.Int)moduleList=struct(* Expected invariant: list of increasing values *)(* TODO find a way to properly enforce this invariant *)typenonrect=tlistmoduleCompressed=structtypeelt={skip:int;take:int}typeencoded=eltlistletelt_encoding=Data_encoding.(conv(fun{skip;take}->(skip,take))(fun(skip,take)->{skip;take})(obj2(req"skip"uint16)(req"take"uint16)))letencoding=Data_encoding.listelt_encodingletencodel:encoded=letrecloop_taking~pos~skipped~takenl=matchlwith|[]->iftaken>0then[{skip=skipped;take=taken}]else[]|h::t->ifh=posthenloop_taking~pos:(pos+1)~skipped~taken:(taken+1)telseletelt={skip=skipped;take=taken}inletskipped=h-posinlettaken=1inletelts=loop_taking~pos:(h+1)~skipped~takentinelt::eltsinloop_taking~pos:0~skipped:0~taken:0lletdecode(elts:encoded)=letrecloop~poselts=matcheltswith|[]->Ok[]|elt::elts->(letpos=pos+elt.skipinmatchList.init~when_negative_length:()elt.take(funi->i+pos)with|Okl->(letpos=pos+elt.takeinmatchloop~poseltswithOkt->Ok(l@t)|e->e)|Error()->Error"A compressed element contains a negative list size")inloop~pos:0eltsendletencoding=Data_encoding.conv_with_guardCompressed.encodeCompressed.decodeCompressed.encodingletslot_range~min~count=error_when(min<0)(Invalid_slotmin)>>?fun()->error_when(min>max_value)(Invalid_slotmin)>>?fun()->error_when(count<1)(Invalid_slotcount)>>?fun()->error_when(count>max_value)(Invalid_slotcount)>>?fun()->letmax=min+count-1inerror_when(max>max_value)(Invalid_slotmax)>>?fun()->okMisc.(min-->max)end