123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346(*
Runtime library
*)openPrintfexceptionErrorofstring(*
Error messages
*)leterrors=raise(Errors)letread_error()=error"Read error"letread_error_atib=error(sprintf"Read error (%i)"ib.Bi_inbuf.i_pos)lettag_errortags=error(sprintf"Found wrong tag %i for %s"tags)letunsupported_varianthhas_arg=error(sprintf"Unsupported variant (hash=%i, arg=%B)"hhas_arg)letmissing_tuple_fieldslenreq_fields=letmissing=List.fold_right(funiacc->ifi>=lentheni::accelseacc)req_fields[]inerror(sprintf"Missing tuple field%s %s"(ifList.lengthmissing>1then"s"else"")(String.concat", "(List.mapstring_of_intmissing)))letmissing_fieldsbit_fieldsfield_names=letacc=ref[]inforz=Array.lengthfield_names-1downto0doleti=z/31inletj=zmod31inifbit_fields.(i)land(1lslj)=0thenacc:=field_names.(z)::!accdone;error(sprintf"Missing record field%s %s"(ifList.length!acc>1then"s"else"")(String.concat", "!acc))(*
Readers
*)letget_unit_readertag=iftag=Bi_io.unit_tagthenBi_io.read_untagged_unitelsetag_errortag"unit"letread_unitib=ifBi_io.read_tagib=Bi_io.unit_tagthenBi_io.read_untagged_unitibelseread_error_atibletget_bool_readertag=iftag=Bi_io.bool_tagthenBi_io.read_untagged_boolelsetag_errortag"bool"letread_boolib=ifBi_io.read_tagib=Bi_io.bool_tagthenBi_io.read_untagged_boolibelseread_error_atibletget_int_readertag=matchtagwith1->Bi_io.read_untagged_int8|2->Bi_io.read_untagged_int16|16->Bi_io.read_untagged_uvint|17->Bi_io.read_untagged_svint|_->tag_errortag"int"letread_intib=matchBi_io.read_tagibwith1->Bi_io.read_untagged_int8ib|2->Bi_io.read_untagged_int16ib|16->Bi_io.read_untagged_uvintib|17->Bi_io.read_untagged_svintib|_->read_error_atibletget_char_readertag=iftag=Bi_io.int8_tagthenBi_io.read_untagged_charelsetag_errortag"char"letread_charib=ifBi_io.read_tagib=Bi_io.int8_tagthenBi_io.read_untagged_charibelseread_error_atibletget_int16_readertag=iftag=Bi_io.int16_tagthenBi_io.read_untagged_int16elsetag_errortag"int16"letread_int16ib=ifBi_io.read_tagib=Bi_io.int16_tagthenBi_io.read_untagged_int16ibelseread_error_atibletget_int32_readertag=iftag=Bi_io.int32_tagthenBi_io.read_untagged_int32elsetag_errortag"int32"letread_int32ib=ifBi_io.read_tagib=Bi_io.int32_tagthenBi_io.read_untagged_int32ibelseread_error_atibletget_int64_readertag=iftag=Bi_io.int64_tagthenBi_io.read_untagged_int64elsetag_errortag"int64"letread_int64ib=ifBi_io.read_tagib=Bi_io.int64_tagthenBi_io.read_untagged_int64ibelseread_error_atibletget_float32_readertag=iftag=Bi_io.float32_tagthenBi_io.read_untagged_float32elsetag_errortag"float32"letget_float64_readertag=iftag=Bi_io.float64_tagthenBi_io.read_untagged_float64elsetag_errortag"float64"letget_float_reader=get_float64_readerletread_float32ib=ifBi_io.read_tagib=Bi_io.float32_tagthenBi_io.read_untagged_float32ibelseread_error_atibletread_float64ib=ifBi_io.read_tagib=Bi_io.float64_tagthenBi_io.read_untagged_float64ibelseread_error_atibletread_float=read_float64letget_string_readertag=iftag=Bi_io.string_tagthenBi_io.read_untagged_stringelsetag_errortag"string"letread_stringib=ifBi_io.read_tagib=Bi_io.string_tagthenBi_io.read_untagged_stringibelseread_error_atibletread_array_valueget_readerib=letlen=Bi_vint.read_uvintibiniflen=0then[||]elseletreader=get_reader(Bi_io.read_tagib)inleta=Array.makelen(readerib)infori=1tolen-1doArray.unsafe_setai(readerib)done;aletread_list_valueget_readerib=Array.to_list(read_array_valueget_readerib)letget_array_readerget_readertag=iftag=Bi_io.array_tagthenread_array_valueget_readerelsetag_errortag"array"letget_list_readerget_readertag=iftag=Bi_io.array_tagthenfunib->Array.to_list(read_array_valueget_readerib)elsetag_errortag"list"letread_arrayget_readerib=ifBi_io.read_tagib=Bi_io.array_tagthenread_array_valueget_readeribelseread_error_atibletread_listreadib=Array.to_list(read_arrayreadib)(*
Writers
*)letwrite_taggedtagwritebufx=Bi_io.write_tagbuftag;writebufxletwrite_untagged_optionwritebufx=matchxwithNone->Bi_io.write_numtagbuf0false|Somex->Bi_io.write_numtagbuf0true;writebufxletwrite_optionwritebufx=Bi_io.write_tagbufBi_io.num_variant_tag;write_untagged_optionwritebufxletarray_init2lenxf=iflen=0then[||]elseleta=Array.makelen(f0x)infori=1tolen-1doArray.unsafe_setai(fix)done;aletarray_init3lenxyf=iflen=0then[||]elseleta=Array.makelen(f0xy)infori=1tolen-1doArray.unsafe_setai(fixy)done;aletarray_iter2fxa=fori=0toArray.lengtha-1dofx(Array.unsafe_getai)doneletarray_iter3fxya=fori=0toArray.lengtha-1dofxy(Array.unsafe_getai)doneletreclist_iter2fx=function[]->()|y::l->fxy;list_iter2fxlletreclist_iter3fxy=function[]->()|z::l->fxyz;list_iter3fxylletwrite_untagged_arraycell_tagwritebufa=letlen=Array.lengthainBi_vint.write_uvintbuflen;iflen>0then(Bi_io.write_tagbufcell_tag;array_iter2writebufa)letwrite_arraycell_tagwritebufa=Bi_io.write_tagbufBi_io.array_tag;write_untagged_arraycell_tagwritebufaletwrite_untagged_listcell_tagwritebufl=letlen=List.lengthlinBi_vint.write_uvintbuflen;iflen>0then(Bi_io.write_tagbufcell_tag;list_iter2writebufl)letwrite_listcell_tagwritebufl=Bi_io.write_tagbufBi_io.array_tag;write_untagged_listcell_tagwritebufl(*
shortcut for getting the tag of a polymorphic variant since
biniou uses the same representation
(usefulness?)
*)letget_poly_tag(x:[>])=letr=Obj.reprxinifObj.is_blockrthen(Obj.obj(Obj.fieldr0):int)else(Obj.objr:int)(* We want an identity function that is not inlined *)typeidentity_t={mutable_identity:'a.'a->'a}letidentity_ref={_identity=(funx->x)}letidentityx=identity_ref._identityx(*
Checking at runtime that our assumptions on unspecified compiler behavior
still hold.
*)typet={_a:intoption;_b:int;}letcreate()={{_a=None;_b=Array.lengthSys.argv}with_a=None}lettest()=letr=create()inletv=Some17inObj.set_field(Obj.reprr)0(Obj.reprv);letsafe_r=identityrin(* r._a is inlined by ocamlopt and equals None
because the field is supposed to be immutable. *)assert(safe_r._a=v)let()=test()(************************************)