Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file commonInc.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011(******************************************************************************
* capnp-ocaml
*
* Copyright (c) 2013-2014, Paul Pelzl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
******************************************************************************)(* Runtime support which is common to both Reader and Builder interfaces. *)letsizeof_uint32=4letsizeof_uint64=8letinvalid_msg=Message.invalid_msgletout_of_int_range=Message.out_of_int_rangetypero=Message.rotyperw=Message.rwmoduleMake(MessageWrapper:MessageSig.S)=structincludeMessageWrapperletbounds_check_slice_exn?err(slice:'capSlice.t):unit=letopenSliceinifslice.segment_id<0||slice.segment_id>=Message.num_segmentsslice.msg||slice.start<0||slice.start+slice.len>Segment.length(Slice.get_segmentslice)thenleterror_msg=matcherrwith|None->"pointer referenced a memory region outside the message"|Somemsg->msgininvalid_msgerror_msgelse()(** Get the range of bytes associated with a pointer stored in a struct. *)letss_get_pointer(struct_storage:('cap,'a)StructStorage.t)(word:int)(* Struct-relative pointer index *):'capSlice.toption=(* Returns None if storage is too small for this word *)letpointers=struct_storage.StructStorage.pointersinletstart=word*sizeof_uint64inletlen=sizeof_uint64inifstart+len<=pointers.Slice.lenthenSome{pointerswithSlice.start=pointers.Slice.start+start;Slice.len=len}elseNoneletdecode_pointer64(pointer64:int64):Pointer.t=ifUtil.is_int64_zeropointer64thenPointer.Nullelseletpointer_int=Int64.to_intpointer64inlettag=pointer_intlandPointer.Bitfield.tag_maskin(* OCaml won't match an int against let-bound variables,
only against constants. *)matchtagwith|0x0->(* Pointer.Bitfield.tag_val_struct *)Pointer.Struct(StructPointer.decodepointer64)|0x1->(* Pointer.Bitfield.tag_val_list *)Pointer.List(ListPointer.decodepointer64)|0x2->(* Pointer.Bitfield.tag_val_far *)Pointer.Far(FarPointer.decodepointer64)|0x3->(* Pointer.Bitfield.tag_val_other *)Pointer.Other(OtherPointer.decodepointer64)|_->assertfalse(* Given a range of eight bytes corresponding to a cap'n proto pointer,
decode the information stored in the pointer. *)letdecode_pointer(pointer_bytes:'capSlice.t):Pointer.t=letpointer64=Slice.get_int64pointer_bytes0indecode_pointer64pointer64letmake_list_storage_aux~message~num_words~num_elements~storage_type~segment_id~segment_offset=letstorage={Slice.msg=message;Slice.segment=Message.get_segmentmessagesegment_id;Slice.segment_id=segment_id;Slice.start=segment_offset;Slice.len=num_words*sizeof_uint64;}inlet()=bounds_check_slice_exn~err:"list pointer describes invalid storage region"storagein{ListStorage.storage=storage;ListStorage.storage_type=storage_type;ListStorage.num_elements=num_elements;}(* Given a list pointer descriptor, construct the corresponding list storage
descriptor. *)letmake_list_storage~(message:'capMessage.t)(* Message of interest *)~(segment_id:int)(* Segment ID where list storage is found *)~(segment_offset:int)(* Segment offset where list storage is found *)~(list_pointer:ListPointer.t):'capListStorage.t=letopenListPointerinmatchlist_pointer.element_typewith|Void->make_list_storage_aux~message~num_words:0~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Empty~segment_id~segment_offset|OneBitValue->make_list_storage_aux~message~num_words:(Util.ceil_ratiolist_pointer.num_elements64)~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Bit~segment_id~segment_offset|OneByteValue->make_list_storage_aux~message~num_words:(Util.ceil_ratiolist_pointer.num_elements8)~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Bytes1~segment_id~segment_offset|TwoByteValue->make_list_storage_aux~message~num_words:(Util.ceil_ratiolist_pointer.num_elements4)~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Bytes2~segment_id~segment_offset|FourByteValue->make_list_storage_aux~message~num_words:(Util.ceil_ratiolist_pointer.num_elements2)~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Bytes4~segment_id~segment_offset|EightByteValue->make_list_storage_aux~message~num_words:list_pointer.num_elements~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Bytes8~segment_id~segment_offset|EightBytePointer->make_list_storage_aux~message~num_words:list_pointer.num_elements~num_elements:list_pointer.num_elements~storage_type:ListStorageType.Pointer~segment_id~segment_offset|Composite->ifsegment_id<0||segment_id>=Message.num_segmentsmessagetheninvalid_msg"composite list pointer describes invalid tag region"elseletsegment=Message.get_segmentmessagesegment_idinifsegment_offset+sizeof_uint64>Segment.lengthsegmenttheninvalid_msg"composite list pointer describes invalid tag region"elseletpointer64=Segment.get_int64segmentsegment_offsetinletpointer_int=Int64.to_intpointer64inlettag=pointer_intlandPointer.Bitfield.tag_maskiniftag=Pointer.Bitfield.tag_val_structthenletstruct_pointer=StructPointer.decodepointer64inletnum_words=list_pointer.num_elementsinletnum_elements=struct_pointer.StructPointer.offsetinletwords_per_element=struct_pointer.StructPointer.data_words+struct_pointer.StructPointer.pointer_wordsinifnum_elements*words_per_element>num_wordstheninvalid_msg"composite list pointer describes invalid word count"elsemake_list_storage_aux~message~num_words~num_elements~storage_type:(ListStorageType.Composite(struct_pointer.StructPointer.data_words,struct_pointer.StructPointer.pointer_words))~segment_id~segment_offsetelseinvalid_msg"composite list pointer has malformed element type tag"(* Given a description of a cap'n proto far pointer, get the object which
the pointer points to. *)letrecderef_far_pointer(far_pointer:FarPointer.t)(message:'capMessage.t):('cap,'a)Object.t=letopenFarPointerinmatchfar_pointer.landing_padwith|NormalPointer->letnext_pointer_bytes={Slice.msg=message;Slice.segment=Message.get_segmentmessagefar_pointer.segment_id;Slice.segment_id=far_pointer.segment_id;Slice.start=far_pointer.offset*sizeof_uint64;Slice.len=sizeof_uint64;}inlet()=bounds_check_slice_exn~err:"far pointer describes invalid landing pad"next_pointer_bytesinderef_pointernext_pointer_bytes|TaggedFarPointer->letcontent_pointer_bytes={Slice.msg=message;Slice.segment=Message.get_segmentmessagefar_pointer.segment_id;Slice.segment_id=far_pointer.segment_id;Slice.start=far_pointer.offset*sizeof_uint64;Slice.len=sizeof_uint64;}inlettag_bytes={content_pointer_byteswithSlice.start=Slice.get_endcontent_pointer_bytes;}inmatch(decode_pointercontent_pointer_bytes,decode_pointertag_bytes)with|(Pointer.Farcontent_pointer,Pointer.Listlist_pointer)->Object.List(make_list_storage~message~segment_id:content_pointer.FarPointer.segment_id~segment_offset:(content_pointer.FarPointer.offset*sizeof_uint64)~list_pointer)|(Pointer.Farcontent_pointer,Pointer.Structstruct_pointer)->letsegment_id=content_pointer.FarPointer.segment_idinletdata={Slice.msg=message;Slice.segment=Message.get_segmentmessagesegment_id;Slice.segment_id;Slice.start=content_pointer.FarPointer.offset*sizeof_uint64;Slice.len=struct_pointer.StructPointer.data_words*sizeof_uint64;}inletpointers={datawithSlice.start=Slice.get_enddata;Slice.len=struct_pointer.StructPointer.pointer_words*sizeof_uint64;}inlet()=bounds_check_slice_exn~err:"struct-tagged far pointer describes invalid data region"datainlet()=bounds_check_slice_exn~err:"struct-tagged far pointer describes invalid pointers region"pointersinObject.Struct(StructStorage.v~data~pointers)|_->invalid_msg"tagged far pointer points to invalid landing pad"(* Given a range of eight bytes which represent a pointer, get the object which
the pointer points to. *)andderef_pointer(pointer_bytes:'capSlice.t):('cap,'a)Object.t=letpointer64=Slice.get_int64pointer_bytes0inifUtil.is_int64_zeropointer64thenObject.Noneelseletpointer64=Slice.get_int64pointer_bytes0inlettag_bits=Int64.to_intpointer64inlettag=tag_bitslandPointer.Bitfield.tag_maskin(* OCaml won't match an int against let-bound variables,
only against constants. *)matchtagwith|0x0->(* Pointer.Bitfield.tag_val_struct *)letstruct_pointer=StructPointer.decodepointer64inletopenStructPointerinletdata={pointer_byteswithSlice.start=(Slice.get_endpointer_bytes)+(struct_pointer.offset*sizeof_uint64);Slice.len=struct_pointer.data_words*sizeof_uint64;}inletpointers={datawithSlice.start=Slice.get_enddata;Slice.len=struct_pointer.pointer_words*sizeof_uint64;}inlet()=bounds_check_slice_exn~err:"struct pointer describes invalid data region"datainlet()=bounds_check_slice_exn~err:"struct pointer describes invalid pointers region"pointersinObject.Struct(StructStorage.v~data~pointers)|0x1->(* Pointer.Bitfield.tag_val_list *)letlist_pointer=ListPointer.decodepointer64inObject.List(make_list_storage~message:pointer_bytes.Slice.msg~segment_id:pointer_bytes.Slice.segment_id~segment_offset:((Slice.get_endpointer_bytes)+(list_pointer.ListPointer.offset*sizeof_uint64))~list_pointer)|0x2->(* Pointer.Bitfield.tag_val_far *)letfar_pointer=FarPointer.decodepointer64inderef_far_pointerfar_pointerpointer_bytes.Slice.msg|0x3->(* Pointer.Bitfield.tag_val_other *)letother_pointer=OtherPointer.decodepointer64inlet(OtherPointer.Capabilityindex)=other_pointerinObject.Capabilityindex|_->assertfalsemoduleListDecoders=structtype('cap,'a)struct_decoders_t={bytes:'capSlice.t->'a;pointer:'capSlice.t->'a;composite:'b.('cap,'b)StructStorage.t->'a;}type('cap,'a)t=|Emptyof(unit->'a)|Bitof(bool->'a)|Bytes1of('capSlice.t->'a)|Bytes2of('capSlice.t->'a)|Bytes4of('capSlice.t->'a)|Bytes8of('capSlice.t->'a)|Pointerof('capSlice.t->'a)|Structof('cap,'a)struct_decoders_tendmoduleListCodecs=structtype'astruct_codecs_t={bytes:(rwSlice.t->'a)*('a->rwSlice.t->unit);pointer:(rwSlice.t->'a)*('a->rwSlice.t->unit);composite:'b.((rw,'b)StructStorage.t->'a)*('a->(rw,'b)StructStorage.t->unit);}type'at=|Emptyof(unit->'a)*('a->unit)|Bitof(bool->'a)*('a->bool)|Bytes1of(rwSlice.t->'a)*('a->rwSlice.t->unit)|Bytes2of(rwSlice.t->'a)*('a->rwSlice.t->unit)|Bytes4of(rwSlice.t->'a)*('a->rwSlice.t->unit)|Bytes8of(rwSlice.t->'a)*('a->rwSlice.t->unit)|Pointerof(rwSlice.t->'a)*('a->rwSlice.t->unit)|Structof'astruct_codecs_tendlet_dummy=reftrueletmake_array_readonly(list_storage:'capListStorage.t)(decoders:('cap,'a)ListDecoders.t):(ro,'a,'capListStorage.t)InnerArray.t=letmake_element_slicelsibyte_count={ls.ListStorage.storagewithSlice.start=ls.ListStorage.storage.Slice.start+(i*byte_count);Slice.len=byte_count;}inletlength=list_storage.ListStorage.num_elementsin(* Note: the following is attempting to strike a balance between
* (1) building InnerArray.get_unsafe closures that do as little work as
* possible and
* (2) making the closure calling convention as efficient as possible.
*
* A naive implementation of this getter can result in quite slow code. *)matchlist_storage.ListStorage.storage_typewith|ListStorageType.Empty->beginmatchdecoderswith|ListDecoders.Emptydecode->letro_get_unsafe_void_ls_i=decode()in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_void;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<Void> where a different list type was expected"end|ListStorageType.Bit->beginmatchdecoderswith|ListDecoders.Bitdecode->letro_get_unsafe_boollsi=letbyte_ofs=i/8inletbit_ofs=imod8inletbyte_val=Slice.get_uint8ls.ListStorage.storagebyte_ofsindecode((byte_valland(1lslbit_ofs))<>0)in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_bool;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<Bool> where a different list type was expected"end|ListStorageType.Bytes1->beginmatchdecoderswith|ListDecoders.Bytes1decode|ListDecoders.Struct{ListDecoders.bytes=decode;_}->letro_get_unsafe_bytes1lsi=decode(make_element_slicelsi1)in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_bytes1;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<1 byte> where a different list type was expected"end|ListStorageType.Bytes2->beginmatchdecoderswith|ListDecoders.Bytes2decode|ListDecoders.Struct{ListDecoders.bytes=decode;_}->letro_get_unsafe_bytes2lsi=decode(make_element_slicelsi2)in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_bytes2;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<2 byte> where a different list type was expected"end|ListStorageType.Bytes4->beginmatchdecoderswith|ListDecoders.Bytes4decode|ListDecoders.Struct{ListDecoders.bytes=decode;_}->letro_get_unsafe_bytes4lsi=decode(make_element_slicelsi4)in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_bytes4;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<4 byte> where a different list type was expected"end|ListStorageType.Bytes8->beginmatchdecoderswith|ListDecoders.Bytes8decode|ListDecoders.Struct{ListDecoders.bytes=decode;_}->letro_get_unsafe_bytes8lsi=decode(make_element_slicelsi8)in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_bytes8;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<8 byte> where a different list type was expected"end|ListStorageType.Pointer->beginmatchdecoderswith|ListDecoders.Pointerdecode|ListDecoders.Struct{ListDecoders.pointer=decode;_}->letro_get_unsafe_pointerlsi=decode(make_element_slicelsisizeof_uint64)in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_pointer;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<pointer> a different list type was expected"end|ListStorageType.Composite(data_words,pointer_words)->letdata_size=data_words*sizeof_uint64inletpointers_size=pointer_words*sizeof_uint64inletmake_storagelsi~data_size~pointers_size=lettotal_size=data_size+pointers_sizein(* Skip over the composite tag word *)letcontent_offset=ls.ListStorage.storage.Slice.start+sizeof_uint64inletdata={ls.ListStorage.storagewithSlice.start=content_offset+(i*total_size);Slice.len=data_size;}inletpointers={datawithSlice.start=Slice.get_enddata;Slice.len=pointers_size;}inStructStorage.v~data~pointersinletmake_bytes_handler~size~decode=ifdata_words=0theninvalid_msg"decoded List<composite> with empty data region where data was expected"elseletro_get_unsafe_composite_byteslsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletslice={struct_storage.StructStorage.datawithSlice.len=size}indecodeslicein{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_composite_bytes;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}inbeginmatchdecoderswith|ListDecoders.Emptydecode->letro_get_unsafe_composite_void_ls_i=decode()in{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_composite_void;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|ListDecoders.Bitdecode->ifdata_words=0theninvalid_msg"decoded List<composite> with empty data region where data was expected"elseletro_get_unsafe_composite_boollsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletfirst_byte=Slice.get_uint8struct_storage.StructStorage.data0inletis_set=(first_byteland0x1)<>0indecodeis_setin{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_composite_bool;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|ListDecoders.Bytes1decode->make_bytes_handler~size:1~decode|ListDecoders.Bytes2decode->make_bytes_handler~size:2~decode|ListDecoders.Bytes4decode->make_bytes_handler~size:4~decode|ListDecoders.Bytes8decode->make_bytes_handler~size:8~decode|ListDecoders.Pointerdecode->ifpointer_words=0theninvalid_msg"decoded List<composite> with empty pointers region where \
pointers were expected"elseletro_get_unsafe_composite_pointerlsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletslice={struct_storage.StructStorage.pointerswithSlice.len=sizeof_uint64}indecodeslicein{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_composite_pointer;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}|ListDecoders.Structstruct_decoders->letro_get_unsafe_composite_structlsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinstruct_decoders.ListDecoders.compositestruct_storagein{InnerArray.length;InnerArray.init=InnerArray.invalid_init;InnerArray.get_unsafe=ro_get_unsafe_composite_struct;InnerArray.set_unsafe=InnerArray.invalid_set_unsafe;InnerArray.storage=Somelist_storage;}endletmake_array_readwrite~(list_storage:rwListStorage.t)~(init:int->rwListStorage.t)~(codecs:'aListCodecs.t):(rw,'a,rwListStorage.t)InnerArray.t=letmake_element_slicelsibyte_count={ls.ListStorage.storagewithSlice.start=ls.ListStorage.storage.Slice.start+(i*byte_count);Slice.len=byte_count;}inletlength=list_storage.ListStorage.num_elementsin(* Note: the following is attempting to strike a balance between
* (1) building InnerArray.get_unsafe/set_unsafe closures that do as little
* work as possible and
* (2) making the closure calling convention as efficient as possible.
*
* A naive implementation of these accessors can result in quite slow code. *)matchlist_storage.ListStorage.storage_typewith|ListStorageType.Empty->beginmatchcodecswith|ListCodecs.Empty(decode,encode)->letrw_get_unsafe_void_ls_i=decode()inletrw_set_unsafe_void_ls_iv=encodevin{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_void;InnerArray.set_unsafe=rw_set_unsafe_void;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<Void> where a different list type was expected"end|ListStorageType.Bit->beginmatchcodecswith|ListCodecs.Bit(decode,encode)->letrw_get_unsafe_boollsi=letbyte_ofs=i/8inletbit_ofs=imod8inletbyte_val=Slice.get_uint8ls.ListStorage.storagebyte_ofsindecode((byte_valland(1lslbit_ofs))<>0)inletrw_set_unsafe_boollsiv=letbyte_ofs=i/8inletbit_ofs=imod8inletbitmask=1lslbit_ofsinletold_byte_val=Slice.get_uint8ls.ListStorage.storagebyte_ofsinletnew_byte_val=ifencodevthenold_byte_vallorbitmaskelseold_byte_valland(lnotbitmask)inSlice.set_uint8ls.ListStorage.storagebyte_ofsnew_byte_valin{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_bool;InnerArray.set_unsafe=rw_set_unsafe_bool;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<Bool> where a different list type was expected"end|ListStorageType.Bytes1->beginmatchcodecswith|ListCodecs.Bytes1(decode,encode)|ListCodecs.Struct{ListCodecs.bytes=(decode,encode);_}->letrw_get_unsafe_bytes1lsi=decode(make_element_slicelsi1)inletrw_set_unsafe_bytes1lsiv=encodev(make_element_slicelsi1)in{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_bytes1;InnerArray.set_unsafe=rw_set_unsafe_bytes1;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<1 byte> where a different list type was expected"end|ListStorageType.Bytes2->beginmatchcodecswith|ListCodecs.Bytes2(decode,encode)|ListCodecs.Struct{ListCodecs.bytes=(decode,encode);_}->letrw_get_unsafe_bytes2lsi=decode(make_element_slicelsi2)inletrw_set_unsafe_bytes2lsiv=encodev(make_element_slicelsi2)in{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_bytes2;InnerArray.set_unsafe=rw_set_unsafe_bytes2;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<2 byte> where a different list type was expected"end|ListStorageType.Bytes4->beginmatchcodecswith|ListCodecs.Bytes4(decode,encode)|ListCodecs.Struct{ListCodecs.bytes=(decode,encode);_}->letrw_get_unsafe_bytes4lsi=decode(make_element_slicelsi4)inletrw_set_unsafe_bytes4lsiv=encodev(make_element_slicelsi4)in{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_bytes4;InnerArray.set_unsafe=rw_set_unsafe_bytes4;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<4 byte> where a different list type was expected"end|ListStorageType.Bytes8->beginmatchcodecswith|ListCodecs.Bytes8(decode,encode)|ListCodecs.Struct{ListCodecs.bytes=(decode,encode);_}->letrw_get_unsafe_bytes8lsi=decode(make_element_slicelsi8)inletrw_set_unsafe_bytes8lsiv=encodev(make_element_slicelsi8)in{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_bytes8;InnerArray.set_unsafe=rw_set_unsafe_bytes8;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<8 byte> where a different list type was expected"end|ListStorageType.Pointer->beginmatchcodecswith|ListCodecs.Pointer(decode,encode)|ListCodecs.Struct{ListCodecs.pointer=(decode,encode);_}->letrw_get_unsafe_ptrlsi=decode(make_element_slicelsisizeof_uint64)inletrw_set_unsafe_ptrlsiv=encodev(make_element_slicelsisizeof_uint64)in{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_ptr;InnerArray.set_unsafe=rw_set_unsafe_ptr;InnerArray.storage=Somelist_storage;}|_->invalid_msg"decoded List<pointer> where a different list type was expected"end|ListStorageType.Composite(data_words,pointer_words)->letdata_size=data_words*sizeof_uint64inletpointers_size=pointer_words*sizeof_uint64inletmake_storagelsi~data_size~pointers_size=lettotal_size=data_size+pointers_sizein(* Skip over the composite tag word *)letcontent_offset=ls.ListStorage.storage.Slice.start+sizeof_uint64inletdata={ls.ListStorage.storagewithSlice.start=content_offset+(i*total_size);Slice.len=data_size;}inletpointers={datawithSlice.start=Slice.get_enddata;Slice.len=pointers_size;}inStructStorage.v~data~pointersinletmake_bytes_handlers~size~decode~encode=ifdata_words=0theninvalid_msg"decoded List<composite> with empty data region where data was expected"elseletrw_get_unsafe_composite_byteslsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletslice={struct_storage.StructStorage.datawithSlice.len=size}indecodesliceinletrw_set_unsafe_composite_byteslsiv=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletslice={struct_storage.StructStorage.datawithSlice.len=size}inencodevslicein{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_composite_bytes;InnerArray.set_unsafe=rw_set_unsafe_composite_bytes;InnerArray.storage=Somelist_storage;}inbeginmatchcodecswith|ListCodecs.Empty(decode,encode)->letrw_get_unsafe_composite_void_ls_i=decode()inletrw_set_unsafe_composite_void_ls_iv=encodevin{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_composite_void;InnerArray.set_unsafe=rw_set_unsafe_composite_void;InnerArray.storage=Somelist_storage;}|ListCodecs.Bit(decode,encode)->ifdata_words=0theninvalid_msg"decoded List<composite> with empty data region where data was expected"elseletrw_get_unsafe_composite_boollsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletfirst_byte=Slice.get_uint8struct_storage.StructStorage.data0inletis_set=(first_byteland0x1)<>0indecodeis_setinletrw_set_unsafe_composite_boollsiv=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletfirst_byte=Slice.get_uint8struct_storage.StructStorage.data0inletfirst_byte=ifencodevthenfirst_bytelor0x1elsefirst_byteland0xfeinSlice.set_uint8struct_storage.StructStorage.data0first_bytein{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_composite_bool;InnerArray.set_unsafe=rw_set_unsafe_composite_bool;InnerArray.storage=Somelist_storage;}|ListCodecs.Bytes1(decode,encode)->make_bytes_handlers~size:1~decode~encode|ListCodecs.Bytes2(decode,encode)->make_bytes_handlers~size:2~decode~encode|ListCodecs.Bytes4(decode,encode)->make_bytes_handlers~size:4~decode~encode|ListCodecs.Bytes8(decode,encode)->make_bytes_handlers~size:8~decode~encode|ListCodecs.Pointer(decode,encode)->ifpointer_words=0theninvalid_msg"decoded List<composite> with empty pointers region where \
pointers were expected"elseletrw_get_unsafe_composite_ptrlsi=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletslice={struct_storage.StructStorage.pointerswithSlice.len=sizeof_uint64}indecodesliceinletrw_set_unsafe_composite_ptrlsiv=letstruct_storage=make_storagelsi~data_size~pointers_sizeinletslice={struct_storage.StructStorage.pointerswithSlice.len=sizeof_uint64}inencodevslicein{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_composite_ptr;InnerArray.set_unsafe=rw_set_unsafe_composite_ptr;InnerArray.storage=Somelist_storage;}|ListCodecs.Struct{ListCodecs.composite=(decode,encode);_}->letrw_get_unsafe_composite_structlsi=decode(make_storagelsi~data_size~pointers_size)inletrw_set_unsafe_composite_structlsiv=encodev(make_storagelsi~data_size~pointers_size)in{InnerArray.length;InnerArray.init;InnerArray.get_unsafe=rw_get_unsafe_composite_struct;InnerArray.set_unsafe=rw_set_unsafe_composite_struct;InnerArray.storage=Somelist_storage;}end(* Given list storage which is expected to contain UInt8 data, decode the data as
an OCaml string. *)letstring_of_uint8_list~(null_terminated:bool)(* true if the data is expected to end in 0 *)(list_storage:'capListStorage.t):string=letopenListStorageinmatchlist_storage.storage_typewith|ListStorageType.Bytes1->letresult_byte_count=ifnull_terminatedthenlet()=iflist_storage.num_elements<1theninvalid_msg"empty string list has no space for null terminator"inletterminator=Slice.get_uint8list_storage.storage(list_storage.num_elements-1)inlet()=ifterminator<>0theninvalid_msg"string list is not null terminated"inlist_storage.num_elements-1elselist_storage.num_elementsinletbuf=Bytes.createresult_byte_countinSlice.blit_to_bytes~src:list_storage.storage~src_pos:0~dst:buf~dst_pos:0~len:result_byte_count;Bytes.unsafe_to_stringbuf|_->invalid_msg"decoded non-UInt8 list where string data was expected"letstruct_of_bytes_sliceslice=letdata=sliceinletpointers={slicewithSlice.start=Slice.get_enddata;Slice.len=0;}inStructStorage.v~data~pointersletstruct_of_pointer_sliceslice=let()=assert(slice.Slice.len=sizeof_uint64)inletdata={slicewithSlice.len=0}inletpointers={slicewithSlice.len=sizeof_uint64;}inStructStorage.v~data~pointers(* Given some list storage corresponding to a struct list, construct
a function for mapping an element index to the associated
struct storage. *)letmake_struct_of_list_indexlist_storage=letstorage=list_storage.ListStorage.storageinletstorage_type=list_storage.ListStorage.storage_typeinmatchlist_storage.ListStorage.storage_typewith|ListStorageType.Empty->letmake_struct_of_list_index_void_i=letslice={storagewithSlice.start=storage.Slice.start;Slice.len=0;}instruct_of_bytes_slicesliceinmake_struct_of_list_index_void|ListStorageType.Bytes1|ListStorageType.Bytes2|ListStorageType.Bytes4|ListStorageType.Bytes8->(* Short data-only struct *)letbyte_count=ListStorageType.get_byte_countstorage_typeinletmake_struct_of_list_index_bytesi=letslice={storagewithSlice.start=storage.Slice.start+(i*byte_count);Slice.len=byte_count;}instruct_of_bytes_slicesliceinmake_struct_of_list_index_bytes|ListStorageType.Pointer->(* Single-pointer struct *)letmake_struct_of_list_index_pointeri=letslice={storagewithSlice.start=(storage.Slice.start)+(i*sizeof_uint64);Slice.len=sizeof_uint64;}instruct_of_pointer_slicesliceinmake_struct_of_list_index_pointer|ListStorageType.Composite(data_words,pointer_words)->letdata_size=data_words*sizeof_uint64inletpointers_size=pointer_words*sizeof_uint64inletelement_size=data_size+pointers_sizein(* Skip over the composite tag word *)letcontent_offset=storage.Slice.start+sizeof_uint64inletmake_struct_of_list_index_compositei=letdata={storagewithSlice.start=content_offset+(i*element_size);Slice.len=data_size;}inletpointers={storagewithSlice.start=Slice.get_enddata;Slice.len=pointers_size;}inStructStorage.v~data~pointersinmake_struct_of_list_index_composite|ListStorageType.Bit->invalid_msg"decoded List<Bool> where List<composite> was expected"end[@@inline]