123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400moduleOt=Pb_codegen_ocaml_typemoduleF=Pb_codegen_formattingletsp=Pb_codegen_util.spletruntime_function_for_basic_typebtpk=matchpk,btwith|Ot.Pk_varintfalse,Ot.Bt_int->"Pbrt.Decoder.int_as_varint"|Ot.Pk_varinttrue,Ot.Bt_int->"Pbrt.Decoder.int_as_zigzag"|Ot.Pk_varintfalse,Ot.Bt_int32->"Pbrt.Decoder.int32_as_varint"|Ot.Pk_varinttrue,Ot.Bt_int32->"Pbrt.Decoder.int32_as_zigzag"|Ot.Pk_varintfalse,Ot.Bt_uint32->"Pbrt.Decoder.uint32_as_varint"|Ot.Pk_varinttrue,Ot.Bt_uint32->"Pbrt.Decoder.uint32_as_zigzag"|Ot.Pk_varintfalse,Ot.Bt_int64->"Pbrt.Decoder.int64_as_varint"|Ot.Pk_varinttrue,Ot.Bt_int64->"Pbrt.Decoder.int64_as_zigzag"|Ot.Pk_varintfalse,Ot.Bt_uint64->"Pbrt.Decoder.uint64_as_varint"|Ot.Pk_varinttrue,Ot.Bt_uint64->"Pbrt.Decoder.uint64_as_zigzag"|Ot.Pk_bits32,Ot.Bt_int32->"Pbrt.Decoder.int32_as_bits32"|Ot.Pk_bits64,Ot.Bt_int64->"Pbrt.Decoder.int64_as_bits64"|Ot.Pk_bits32,Ot.Bt_uint32->"Pbrt.Decoder.uint32_as_bits32"|Ot.Pk_bits64,Ot.Bt_uint64->"Pbrt.Decoder.uint64_as_bits64"|Ot.Pk_varintfalse,Ot.Bt_bool->"Pbrt.Decoder.bool"|Ot.Pk_bits32,Ot.Bt_float->"Pbrt.Decoder.float_as_bits32"|Ot.Pk_bits64,Ot.Bt_float->"Pbrt.Decoder.float_as_bits64"|Ot.Pk_bits32,Ot.Bt_int->"Pbrt.Decoder.int_as_bits32"|Ot.Pk_bits64,Ot.Bt_int->"Pbrt.Decoder.int_as_bits64"|Ot.Pk_bytes,Ot.Bt_string->"Pbrt.Decoder.string"|Ot.Pk_bytes,Ot.Bt_bytes->"Pbrt.Decoder.bytes"|_->failwith"Invalid decoding/OCaml type combination"letruntime_function_for_wrapper_type{Ot.wt_type;wt_pk}=matchwt_type,wt_pkwith|Ot.Bt_float,Ot.Pk_bits64->"Pbrt.Decoder.wrapper_double_value"|Ot.Bt_float,Ot.Pk_bits32->"Pbrt.Decoder.wrapper_float_value"|Ot.Bt_int64,Ot.Pk_varint_->"Pbrt.Decoder.wrapper_int64_value"|Ot.Bt_int32,Ot.Pk_varint_->"Pbrt.Decoder.wrapper_int32_value"|Ot.Bt_bool,Ot.Pk_varint_->"Pbrt.Decoder.wrapper_bool_value"|Ot.Bt_string,Ot.Pk_bytes->"Pbrt.Decoder.wrapper_string_value"|Ot.Bt_bytes,Ot.Pk_bytes->"Pbrt.Decoder.wrapper_bytes_value"|_->assertfalseletdecode_field_expressionfield_typepk:string=matchfield_typewith|Ot.Ft_user_defined_typet->letf_name=letfunction_prefix="decode_pb"inPb_codegen_util.function_name_of_user_defined~function_prefixtin(matcht.Ot.udt_typewith|`Message->f_name^" (Pbrt.Decoder.nested d)"|`Enum->f_name^" d")|Ot.Ft_unit->"Pbrt.Decoder.empty_nested d"|Ot.Ft_basic_typebt->runtime_function_for_basic_typebtpk^" d"|Ot.Ft_wrapper_typewt->runtime_function_for_wrapper_typewt^" d"letpbrt_payload_kindpayload_kindis_packed=ifis_packedthen"Bytes"elsePb_codegen_util.string_of_payload_kind~capitalize:()payload_kindfalseletgen_field_commonscencoding_numberpayload_kindmessage_name?(is_packed=false)f=F.linepsc"| Some (%i, Pbrt.%s) -> begin"encoding_number(pbrt_payload_kindpayload_kindis_packed);F.sub_scopescf;F.linesc"end";F.linepsc"| Some (%i, pk) -> "encoding_number;F.linepsc" Pbrt.Decoder.unexpected_payload \"%s\" pk"(sp"Message(%s), field(%i)"message_nameencoding_number)letgen_rft_nolabelscr_namerf_label(field_type,encoding_number,pk)=gen_field_commonscencoding_numberpkr_name(funsc->F.linepsc"v.%s <- %s;"rf_label(decode_field_expressionfield_typepk))(* return the variable name used for keeping track if a required
* field has been set during decoding. *)letis_set_variable_namerf_label=sp"%s_is_set"rf_labelletgen_rft_requiredscr_namerf_label(field_type,encoding_number,pk,_)=gen_field_commonscencoding_numberpkr_name(funsc->F.linepsc"v.%s <- %s; %s := true;"rf_label(decode_field_expressionfield_typepk)(is_set_variable_namerf_label))letgen_rft_optionalscr_namerf_labeloptional_field=letfield_type,encoding_number,pk,_=optional_fieldingen_field_commonscencoding_numberpkr_name(funsc->F.linepsc"v.%s <- Some (%s);"rf_label(decode_field_expressionfield_typepk))letgen_rft_repeatedscr_namerf_labelrepeated_field=letrt,field_type,encoding_number,pk,is_packed=repeated_fieldinmatchrt,is_packedwith|Ot.Rt_list,false->gen_field_commonscencoding_numberpkr_name~is_packed(funsc->F.linepsc"v.%s <- (%s) :: v.%s;"rf_label(decode_field_expressionfield_typepk)rf_label)|Ot.Rt_repeated_field,false->gen_field_commonscencoding_numberpkr_name~is_packed(funsc->F.linepsc"Pbrt.Repeated_field.add (%s) v.%s; "(decode_field_expressionfield_typepk)rf_label)|Ot.Rt_list,true->gen_field_commonscencoding_numberpkr_name~is_packed(funsc->F.linepsc"v.%s <- Pbrt.Decoder.packed_fold (fun l d -> (%s)::l) [] d;"rf_label(decode_field_expressionfield_typepk))|Ot.Rt_repeated_field,true->gen_field_commonscencoding_numberpkr_name~is_packed(funsc->F.linesc"Pbrt.Decoder.packed_fold (fun () d -> ";F.sub_scopesc(funsc->F.linepsc"Pbrt.Repeated_field.add (%s) v.%s;"(decode_field_expressionfield_typepk)rf_label);F.linesc") () d;")letgen_rft_associativescr_namerf_labelassociative_field=letat,encoding_number,(key_type,key_pk),(value_type,value_pk)=associative_fieldinletdecode_key_f=runtime_function_for_basic_typekey_typekey_pkin(* Because key can never be nested we can assign the decoding function
* directly rather wrapping up in a closure like for the value
* below
*)(* TODO enhancement
* For the value decoding function passed as an argument to
* [Pbrt.Decoder.map_entry] it's not always the case that it would
* require nesting. In the case it does not neeed a nested decoder
* we can avoid creating a closure and therefore improving
* the performance. *)gen_field_commonscencoding_numberOt.Pk_bytesr_name(funsc->F.linesc"let decode_value = (fun d ->";F.sub_scopesc(funsc->F.linesc@@decode_field_expressionvalue_typevalue_pk);F.linesc") in";letdecode_expression=sp"(Pbrt.Decoder.map_entry d ~decode_key:%s ~decode_value)"decode_key_finmatchatwith|Ot.At_list->F.linepsc"v.%s <- ("rf_label;F.sub_scopesc(funsc->F.linepsc"%s::v.%s;"decode_expressionrf_label);F.linesc");"|Ot.At_hashtable->F.linepsc"let a, b = %s in"decode_expression;F.linepsc"Hashtbl.add v.%s a b;"rf_label)letgen_rft_variantscr_namerf_label{Ot.v_constructors;_}=List.iter(funvariant_constructor->let{Ot.vc_constructor;vc_field_type;vc_encoding_number;vc_payload_kind=pk;vc_options=_;}=variant_constructoringen_field_commonscvc_encoding_numberpkr_name(funsc->matchvc_field_typewith|Ot.Vct_nullary->F.linesc"Pbrt.Decoder.empty_nested d;";F.linepsc"v.%s <- %s;"rf_labelvc_constructor|Ot.Vct_non_nullary_constructorfield_type->F.linepsc"v.%s <- %s (%s);"rf_labelvc_constructor(decode_field_expressionfield_typepk)))v_constructorsletgen_record?and_{Ot.r_name;r_fields}sc=(* list fields have a special treatement when decoding since each new element
of a repeated field is appended to the front of the list. In order
to retreive the right order efficiently we reverse all the repeated field
lists values when the message is done being decoded. *)letall_lists=List.fold_left(funacc{Ot.rf_label;rf_field_type;_}->matchrf_field_typewith|Ot.Rft_repeated(Ot.Rt_list,_,_,_,_)->rf_label::acc|Ot.Rft_associative(Ot.At_list,_,_,_)->rf_label::acc|_->acc)[]r_fieldsinletall_required_rf_labels=List.fold_left(funacc{Ot.rf_label;rf_field_type;_}->matchrf_field_typewith|Ot.Rft_required_->rf_label::acc|_->acc)[]r_fieldsinletmutable_record_name=Pb_codegen_util.mutable_record_namer_nameinF.linepsc"%s decode_pb_%s d ="(Pb_codegen_util.let_decl_of_andand_)r_name;F.sub_scopesc(funsc->F.linepsc"let v = default_%s () in"mutable_record_name;F.linesc"let continue__= ref true in";(* Add the is_set_<field_name> boolean variable which keeps track
* of whether a required field is set during the decoding. *)List.iter(funrf_label->F.linepsc"let %s = ref false in"(is_set_variable_namerf_label))all_required_rf_labels;(* Decoding is done with recursively (tail - recursive). The
* function loop iterate over all fields returned by the Protobuf
* runtime. *)F.linesc"while !continue__ do";F.sub_scopesc(funsc->F.linesc"match Pbrt.Decoder.key d with";(* termination condition *)F.linesc"| None -> (";F.sub_scopesc(funsc->List.iter(funfield_name->F.linepsc"v.%s <- List.rev v.%s;"field_namefield_name)all_lists);F.linesc"); continue__ := false";(* compare the decoded field with the one defined in the
* .proto file. Unknown fields are ignored. *)List.iter(fun{Ot.rf_label;rf_field_type;_}->matchrf_field_typewith|Ot.Rft_nolabelx->gen_rft_nolabelscr_namerf_labelx|Ot.Rft_requiredx->gen_rft_requiredscr_namerf_labelx|Ot.Rft_optionalx->gen_rft_optionalscr_namerf_labelx|Ot.Rft_repeatedx->gen_rft_repeatedscr_namerf_labelx|Ot.Rft_associativex->gen_rft_associativescr_namerf_labelx|Ot.Rft_variantx->gen_rft_variantscr_namerf_labelx)r_fields;F.linesc("| Some (_, payload_kind) -> "^"Pbrt.Decoder.skip d payload_kind"));F.linesc"done;";(* Add the check to see if all required fields are set if not
* a Protobuf.Decoder.Failure exception is raised *)List.iter(funrf_label->F.linepsc"begin if not !%s then Pbrt.Decoder.missing_field \"%s\" end;"(is_set_variable_namerf_label)rf_label)all_required_rf_labels;F.linesc"({";F.sub_scopesc(funsc->List.iter(fun{Ot.rf_label;_}->F.linepsc"%s = v.%s;"rf_labelrf_label)r_fields);F.linepsc"} : %s)"r_name)letgen_unit?and_{Ot.er_name}sc=F.linepsc"%s decode_pb_%s d ="(Pb_codegen_util.let_decl_of_andand_)er_name;F.sub_scopesc(funsc->F.linesc"match Pbrt.Decoder.key d with";F.linesc"| None -> ();";F.linesc"| Some (_, pk) -> ";F.linepsc" Pbrt.Decoder.unexpected_payload \"%s\" pk"(sp"Unexpected fields in empty message(%s)"er_name))letgen_variant?and_{Ot.v_name;v_constructors}sc=letprocess_ctorscvariant_constructor=let{Ot.vc_constructor;vc_field_type;vc_encoding_number;vc_payload_kind=pk;vc_options=_;}=variant_constructorinmatchvc_field_typewith|Ot.Vct_nullary->F.linepsc"| Some (%i, _) -> begin "vc_encoding_number;F.sub_scopesc(funsc->F.linesc"Pbrt.Decoder.empty_nested d ;";F.linepsc"(%s : %s)"vc_constructorv_name);F.linesc"end"|Ot.Vct_non_nullary_constructorfield_type->F.linepsc"| Some (%i, _) -> (%s (%s) : %s) "vc_encoding_numbervc_constructor(decode_field_expressionfield_typepk)v_nameinF.linepsc"%s decode_pb_%s d = "(Pb_codegen_util.let_decl_of_andand_)v_name;F.sub_scopesc(funsc->F.linepsc"let rec loop () = ";F.sub_scopesc(funsc->F.linepsc"let ret:%s = match Pbrt.Decoder.key d with"v_name;F.sub_scopesc(funsc->F.linepsc"| None -> Pbrt.Decoder.malformed_variant \"%s\""v_name;List.iter(functor->process_ctorscctor)v_constructors;F.linesc"| Some (n, payload_kind) -> (";F.linesc" Pbrt.Decoder.skip d payload_kind; ";F.linesc" loop () ";F.linesc")");F.linesc"in";F.linesc"ret");F.linesc"in";F.linesc"loop ()")letgen_const_variant?and_{Ot.cv_name;cv_constructors}sc=F.linepsc"%s decode_pb_%s d = "(Pb_codegen_util.let_decl_of_andand_)cv_name;F.sub_scopesc(funsc->F.linesc"match Pbrt.Decoder.int_as_varint d with";List.iter(fun{Ot.cvc_name;cvc_binary_value;_}->F.linepsc"| %i -> (%s:%s)"cvc_binary_valuecvc_namecv_name)cv_constructors;F.linepsc"| _ -> Pbrt.Decoder.malformed_variant \"%s\""cv_name)letgen_struct?and_tsc=let{Ot.spec;_}=tinlethas_encoded=matchspecwith|Ot.Recordr->gen_record?and_rsc;true|Ot.Variantv->gen_variant?and_vsc;true|Ot.Const_variantv->gen_const_variant?and_vsc;true|Ot.Unitu->gen_unit?and_usc;trueinhas_encodedletgen_sig?and_tsc=let_=and_inlet{Ot.spec;_}=tinletftype_name=F.linepsc"val decode_pb_%s : Pbrt.Decoder.t -> %s"type_nametype_name;F.linepsc("(** [decode_pb_%s decoder] decodes a "^^"[%s] binary value from [decoder] *)")type_nametype_nameinlethas_encoded=matchspecwith|Ot.Record{Ot.r_name;_}->fr_name;true|Ot.Variant{Ot.v_name;_}->fv_name;true|Ot.Const_variant{Ot.cv_name;_}->fcv_name;true|Ot.Unit{Ot.er_name;_}->fer_name;trueinhas_encodedletocamldoc_title="Protobuf Decoding"letrequires_mutable_records=trueletplugin:Pb_codegen_plugin.t=letmoduleP=structletgen_sig=gen_sigletgen_struct=gen_structletocamldoc_title=ocamldoc_titleletrequires_mutable_records=requires_mutable_recordsendin(moduleP)