123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306moduleOt=Pb_codegen_ocaml_typemoduleF=Pb_codegen_formattingletsp=Pb_codegen_util.spletunsupportedjson_label=failwith(sp"Unsupported field type for field: %s"json_label)letunsupported2json_labelxy=failwith(sp"Unsupported 2 field type for field: %s (%s, %s)"json_label(Pb_codegen_util.string_of_basic_typex)(Pb_codegen_util.string_of_payload_kindyfalse))letsetter_of_basic_typejson_labelbasic_typepk=matchbasic_type,pkwith(* String *)|Ot.Bt_string,_->"string",None(* Float *)|Ot.Bt_float,Ot.Pk_bits32->"number",None|Ot.Bt_float,Ot.Pk_bits64->"string",Some"Js.Float.toString"(* Int32 *)|Ot.Bt_int32,_->"number",Some"Int32.to_float"|Ot.Bt_uint32,_->"number",Some"Int32.to_float"(* Int64 *)|Ot.Bt_int64,Ot.Pk_varint_|Ot.Bt_int64,Ot.Pk_bits64|Ot.Bt_uint64,Ot.Pk_varint_|Ot.Bt_uint64,Ot.Pk_bits64->"string",Some"Int64.to_string"(* 64 bit integer are always encoded as string since
only support up to 51 bits integer. An improvement
could be to check for value > 2^51 and use int *)(* int *)|Ot.Bt_int,Ot.Pk_bits32->"number",Some"float_of_int"|Ot.Bt_int,Ot.Pk_varint_|Ot.Bt_int,Ot.Pk_bits64->"string",Some"string_of_int"(* bool *)|Ot.Bt_bool,Ot.Pk_varint_->"boolean",None(* bytes *)|Ot.Bt_bytes,Ot.Pk_bytes->unsupportedjson_label|x,y->unsupported2json_labelxyletgen_fieldscvar_namejson_labelfield_typepk=(* reusable function for both basic type and wrapped type which
* are both based upon basic type *)letbasic_type_statementbasic_typevar_namepk=letsetter,map_function=setter_of_basic_typejson_labelbasic_typepkinmatchmap_functionwith|None->Printf.sprintf"Js.Dict.set json \"%s\" (Js.Json.%s %s)"json_labelsettervar_name|Somemap_function->Printf.sprintf"Js.Dict.set json \"%s\" (Js.Json.%s (%s %s))"json_labelsettermap_functionvar_nameinmatchfield_type,pkwith|Ot.Ft_unit,_->F.linesc"(* unit type -> encode nothing *)"(* Basic types *)|Ot.Ft_basic_typebasic_type,_->letstatement=basic_type_statementbasic_typevar_namepkinF.linepsc"%s;"statement(* User defined *)|Ot.Ft_user_defined_typeudt,_->let{Ot.udt_type;_}=udtinletf_name=letfunction_prefix="encode"inPb_codegen_util.function_name_of_user_defined~function_prefixudtin(matchudt_typewith|`Message->F.linepsc"begin (* %s field *)"json_label;F.sub_scopesc(funsc->F.linepsc"let json' = %s %s in"f_namevar_name;F.linepsc"Js.Dict.set json \"%s\" (Js.Json.object_ json');"json_label);F.linesc"end;"|`Enum->F.linepsc"Js.Dict.set json \"%s\" (Js.Json.string (%s %s));"json_labelf_namevar_name)|Ot.Ft_wrapper_typewrapper_type,_->let{Ot.wt_type;Ot.wt_pk}=wrapper_typeinF.linesc"begin";F.sub_scopesc(funsc->F.linepsc"match %s with"var_name;F.linepsc"| None -> Js.Dict.set json \"%s\" Js.Json.null"json_label;letstatement=basic_type_statementwt_type"__x__"wt_pkinF.linepsc"| Some __x__ -> %s"statement);F.linesc"end;"letgen_rft_nolabelscvar_namerf_label(field_type,_,pk)=letjson_label=Pb_codegen_util.camel_case_of_labelrf_labelingen_fieldscvar_namejson_labelfield_typepkletgen_rft_optionalscvar_namerf_label(field_type,_,pk,_)=F.linepsc"begin match %s with"var_name;F.linesc"| None -> ()";F.linesc"| Some v ->";F.sub_scopesc(funsc->letjson_label=Pb_codegen_util.camel_case_of_labelrf_labelingen_fieldsc"v"json_labelfield_typepk);F.linesc"end;"letgen_rft_repeatedscvar_namerf_labelrepeated_field=letrepeated_type,field_type,_,pk,_=repeated_fieldin(matchrepeated_typewith|Ot.Rt_list->()|Ot.Rt_repeated_field->sp"Pbrt.Repeated_field is not supported with JSON (field: %s)"rf_label|>failwith);letjson_label=Pb_codegen_util.camel_case_of_labelrf_labelinF.linepsc"begin match %s with"var_name;F.linesc"| [] -> ()";F.linepsc"| __x__ -> (* %s *)"json_label;F.sub_scopesc(funsc->matchfield_type,pkwith|Ot.Ft_unit,_->unsupportedjson_label|Ot.Ft_basic_typebasic_type,_->letsetter,map_function=setter_of_basic_typejson_labelbasic_typepkin(matchmap_functionwith|None->F.linepsc"let a = __x__ |> Array.of_list |> Array.map Js.Json.%s in"setter|Somemap_function->F.linesc@@sp("let a = __x__ |> List.map %s |> Array.of_list "^^"|> Array.map Js.Json.%s in")map_functionsetter);F.linepsc"Js.Dict.set json \"%s\" (Js.Json.array a);"json_label(* User defined *)|Ot.Ft_user_defined_typeudt,Ot.Pk_bytes->letf_name=letfunction_prefix="encode"inPb_codegen_util.function_name_of_user_defined~function_prefixudtinF.linepsc"let (%s':Js.Json.t) ="rf_label;F.sub_scopesc(funsc->F.linesc"__x__";F.linesc"|> Array.of_list";F.linepsc"|> Array.map (fun v ->";F.sub_scopesc(funsc->F.linepsc"v |> %s |> Js.Json.object_"f_name);F.linesc")";F.linesc"|> Js.Json.array");F.linesc"in";F.linepsc"Js.Dict.set json \"%s\" %s'"json_labelrf_label|_->unsupportedjson_label);F.linepsc"end;"letgen_rft_variantscvar_namerf_label{Ot.v_constructors;_}=F.linepsc"begin match %s with"var_name;F.sub_scopesc(funsc->List.iter(fun{Ot.vc_constructor;vc_field_type;vc_payload_kind;_}->letvar_name="v"inletjson_label=Pb_codegen_util.camel_case_of_constructorvc_constructorinF.linepsc"| %s v ->"vc_constructor;F.sub_scopesc(funsc->matchvc_field_typewith|Ot.Vct_nullary->F.linepsc"Js.Dict.set json \"%s\" Js.Json.null"json_label|Ot.Vct_non_nullary_constructorfield_type->gen_fieldscvar_namejson_labelfield_typevc_payload_kind))v_constructors);F.linepsc"end; (* match v.%s *)"rf_labelletgen_record?and_{Ot.r_name;r_fields}sc=letrn=r_nameinF.linepsc"%s encode_%s (v:%s) = "(Pb_codegen_util.let_decl_of_andand_)rnrn;F.sub_scopesc(funsc->F.linesc"let json = Js.Dict.empty () in";List.iter(funrecord_field->let{Ot.rf_label;rf_field_type;_}=record_fieldinletvar_name=sp"v.%s"rf_labelinmatchrf_field_typewith|Ot.Rft_nolabelnolabel_field->gen_rft_nolabelscvar_namerf_labelnolabel_field|Ot.Rft_repeatedrepeated_field->gen_rft_repeatedscvar_namerf_labelrepeated_field|Ot.Rft_variantvariant_field->gen_rft_variantscvar_namerf_labelvariant_field|Ot.Rft_optionaloptional_field->gen_rft_optionalscvar_namerf_labeloptional_field|Ot.Rft_required_->Printf.eprintf"Only proto3 syntax supported in JSON encoding";exit1|Ot.Rft_associative_->Printf.eprintf"Map field are not currently supported for JSON";exit1)r_fields(* List.iter *);F.linesc"json")letgen_variant?and_{Ot.v_name;v_constructors}sc=letprocess_v_constructorscv_constructor=let{Ot.vc_constructor;Ot.vc_field_type;Ot.vc_payload_kind;_}=v_constructorinletjson_label=Pb_codegen_util.camel_case_of_constructorvc_constructorinmatchvc_field_typewith|Ot.Vct_nullary->F.linepsc"| %s ->"vc_constructor;F.linepsc" Js.Dict.set json \"%s\" Js.Json.null"json_label|Ot.Vct_non_nullary_constructorfield_type->F.linepsc"| %s v ->"vc_constructor;F.sub_scopesc(funsc->gen_fieldsc"v"json_labelfield_typevc_payload_kind)inF.linepsc"%s encode_%s (v:%s) = "(Pb_codegen_util.let_decl_of_andand_)v_namev_name;F.sub_scopesc(funsc->F.linesc"let json = Js.Dict.empty () in";F.linesc"begin match v with";List.iter(process_v_constructorsc)v_constructors;F.linesc"end;";F.linesc"json")letgen_const_variant?and_{Ot.cv_name;Ot.cv_constructors}sc=F.linepsc"%s encode_%s (v:%s) : string = "(Pb_codegen_util.let_decl_of_andand_)cv_namecv_name;F.sub_scopesc(funsc->F.linesc"match v with";List.iter(fun{Ot.cvc_name;cvc_string_value;_}->F.linepsc"| %s -> \"%s\""cvc_namecvc_string_value)cv_constructors)letgen_unit?and_{Ot.er_name}sc=letrn=er_nameinF.linepsc"%s encode_%s (_v:%s) = "(Pb_codegen_util.let_decl_of_andand_)rnrn;F.linesc"Js.Json.null"letgen_struct?and_tsc:bool=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.Unitv->gen_unit?and_vsc;trueinhas_encodedletgen_sig?and_tsc=let_=and_inlet{Ot.spec;_}=tinletftype_name=F.linepsc"val encode_%s : %s -> Js.Json.t Js.Dict.t"type_nametype_name;F.linepsc("(** [encode_%s v dict] encodes [v] int the "^^"given JSON [dict] *)")type_nameinmatchspecwith|Ot.Record{Ot.r_name;_}->fr_name;true|Ot.Variantv->fv.Ot.v_name;true|Ot.Const_variant{Ot.cv_name;_}->F.linepsc"val encode_%s : %s -> string"cv_namecv_name;F.linepsc"(** [encode_%s v] returns JSON string *)"cv_name;true|Ot.Unit{Ot.er_name}->F.linepsc"val encode_%s : %s -> Js.Json.t"er_nameer_name;F.linepsc"(** [encode_%s v] returns JSON null *)"er_name;trueletocamldoc_title="Protobuf JSON Encoding"letrequires_mutable_records=falseletplugin:Pb_codegen_plugin.t=letmoduleP=structletgen_sig=gen_sigletgen_struct=gen_structletocamldoc_title=ocamldoc_titleletrequires_mutable_records=requires_mutable_recordsendin(moduleP)