123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195open!BaseopenFaradayopenMessage(* This is currently written with little to no concern about the efficiency of the
serializer. If performance is necessary, we would want to keep a closer eye on
the internal buffer and flush occasionally.
*)letrecdispatcht=function|Nil->write_nilt|Integeri->write_intti|UInt64i->write_uint64ti|Int64i->write_signed_integerti|Booleanb->write_booltb|Floatingf->write_floattf|Arrayvs->write_arraytvs|Mapkvs->write_maptkvs|Strings->write_strvalts|Binarybs->write_bintbs|Extensionext->write_exttextandwrite_nilt=write_chartConstants.nilandwrite_booltb=matchbwith|true->write_chartConstants.true_|false->write_chartConstants.false_andwrite_intti=ifi>=0thenwrite_nonnegative_integert(Int64.of_inti)elsewrite_signed_integert(Int64.of_inti)andwrite_uint64ti=write_chartConstants.uint64_header;BE.write_uint64tiandwrite_nonnegative_integerti=letopenInt64.Oinifi<=(2L**7L)-1Lthen(* This fits into 8 bits, and we must have the top bit unset here *)write_uint8t(Int64.to_int_exni)elseifi<=0xFFLthen(write_chartConstants.uint8_header;write_uint8t(Int64.to_int_exni))elseifi<=0xFFFFLthen(write_chartConstants.uint16_header;BE.write_uint16t(Int64.to_int_exni))elseifi<=0xFFFF_FFFFLthen(write_chartConstants.uint32_header;letv=ifi<2L**31Lthenielsei-(2L**32L)inBE.write_uint32t(Int64.to_int32_exnv))else(write_chartConstants.uint64_header;BE.write_uint64ti)andwrite_signed_integerti=letopenInt64.Oinifi>=0Lthenwrite_nonnegative_integertielseif-32L<=ithenwrite_uint8t(Int.(lor)(Int64.to_int_exni)Constants.negative_fixint_mask)elseif-(2L**7L)<=ithen(write_chartConstants.int8_header;(* This is correct by properties of 2s complement arithmetic *)write_uint8t(Int64.to_int_exni))elseif-(2L**15L)<=ithen(write_chartConstants.int16_header;BE.write_uint16t(Int64.to_int_exni))elseif-(2L**31L)<=ithen(write_chartConstants.int32_header;BE.write_uint32t(Int64.to_int32_exni))else(write_chartConstants.int64_header;BE.write_uint64ti)andwrite_floattf=write_chartConstants.float64_header;BE.write_doubletf(* Don't shadow [Faraday.write_string]. *)andwrite_strvalts=letopenInt.Oinletlen=String.lengthsiniflen<=31thenwrite_uint8t(lenlorConstants.fixstr_mask)elseiflen<=(2**8)-1then(write_chartConstants.str8_header;write_uint8tlen)elseiflen<=(2**16)-1then(write_chartConstants.str16_header;BE.write_uint16tlen)else(write_chartConstants.str32_header;BE.write_uint32t(Int32.of_int_exnlen));write_stringtsandwrite_bintb=letopenInt.Oinletlen=Bytes.lengthbiniflen<=(2**8)-1then(write_chartConstants.bin8_header;write_uint8tlen)elseiflen<=(2**16)-1then(write_chartConstants.bin16_header;BE.write_uint16tlen)else(write_chartConstants.bin32_header;BE.write_uint32t(Int32.of_int_exnlen));write_bytestbandwrite_arraytvs=letopenInt.Oinletlen=List.lengthvsiniflen<=15thenwrite_uint8t(lenlorConstants.fixarray_mask)elseiflen<=(2**16)-1then(write_chartConstants.array16_header;BE.write_uint16tlen)else(write_chartConstants.array32_header;BE.write_uint32t(Int32.of_int_exnlen));List.iter~f:(dispatcht)vsandwrite_maptkvs=letopenInt.Oinletlen=List.lengthkvsiniflen<=15thenwrite_uint8t(lenlorConstants.fixmap_mask)elseiflen<=(2**16)-1then(write_chartConstants.map16_header;BE.write_uint16tlen)else(write_chartConstants.map32_header;BE.write_uint32t(Int32.of_int_exnlen));List.iter~f:(fun(k,v)->dispatchtk;dispatchtv)kvs(* The spec does not actually say what to do in the case that an extension type takes a
number of bytes that falls between two of the fixed sizes. Here, we choose to represent
that as an 8-bit chunk rather than padding with 0s, because those 0s may be meaningful
to the end-user.
*)andwrite_extt{type_id;data}=letopenInt.Oinletlen=Bytes.lengthdatainiflen=1thenwrite_chartConstants.fixext1_headerelseiflen=2thenwrite_chartConstants.fixext2_headerelseiflen=4thenwrite_chartConstants.fixext4_headerelseiflen=8thenwrite_chartConstants.fixext8_headerelseiflen=16thenwrite_chartConstants.fixext16_headerelseiflen<=(2**8)-1then(write_chartConstants.ext8_header;write_uint8tlen)elseiflen<=(2**16)-1then(write_chartConstants.ext16_header;BE.write_uint16tlen)elseiflen<=(2**32)-1then(write_chartConstants.ext32_header;BE.write_uint32t(Int32.of_int_exnlen))elsefailwith"Ext data too large for messagepack format!";write_uint8ttype_id;write_bytestdata;;letmessage_to_string_exn?(bufsize=256)msg=lett=createbufsizeindispatchtmsg;serialize_to_stringt;;