diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..f485c7c4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +_opam +_build diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 36cb9613..a1d7e6a3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,6 +3,7 @@ on: push: branches: - master + - br-4.0 pull_request: jobs: run: @@ -14,20 +15,48 @@ jobs: #- macos-latest #- windows-latest ocaml-compiler: - - 4.08.x - - 4.12.x + - '4.08' + - '4.14' + - '5.1' runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - #with: - # submodules: true + with: + submodules: true - uses: ocaml/setup-ocaml@v2 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} + allow-prerelease-opam: true + dune-cache: true #- run: sudo apt install protobuf-compiler libprotobuf-dev - run: opam pin -n . - run: opam depext -yt ocaml-protoc - run: opam install -t . --deps-only - run: opam exec -- dune build @install - run: opam exec -- dune runtest - #- run: opam exec -- make integration + + integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - run: docker build -f dep/Dockerfile . --target=base + - run: docker build -f dep/Dockerfile . --target=run-the-damn-build + + format: + name: format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + #with: + # submodules: true + - uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: 5.1 + allow-prerelease-opam: true + dune-cache: true + #- run: sudo apt install protobuf-compiler libprotobuf-dev + - run: opam install ocamlformat.0.24.1 + - run: opam exec -- dune build @fmt --auto-promote + - run: git diff -q diff --git a/Makefile.test b/Makefile.test index 08fb9b32..fb6b1715 100644 --- a/Makefile.test +++ b/Makefile.test @@ -32,39 +32,42 @@ tests: # location of where the Google protoc compiler is installed PB_INSTALL ?= /usr/ -PB_HINC = $(PB_INSTALL)/include -PB_LINC = $(PB_INSTALL)/lib +PB_HINC ?= $(PB_INSTALL)/include +PB_LINC ?= $(PB_INSTALL)/lib PROTOC = $(PB_INSTALL)/bin/protoc +PB_HINC_I = $(addprefix -I, $(PB_HINC)) +PB_LINC_L = $(addprefix -L, $(PB_LINC)) + export LD_LIBRARY_PATH=$(PB_LINC) $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc: $(OCAMLOPTIONS_HINC)/ocamloptions.proto cd $(OCAMLOPTIONS_HINC) && \ - $(PROTOC) --cpp_out ./ -I ./ -I $(abspath $(PB_HINC)) ocamloptions.proto + $(PROTOC) --cpp_out ./ -I ./ $(PB_HINC_I) ocamloptions.proto %_cpp.tsk: %_cpp.cpp %.pb.cc $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ - -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(OCAMLOPTIONS_HINC) -I $(PB_HINC) \ - -L $(PB_LINC) -l protobuf \ + -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(OCAMLOPTIONS_HINC) $(PB_HINC_L) \ + $(PB_LINC_L) $(PB_HINC_I) \ $? \ - -o $@ + -o $@ -l protobuf $(INTEGRATION_TESTS_DIR)/test10_cpp.tsk: \ $(INTEGRATION_TESTS_DIR)/test10_cpp.cpp \ $(INTEGRATION_TESTS_DIR)/test10.pb.cc \ $(INTEGRATION_TESTS_DIR)/test09.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ - -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(PB_HINC) \ - -L $(PB_LINC) -l protobuf \ + -I ./ -I $(INTEGRATION_TESTS_DIR) \ + $(PB_LINC_L) $(PB_HINC_I) \ $? \ - -o $@ + -o $@ -l protobuf .SECONDARY: %.pb.cc: %.proto $(PROTOC) \ --cpp_out $(INTEGRATION_TESTS_DIR) \ - -I $(PB_HINC) -I $(OCAMLOPTIONS_HINC) -I $(INTEGRATION_TESTS_DIR) \ + $(PB_HINC_I) -I $(OCAMLOPTIONS_HINC) -I $(INTEGRATION_TESTS_DIR) \ $< diff --git a/README.md b/README.md index 8fc0370e..bf5b3fc4 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ compiler**. See [here](https://github.com/mransan/bs-protobuf-demo) for complete example. - ### A simple example > This example generates the binary encoding, if you are more interested in a **JavaScript** diff --git a/benchs/bin/dune b/benchs/bin/dune index c3173dd5..9fb9214d 100644 --- a/benchs/bin/dune +++ b/benchs/bin/dune @@ -1,4 +1,3 @@ - (executable (name run) (ocamlopt_flags :standard -inline 100) diff --git a/benchs/dune b/benchs/dune index 207e4ef7..b710d38b 100644 --- a/benchs/dune +++ b/benchs/dune @@ -1,7 +1,10 @@ (executable (name benchs) (ocamlopt_flags :standard -inline 100) - (foreign_stubs (language c) (flags :standard -std=c99 -O2) (names stubs)) + (foreign_stubs + (language c) + (flags :standard -std=c99 -O2) + (names stubs)) (libraries ocaml-protoc benchmark)) (rule diff --git a/dep/Dockerfile b/dep/Dockerfile new file mode 100644 index 00000000..b5a911d7 --- /dev/null +++ b/dep/Dockerfile @@ -0,0 +1,22 @@ +FROM ocaml/opam:debian-ocaml-4.14 AS base + +WORKDIR /build/ +RUN sudo chown -R opam: /build/ +RUN sudo apt install protobuf-compiler libprotobuf-dev -y +COPY --chown=opam ./src/ ./src/ +COPY --chown=opam pbrt.opam pbrt_services.opam pbrt_yojson.opam ocaml-protoc.opam \ + Makefile Makefile.test dune-project dune .ocamlformat \ + .ocamlformat-ignore ./ + +RUN opam pin -n . +RUN opam depext -yt ocaml-protoc +RUN opam install -t . --deps-only + +FROM base AS run-the-damn-build +RUN opam exec -- dune build @install +RUN opam exec -- dune runtest + +# integration tests +RUN opam install ppx_deriving -y +RUN opam exec -- make clean build integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/ + diff --git a/src/compilerlib/dune b/src/compilerlib/dune index 7bab48c5..d0cd6229 100644 --- a/src/compilerlib/dune +++ b/src/compilerlib/dune @@ -13,9 +13,10 @@ pb_codegen_make pb_codegen_encode_binary pb_codegen_encode_bs pb_codegen_encode_yojson pb_codegen_formatting pb_codegen_ocaml_type_dump pb_codegen_ocaml_type pb_codegen_pp pb_codegen_plugin pb_codegen_types - pb_codegen_services pb_codegen_util pb_exception pb_field_type pb_location - pb_logger pb_option pb_parsing pb_parsing_lexer pb_parsing_parser - pb_parsing_parse_tree pb_parsing_util pb_typing_graph pb_typing - pb_typing_recursion pb_typing_resolution pb_typing_type_tree - pb_typing_util pb_typing_validation pb_util pb_format_util) + Pb_codegen_decode_pb_options pb_codegen_services pb_codegen_util + pb_exception pb_field_type pb_location pb_logger pb_option pb_raw_option + pb_parsing pb_parsing_lexer pb_parsing_parser pb_parsing_parse_tree + pb_parsing_util pb_typing_graph pb_typing pb_typing_recursion + pb_typing_resolution pb_typing_type_tree pb_typing_util + pb_typing_validation pb_util pb_format_util) (libraries stdlib-shims)) diff --git a/src/compilerlib/pb_codegen_all.ml b/src/compilerlib/pb_codegen_all.ml index 0a0de529..7a822768 100644 --- a/src/compilerlib/pb_codegen_all.ml +++ b/src/compilerlib/pb_codegen_all.ml @@ -40,7 +40,7 @@ let new_ocaml_mod ~proto_file_options ~proto_file_name () : ocaml_mod = let self = { ml = F.empty_scope (); mli = F.empty_scope () } in let print_ppx sc = - match Pb_option.get proto_file_options "ocaml_file_ppx" with + match Pb_raw_option.get_ext proto_file_options "ocaml_file_ppx" with | None -> () | Some Pb_option.(Scalar_value (Constant_string s)) -> F.linep sc "[@@@%s]" s @@ -48,7 +48,7 @@ let new_ocaml_mod ~proto_file_options ~proto_file_name () : ocaml_mod = in (* write preludes *) - F.line self.ml "[@@@ocaml.warning \"-27-30-39\"]"; + F.line self.ml "[@@@ocaml.warning \"-27-30-39-44\"]"; F.empty_line self.ml; print_ppx self.ml; F.empty_line self.mli; diff --git a/src/compilerlib/pb_codegen_all.mli b/src/compilerlib/pb_codegen_all.mli index b693585e..5d7d1a4f 100644 --- a/src/compilerlib/pb_codegen_all.mli +++ b/src/compilerlib/pb_codegen_all.mli @@ -12,7 +12,7 @@ type ocaml_mod = { val codegen : Ot.proto -> generate_make:bool -> - proto_file_options:Pb_option.set -> + proto_file_options:Pb_raw_option.set -> proto_file_name:string -> services:bool -> Plugin.t list -> diff --git a/src/compilerlib/pb_codegen_backend.ml b/src/compilerlib/pb_codegen_backend.ml index 14194ced..183f3463 100644 --- a/src/compilerlib/pb_codegen_backend.ml +++ b/src/compilerlib/pb_codegen_backend.ml @@ -195,7 +195,7 @@ let encoding_info_of_field_type ~all_types field_type : Ot.payload_kind = let encoding_of_field ~all_types (field : (Pb_field_type.resolved, 'a) Tt.field) = let packed = - match Typing_util.field_option field "packed" with + match Typing_util.field_option field (Pb_option.Simple_name "packed") with | Some Pb_option.(Scalar_value (Constant_bool x)) -> x | Some _ -> E.invalid_packed_option (Typing_util.field_name field) | None -> false @@ -209,34 +209,34 @@ let encoding_of_field ~all_types (field : (Pb_field_type.resolved, 'a) Tt.field) let compile_field_type ~unsigned_tag ~(all_types : _ Tt.proto_type list) file_options field_options file_name field_type : Ot.field_type = let ocaml_type = - match Pb_option.get field_options "ocaml_type" with + match Pb_option.get_ext field_options "ocaml_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> `Int_t | _ -> `None in let int32_type = - match Pb_option.get file_options "int32_type" with + match Pb_option.get_ext file_options "int32_type" with | Some Pb_option.(Scalar_value (Pb_option.Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_int32) in let uint32_type = - match Pb_option.get file_options "int32_type" with + match Pb_option.get_ext file_options "int32_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_uint32) in let int64_type = - match Pb_option.get file_options "int64_type" with + match Pb_option.get_ext file_options "int64_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_int64) in let uint64_type = - match Pb_option.get file_options "int64_type" with + match Pb_option.get_ext file_options "int64_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_uint64) @@ -289,13 +289,13 @@ let compile_field_type ~unsigned_tag ~(all_types : _ Tt.proto_type list) | `User_defined id, _ -> user_defined_type_of_id ~all_types ~file_name id let is_mutable ?field_name field_options = - match Pb_option.get field_options "ocaml_mutable" with + match Pb_option.get_ext field_options "ocaml_mutable" with | Some Pb_option.(Scalar_value (Constant_bool v)) -> v | Some _ -> Pb_exception.invalid_mutable_option ?field_name () | None -> false let ocaml_container field_options = - match Pb_option.get field_options "ocaml_container" with + match Pb_option.get_ext field_options "ocaml_container" with | None -> None | Some Pb_option.(Scalar_value (Constant_literal container_name)) -> Some container_name @@ -328,6 +328,7 @@ let variant_of_oneof ?include_oneof_name ~outer_message_names ~unsigned_tag (match field_type with | Ft_unit -> Vct_nullary | _ -> Vct_non_nullary_constructor field_type); + vc_options = field.field_options; }) oneof_field.Tt.oneof_fields in @@ -370,7 +371,7 @@ let process_all_types_ppx_extension file_name file_options match type_level_ppx_extension with | Some x -> Some x | None -> - Pb_option.get file_options "ocaml_all_types_ppx" + Pb_option.get_ext file_options "ocaml_all_types_ppx" |> string_of_string_option file_name let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) @@ -387,7 +388,8 @@ let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) let { Tt.message_names; _ } = scope in let type_level_ppx_extension = - Typing_util.message_option message "ocaml_type_ppx" + Typing_util.message_option message + (Pb_option.Extension_name "ocaml_type_ppx") |> string_of_string_option message_name |> process_all_types_ppx_extension file_name file_options in @@ -411,21 +413,6 @@ let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) } in [ type_ ] - | Tt.Message_oneof_field f :: [] -> - let outer_message_names = message_names @ [ message_name ] in - let variant = - variant_of_oneof ~unsigned_tag ~outer_message_names ~all_types - file_options file_name f - in - [ - Ot. - { - module_prefix; - spec = Variant variant; - type_level_ppx_extension; - type_options = message_options; - }; - ] | _ -> let variants, fields = List.fold_left @@ -647,7 +634,7 @@ let compile_enum file_options file_name scope enum = in let type_level_ppx_extension = - Typing_util.enum_option enum "ocaml_enum_ppx" + Typing_util.enum_option enum (Pb_option.Extension_name "ocaml_enum_ppx") |> string_of_string_option enum_name |> process_all_types_ppx_extension file_name file_options in diff --git a/src/compilerlib/pb_codegen_decode_binary.ml b/src/compilerlib/pb_codegen_decode_binary.ml index f9e98225..1257e065 100644 --- a/src/compilerlib/pb_codegen_decode_binary.ml +++ b/src/compilerlib/pb_codegen_decode_binary.ml @@ -161,6 +161,7 @@ let gen_rft_variant sc r_name rf_label { Ot.v_constructors; _ } = vc_field_type; vc_encoding_number; vc_payload_kind = pk; + vc_options = _; } = variant_constructor in @@ -169,9 +170,9 @@ let gen_rft_variant sc r_name rf_label { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> F.line sc "Pbrt.Decoder.empty_nested d;"; - F.linep sc "v.%s <- %s;" rf_label vc_constructor + F.linep sc "v.%s <- Some %s;" rf_label vc_constructor | Ot.Vct_non_nullary_constructor field_type -> - F.linep sc "v.%s <- %s (%s);" rf_label vc_constructor + F.linep sc "v.%s <- Some (%s (%s));" rf_label vc_constructor (decode_field_expression field_type pk))) v_constructors @@ -281,6 +282,7 @@ let gen_variant ?and_ { Ot.v_name; v_constructors } sc = vc_field_type; vc_encoding_number; vc_payload_kind = pk; + vc_options = _; } = variant_constructor in diff --git a/src/compilerlib/pb_codegen_decode_bs.ml b/src/compilerlib/pb_codegen_decode_bs.ml index 645f782d..7a8c74cd 100644 --- a/src/compilerlib/pb_codegen_decode_bs.ml +++ b/src/compilerlib/pb_codegen_decode_bs.ml @@ -94,12 +94,14 @@ let gen_rft_variant sc ~r_name ~rf_label { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> - F.linep sc "| \"%s\" -> v.%s <- %s" json_label rf_label vc_constructor + F.linep sc "| \"%s\" -> v.%s <- Some %s" json_label rf_label + vc_constructor | Ot.Vct_non_nullary_constructor field_type -> let value_expression = value_expression ~r_name ~rf_label field_type in F.linep sc "| \"%s\" -> " json_label; F.linep sc " let json = Js.Dict.unsafeGet json \"%s\" in" json_label; - F.linep sc " v.%s <- %s (%s)" rf_label vc_constructor value_expression) + F.linep sc " v.%s <- Some (%s (%s))" rf_label vc_constructor + value_expression) v_constructors (* Generate decode function for a record *) diff --git a/src/compilerlib/pb_codegen_decode_bs.mli b/src/compilerlib/pb_codegen_decode_bs.mli index 7c0a8a1c..3aa642c1 100644 --- a/src/compilerlib/pb_codegen_decode_bs.mli +++ b/src/compilerlib/pb_codegen_decode_bs.mli @@ -1,4 +1,3 @@ - include Pb_codegen_plugin.S val plugin : Pb_codegen_plugin.t diff --git a/src/compilerlib/pb_codegen_decode_pb_options.ml b/src/compilerlib/pb_codegen_decode_pb_options.ml new file mode 100644 index 00000000..5278ea4b --- /dev/null +++ b/src/compilerlib/pb_codegen_decode_pb_options.ml @@ -0,0 +1,346 @@ +module Ot = Pb_codegen_ocaml_type +module F = Pb_codegen_formatting + +let sp = Pb_codegen_util.sp + +let field_pattern_match ~r_name ~rf_label field_type = + match field_type with + | Ot.Ft_basic_type bt -> + let decode runtime_f = + sp "Pbrt_pb_options.%s pb_options_value \"%s\" \"%s\"" runtime_f r_name + rf_label + in + let exp = + match bt with + | Ot.Bt_string -> decode "string" + | Ot.Bt_float -> decode "float" + | Ot.Bt_int -> decode "int" + | Ot.Bt_int32 -> decode "int32" + | Ot.Bt_int64 -> decode "int64" + | Ot.Bt_uint32 -> sp "`unsigned (%s)" (decode "int32") + | Ot.Bt_uint64 -> sp "`unsigned (%s)" (decode "int64") + | Ot.Bt_bool -> decode "bool" + | Ot.Bt_bytes -> decode "bytes" + in + "pb_options_value", exp + | Ot.Ft_unit -> + ( "pb_options_value", + sp "Pbrt_pb_options.unit pb_options_value \"%s\" \"%s\"" r_name rf_label ) + | Ot.Ft_user_defined_type udt -> + let f_name = + let function_prefix = "decode_pb_options" in + Pb_codegen_util.function_name_of_user_defined ~function_prefix udt + in + let value_expression = "(" ^ f_name ^ " pb_options_value)" in + "pb_options_value", value_expression + | _ -> assert false + +let pb_options_label_of_field_label rf_label = + match rf_label with + | "and_" | "as_" | "assert_" | "begin_" | "class_" | "constraint_" | "do_" + | "done_" | "downto_" | "else_" | "end_" | "exception_" | "external_" + | "false_" | "for_" | "fun_" | "function_" | "functor_" | "if_" | "in_" + | "include_" | "inherit_" | "initializer_" | "lazy_" | "let_" | "match_" + | "method_" | "module_" | "mutable_" | "new_" | "nonrec_" | "object_" | "of_" + | "open_" | "or_" | "private_" | "rec_" | "sig_" | "struct_" | "then_" | "to_" + | "true_" | "try_" | "type_" | "unit_" | "val_" | "virtual_" | "when_" + | "while_" | "with_" | "mod_" | "land_" | "lor_" | "lxor_" | "lsl_" | "lsr_" + | "asr_" -> + String.sub rf_label 0 (String.length rf_label - 1) + | _ -> rf_label + +(* Generate all the pattern matches for a record field *) +let gen_rft_nolabel sc ~r_name ~rf_label (field_type, _, _) = + let pb_options_label = pb_options_label_of_field_label rf_label in + + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + F.linep sc "| (\"%s\", %s) -> " pb_options_label match_variable_name; + F.linep sc " v.%s <- %s" rf_label exp + +(* Generate all the pattern matches for a repeated field *) +let gen_rft_repeated_field sc ~r_name ~rf_label repeated_field = + let _, field_type, _, _, _ = repeated_field in + + let pb_options_label = pb_options_label_of_field_label rf_label in + + F.linep sc + "| (\"%s\", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin" + pb_options_label; + + F.sub_scope sc (fun sc -> + F.linep sc "v.%s <- List.map (function" rf_label; + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + F.linep sc " | %s -> %s" match_variable_name exp; + F.line sc ") l;"); + + F.line sc "end" + +let gen_rft_optional_field sc ~r_name ~rf_label optional_field = + let field_type, _, _, _ = optional_field in + + let pb_options_label = pb_options_label_of_field_label rf_label in + + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + + F.linep sc "| (\"%s\", %s) -> " pb_options_label match_variable_name; + F.linep sc " v.%s <- Some (%s)" rf_label exp + +(* Generate pattern match for a variant field *) +let gen_rft_variant_field sc ~r_name ~rf_label { Ot.v_constructors; _ } = + List.iter + (fun { Ot.vc_constructor; vc_field_type; _ } -> + let pb_options_label = + Pb_codegen_util.camel_case_of_constructor vc_constructor + in + + match vc_field_type with + | Ot.Vct_nullary -> + F.linep sc "| (\"%s\", _) -> v.%s <- Some %s" pb_options_label rf_label + vc_constructor + | Ot.Vct_non_nullary_constructor field_type -> + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + F.linep sc "| (\"%s\", %s) -> " pb_options_label match_variable_name; + F.linep sc " v.%s <- Some (%s (%s))" rf_label vc_constructor exp) + v_constructors + +let gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type = + let pb_options_label = pb_options_label_of_field_label rf_label in + F.linep sc + "| (\"%s\", Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc) ->" + pb_options_label; + F.sub_scope sc (fun sc -> + let value_name, value_exp = + field_pattern_match ~r_name ~rf_label value_type + in + let key_name = "key" in + let key_exp = + match key_type with + | Ot.Bt_string -> "key" + | Ot.Bt_int -> "(Int.of_string key)" + | Ot.Bt_int32 -> "(Int32.of_string key)" + | Ot.Bt_int64 -> "(Int64.of_string key)" + | Ot.Bt_uint32 -> "(`unsigned (Int32.of_string key))" + | Ot.Bt_uint64 -> "(`unsigned (Int64.of_string key))" + | Ot.Bt_bool -> "(Bool.of_string key)" + | Ot.Bt_float -> + Printf.eprintf "float cannot be used as a map key type"; + exit 1 + | Ot.Bt_bytes -> + Printf.eprintf "bytes cannot be used as a map key type"; + exit 1 + in + F.line sc "let assoc ="; + F.sub_scope sc (fun sc -> + F.line sc "assoc"; + F.linep sc "|> List.map (fun (%s, %s) -> (%s, %s)) " key_name + value_name key_exp value_exp; + F.line sc "|> List.to_seq"; + (* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there + is a repeated key we take the last value associated with it. *) + F.line sc "|> Hashtbl.of_seq"); + F.line sc "in"; + let assoc_exp = + match assoc_type with + | Ot.At_hashtable -> "assoc" + | Ot.At_list -> "assoc |> Hashtbl.to_seq |> List.of_seq" + in + F.linep sc "v.%s <- %s" rf_label assoc_exp) + +(* Generate decode function for a record *) +let gen_record ?and_ { Ot.r_name; r_fields } sc = + let mutable_record_name = Pb_codegen_util.mutable_record_name r_name in + + F.line sc + @@ sp "%s decode_pb_options_%s d =" + (Pb_codegen_util.let_decl_of_and and_) + r_name; + + F.sub_scope sc (fun sc -> + F.linep sc "let v = default_%s () in" mutable_record_name; + F.line sc @@ "let assoc = match d with"; + F.line sc + @@ " | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> \ + assoc"; + F.line sc @@ " | _ -> assert(false)"; + (* TODO raise E *) + F.line sc @@ "in"; + + F.line sc "List.iter (function "; + F.sub_scope sc (fun sc -> + (* Generate pattern match for all the possible message field *) + List.iter + (fun { Ot.rf_label; rf_field_type; _ } -> + match rf_field_type with + | Ot.Rft_nolabel nolabel_field -> + gen_rft_nolabel sc ~r_name ~rf_label nolabel_field + | Ot.Rft_repeated repeated_field -> + gen_rft_repeated_field sc ~r_name ~rf_label repeated_field + | Ot.Rft_variant variant_field -> + gen_rft_variant_field sc ~r_name ~rf_label variant_field + | Ot.Rft_optional optional_field -> + gen_rft_optional_field sc ~r_name ~rf_label optional_field + | Ot.Rft_required _ -> + Printf.eprintf + "Only proto3 syntax supported in pb_options encoding"; + exit 1 + | Ot.Rft_associative + (assoc_type, _, (key_type, _), (value_type, _)) -> + gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type + ~value_type) + r_fields; + + (* Unknown fields are simply ignored *) + F.empty_line sc; + F.line sc "| (_, _) -> () (*Unknown fields are ignored*)"); + F.line sc ") assoc;"; + + (* Transform the mutable record in an immutable one *) + F.line sc "({"; + F.sub_scope sc (fun sc -> + List.iter + (fun { Ot.rf_label; _ } -> + F.linep sc "%s = v.%s;" rf_label rf_label) + r_fields); + F.linep sc "} : %s)" r_name) + +(* Generate decode function for an empty record *) +let gen_unit ?and_ { Ot.er_name } sc = + F.line sc + @@ sp "%s decode_pb_options_%s d =" + (Pb_codegen_util.let_decl_of_and and_) + er_name; + F.line sc (sp "Pbrt_pb_options.unit d \"%s\" \"%s\"" er_name "empty record") + +(* Generate decode function for a variant type *) +let gen_variant ?and_ { Ot.v_name; v_constructors } sc = + (* helper function for each constructor case *) + let process_v_constructor sc { Ot.vc_constructor; vc_field_type; _ } = + let pb_options_label = + Pb_codegen_util.camel_case_of_constructor vc_constructor + in + + match vc_field_type with + | Ot.Vct_nullary -> + F.linep sc "| (\"%s\", _)::_-> (%s : %s)" pb_options_label vc_constructor + v_name + | Ot.Vct_non_nullary_constructor field_type -> + let match_, exp = + let r_name = v_name and rf_label = vc_constructor in + field_pattern_match ~r_name ~rf_label field_type + in + + F.linep sc "| (\"%s\", %s)::_ -> " pb_options_label match_; + F.linep sc " (%s (%s) : %s)" vc_constructor exp v_name + in + + F.linep sc "%s decode_pb_options_%s pb_options =" + (Pb_codegen_util.let_decl_of_and and_) + v_name; + + F.sub_scope sc (fun sc -> + (* even though a variant should be an object with a single field, + * it is possible other fields are present in the pb_options object. Therefore + * we still need a loop to iterate over the key/value, even if in 99.99% + * of the cases it will be a single iteration *) + F.line sc "let assoc = match pb_options with"; + F.line sc + " | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc"; + F.line sc " | _ -> assert(false)"; + (* TODO raise E *) + F.line sc "in"; + + F.line sc "let rec loop = function"; + F.sub_scope sc (fun sc -> + (* termination condition *) + F.linep sc "| [] -> Pbrt_pb_options.E.malformed_variant \"%s\"" v_name; + + List.iter (process_v_constructor sc) v_constructors; + + F.empty_line sc; + F.line sc "| _ :: tl -> loop tl"); + F.line sc "in"; + F.line sc "loop assoc") + +let gen_const_variant ?and_ { Ot.cv_name; cv_constructors } sc = + F.linep sc "%s decode_pb_options_%s pb_options =" + (Pb_codegen_util.let_decl_of_and and_) + cv_name; + + F.sub_scope sc (fun sc -> + F.line sc "match pb_options with"; + List.iter + (fun { Ot.cvc_name; cvc_string_value; _ } -> + F.linep sc + "| Ocaml_protoc_compiler_lib.Pb_option.Scalar_value \ + (Constant_literal \"%s\") -> (%s : %s)" + cvc_string_value cvc_name cv_name) + cv_constructors; + F.linep sc "| _ -> Pbrt_pb_options.E.malformed_variant \"%s\"" cv_name) + +let gen_struct ?and_ t sc = + let { Ot.spec; _ } = t in + let has_encoded = + match spec with + | Ot.Record r -> + gen_record ?and_ r sc; + true + | Ot.Variant v -> + gen_variant ?and_ v sc; + true + | Ot.Const_variant v -> + gen_const_variant ?and_ v sc; + true + | Ot.Unit u -> + gen_unit ?and_ u sc; + true + in + has_encoded + +let gen_sig ?and_ t sc = + let _ = and_ in + let { Ot.spec; _ } = t in + + let f type_name = + F.linep sc + "val decode_pb_options_%s : Ocaml_protoc_compiler_lib.Pb_option.value -> \ + %s" + type_name type_name; + F.linep sc + ("(** [decode_pb_options_%s decoder] decodes a " + ^^ "[%s] value from [decoder] *)") + type_name type_name + in + + match spec with + | Ot.Record { Ot.r_name; _ } -> + f r_name; + true + | Ot.Variant { Ot.v_name; _ } -> + f v_name; + true + | Ot.Const_variant { Ot.cv_name; _ } -> + f cv_name; + true + | Ot.Unit { Ot.er_name; _ } -> + f er_name; + true + +let ocamldoc_title = "Pb_option.set Decoding" +let requires_mutable_records = true + +let plugin : Pb_codegen_plugin.t = + let module P = struct + let gen_sig = gen_sig + let gen_struct = gen_struct + let ocamldoc_title = ocamldoc_title + let requires_mutable_records = requires_mutable_records + end in + (module P) diff --git a/src/compilerlib/pb_codegen_decode_pb_options.mli b/src/compilerlib/pb_codegen_decode_pb_options.mli new file mode 100644 index 00000000..6f01a688 --- /dev/null +++ b/src/compilerlib/pb_codegen_decode_pb_options.mli @@ -0,0 +1,5 @@ +(** Code generator to decode messages from protobuf message options *) + +include Pb_codegen_plugin.S + +val plugin : Pb_codegen_plugin.t diff --git a/src/compilerlib/pb_codegen_decode_yojson.ml b/src/compilerlib/pb_codegen_decode_yojson.ml index cd9a2e1a..58477c4e 100644 --- a/src/compilerlib/pb_codegen_decode_yojson.ml +++ b/src/compilerlib/pb_codegen_decode_yojson.ml @@ -25,7 +25,7 @@ let field_pattern_match ~r_name ~rf_label field_type = | Ot.Bt_bool -> decode "bool" | Ot.Bt_bytes -> decode "bytes" in - ("json_value", exp) + "json_value", exp | Ot.Ft_unit -> "json_value", sp "Pbrt_yojson.unit json_value \"%s\" \"%s\"" r_name rf_label (* TODO Wrapper: add similar one for wrapper type (with different @@ -89,58 +89,56 @@ let gen_rft_variant_field sc ~r_name ~rf_label { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> - F.linep sc "| (\"%s\", _) -> v.%s <- %s" json_label rf_label + F.linep sc "| (\"%s\", _) -> v.%s <- Some %s" json_label rf_label vc_constructor | Ot.Vct_non_nullary_constructor field_type -> let match_variable_name, exp = field_pattern_match ~r_name ~rf_label field_type in F.linep sc "| (\"%s\", %s) -> " json_label match_variable_name; - F.linep sc " v.%s <- %s (%s)" rf_label vc_constructor exp) + F.linep sc " v.%s <- Some (%s (%s))" rf_label vc_constructor exp) v_constructors let gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type = let json_label = Pb_codegen_util.camel_case_of_label rf_label in F.linep sc "| (\"%s\", `Assoc assoc) ->" json_label; F.sub_scope sc (fun sc -> - let value_name, value_exp = field_pattern_match ~r_name ~rf_label value_type in - let key_name = "key" in - let key_exp = - match key_type with - | Ot.Bt_string -> "key" - | Ot.Bt_int -> "(Int.of_string key)" - | Ot.Bt_int32 -> "(Int32.of_string key)" - | Ot.Bt_int64 -> "(Int64.of_string key)" - | Ot.Bt_uint32 -> "(`unsigned (Int32.of_string key))" - | Ot.Bt_uint64 -> "(`unsigned (Int64.of_string key))" - | Ot.Bt_bool -> "(Bool.of_string key)" - | Ot.Bt_float -> - Printf.eprintf "float cannot be used as a map key type"; - exit 1 - | Ot.Bt_bytes -> - Printf.eprintf "bytes cannot be used as a map key type"; - exit 1 - in - F.line sc "let assoc ="; - F.sub_scope sc (fun sc -> - F.line sc "assoc"; - F.linep sc "|> List.map (fun (%s, %s) -> (%s, %s)) " - key_name - value_name - key_exp - value_exp; - F.line sc "|> List.to_seq"; - (* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there - is a repeated key we take the last value associated with it. *) - F.line sc "|> Hashtbl.of_seq"); - F.line sc "in"; - let assoc_exp = - match assoc_type with - | Ot.At_hashtable -> "assoc" - | Ot.At_list -> "assoc |> Hashtbl.to_seq |> List.of_seq" - in - F.linep sc "v.%s <- %s" rf_label assoc_exp); -;; + let value_name, value_exp = + field_pattern_match ~r_name ~rf_label value_type + in + let key_name = "key" in + let key_exp = + match key_type with + | Ot.Bt_string -> "key" + | Ot.Bt_int -> "(Int.of_string key)" + | Ot.Bt_int32 -> "(Int32.of_string key)" + | Ot.Bt_int64 -> "(Int64.of_string key)" + | Ot.Bt_uint32 -> "(`unsigned (Int32.of_string key))" + | Ot.Bt_uint64 -> "(`unsigned (Int64.of_string key))" + | Ot.Bt_bool -> "(Bool.of_string key)" + | Ot.Bt_float -> + Printf.eprintf "float cannot be used as a map key type"; + exit 1 + | Ot.Bt_bytes -> + Printf.eprintf "bytes cannot be used as a map key type"; + exit 1 + in + F.line sc "let assoc ="; + F.sub_scope sc (fun sc -> + F.line sc "assoc"; + F.linep sc "|> List.map (fun (%s, %s) -> (%s, %s)) " key_name + value_name key_exp value_exp; + F.line sc "|> List.to_seq"; + (* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there + is a repeated key we take the last value associated with it. *) + F.line sc "|> Hashtbl.of_seq"); + F.line sc "in"; + let assoc_exp = + match assoc_type with + | Ot.At_hashtable -> "assoc" + | Ot.At_list -> "assoc |> Hashtbl.to_seq |> List.of_seq" + in + F.linep sc "v.%s <- %s" rf_label assoc_exp) (* Generate decode function for a record *) let gen_record ?and_ { Ot.r_name; r_fields } sc = @@ -174,8 +172,10 @@ let gen_record ?and_ { Ot.r_name; r_fields } sc = | Ot.Rft_required _ -> Printf.eprintf "Only proto3 syntax supported in JSON encoding"; exit 1 - | Ot.Rft_associative (assoc_type, _, (key_type, _), (value_type, _)) -> - gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type) + | Ot.Rft_associative + (assoc_type, _, (key_type, _), (value_type, _)) -> + gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type + ~value_type) r_fields; (* Unknown fields are simply ignored *) diff --git a/src/compilerlib/pb_codegen_default.ml b/src/compilerlib/pb_codegen_default.ml index 19d0b4af..70f6cb3f 100644 --- a/src/compilerlib/pb_codegen_default.ml +++ b/src/compilerlib/pb_codegen_default.ml @@ -69,14 +69,7 @@ let record_field_default_info record_field = | Ot.At_hashtable -> "Hashtbl.create 128") (* TODO This initial value could be configurable either via * the default function or via a protobuf option. *) - | Ot.Rft_variant { Ot.v_constructors; _ } -> - (match v_constructors with - | [] -> assert false - | { Ot.vc_constructor; vc_field_type; _ } :: _ -> - (match vc_field_type with - | Ot.Vct_nullary -> vc_constructor - | Ot.Vct_non_nullary_constructor field_type -> - sp "%s (%s)" vc_constructor (dfvft field_type None))) + | Ot.Rft_variant _ -> "None" in field_name, default_value, type_string diff --git a/src/compilerlib/pb_codegen_encode_binary.ml b/src/compilerlib/pb_codegen_encode_binary.ml index 3dcb7b1c..1c3d0944 100644 --- a/src/compilerlib/pb_codegen_encode_binary.ml +++ b/src/compilerlib/pb_codegen_encode_binary.ml @@ -139,22 +139,24 @@ let gen_rft_variant sc var_name { Ot.v_constructors; _ } = vc_field_type; vc_encoding_number; vc_payload_kind; + vc_options = _; } = constructor in match vc_field_type with | Ot.Vct_nullary -> - F.linep sc "| %s ->" vc_constructor; + F.linep sc "| Some %s ->" vc_constructor; F.sub_scope sc (fun sc -> F.line sc "Pbrt.Encoder.empty_nested encoder;"; gen_encode_field_key sc vc_encoding_number vc_payload_kind false) | Ot.Vct_non_nullary_constructor field_type -> - F.linep sc "| %s x ->" vc_constructor; + F.linep sc "| Some %s x ->" vc_constructor; F.sub_scope sc (fun sc -> gen_encode_field_type sc ~with_key:true "x" vc_encoding_number vc_payload_kind false field_type)) v_constructors; + F.line sc "| None -> ()"; F.line sc "end;" let gen_rft_associative sc var_name associative_field = @@ -235,6 +237,7 @@ let gen_variant ?and_ variant sc = vc_field_type; vc_encoding_number; vc_payload_kind; + vc_options = _; } = variant_constructor in diff --git a/src/compilerlib/pb_codegen_encode_bs.ml b/src/compilerlib/pb_codegen_encode_bs.ml index 5c30c9cd..5798d6ba 100644 --- a/src/compilerlib/pb_codegen_encode_bs.ml +++ b/src/compilerlib/pb_codegen_encode_bs.ml @@ -162,14 +162,15 @@ let gen_rft_variant sc var_name rf_label { Ot.v_constructors; _ } = let json_label = Pb_codegen_util.camel_case_of_constructor vc_constructor in - F.linep sc "| %s v ->" vc_constructor; + F.linep sc "| Some (%s v) ->" vc_constructor; F.sub_scope sc (fun sc -> match vc_field_type with | Ot.Vct_nullary -> F.linep sc "Js.Dict.set json \"%s\" Js.Json.null" json_label | Ot.Vct_non_nullary_constructor field_type -> gen_field sc var_name json_label field_type vc_payload_kind)) - v_constructors); + v_constructors; + F.line sc "| None -> ()"); F.linep sc "end; (* match v.%s *)" rf_label let gen_record ?and_ { Ot.r_name; r_fields } sc = diff --git a/src/compilerlib/pb_codegen_encode_yojson.ml b/src/compilerlib/pb_codegen_encode_yojson.ml index bb3f7d06..4fc51d52 100644 --- a/src/compilerlib/pb_codegen_encode_yojson.ml +++ b/src/compilerlib/pb_codegen_encode_yojson.ml @@ -133,7 +133,7 @@ let gen_rft_variant sc rf_label { Ot.v_constructors; _ } = let json_label = Pb_codegen_util.camel_case_of_constructor vc_constructor in - F.linep sc "| %s v ->" vc_constructor; + F.linep sc "| Some (%s v) ->" vc_constructor; F.sub_scope sc (fun sc -> match vc_field_type with | Ot.Vct_nullary -> @@ -144,17 +144,13 @@ let gen_rft_variant sc rf_label { Ot.v_constructors; _ } = with | None -> F.linep sc "(\"%s\", `Null) :: assoc" json_label | Some exp -> F.linep sc "%s :: assoc " exp))) - v_constructors); + v_constructors; + F.line sc "| None -> assoc"); F.linep sc "in (* match v.%s *)" rf_label -let gen_rft_assoc - sc - ~rf_label - ~assoc_type - ~key_type - ~value_field:(value_type, value_pk) - = +let gen_rft_assoc sc ~rf_label ~assoc_type ~key_type + ~value_field:(value_type, value_pk) = let var_name = sp "v.%s" rf_label in let json_label = Pb_codegen_util.camel_case_of_label rf_label in let key_pat, key_exp = @@ -176,44 +172,41 @@ let gen_rft_assoc let write_assoc_field ~fn ~var_name = F.line sc "let assoc_field ="; F.sub_scope sc (fun sc -> - F.linep sc "%s" var_name; - (match assoc_type with - | Ot.At_list -> () - | Ot.At_hashtable -> - F.line sc "|> Hashtbl.to_seq |> List.of_seq"); - F.linep sc "|> List.map (fun (%s, value) -> %s, %s value)" key_pat key_exp fn); - F.line sc "in"; + F.linep sc "%s" var_name; + (match assoc_type with + | Ot.At_list -> () + | Ot.At_hashtable -> F.line sc "|> Hashtbl.to_seq |> List.of_seq"); + F.linep sc "|> List.map (fun (%s, value) -> %s, %s value)" key_pat + key_exp fn); + F.line sc "in" in F.line sc "let assoc ="; F.sub_scope sc (fun sc -> - (match value_type with - | Ot.Ft_unit -> unsupported json_label - | Ot.Ft_basic_type basic_type -> - let runtime_f, map_function = - runtime_function_for_basic_type json_label basic_type value_pk - in - (match map_function with + (match value_type with + | Ot.Ft_unit -> unsupported json_label + | Ot.Ft_basic_type basic_type -> + let runtime_f, map_function = + runtime_function_for_basic_type json_label basic_type value_pk + in + (match map_function with | None -> write_assoc_field ~fn:("Pbrt_yojson." ^ runtime_f) ~var_name | Some map_function -> let fn = - Printf.sprintf - "(fun value -> value |> %s |> Pbrt_yojson.%s)" - map_function - runtime_f + Printf.sprintf "(fun value -> value |> %s |> Pbrt_yojson.%s)" + map_function runtime_f in write_assoc_field ~fn ~var_name) - (* TODO Wrapper: add similar case for Ft_wrapper_type *) - (* User defined *) - | Ot.Ft_user_defined_type udt -> - let fn = - let function_prefix = "encode_json" in - Pb_codegen_util.function_name_of_user_defined ~function_prefix udt - in - write_assoc_field ~fn ~var_name; - | _ -> unsupported json_label); - F.linep sc "(\"%s\", `Assoc assoc_field) :: assoc " json_label); + (* TODO Wrapper: add similar case for Ft_wrapper_type *) + (* User defined *) + | Ot.Ft_user_defined_type udt -> + let fn = + let function_prefix = "encode_json" in + Pb_codegen_util.function_name_of_user_defined ~function_prefix udt + in + write_assoc_field ~fn ~var_name + | _ -> unsupported json_label); + F.linep sc "(\"%s\", `Assoc assoc_field) :: assoc " json_label); F.line sc "in" -;; let gen_record ?and_ { Ot.r_name; r_fields } sc = let rn = r_name in diff --git a/src/compilerlib/pb_codegen_ocaml_type.ml b/src/compilerlib/pb_codegen_ocaml_type.ml index 69328d4b..94ce45f2 100644 --- a/src/compilerlib/pb_codegen_ocaml_type.ml +++ b/src/compilerlib/pb_codegen_ocaml_type.ml @@ -106,6 +106,7 @@ and variant_constructor = { vc_field_type: variant_constructor_type; vc_encoding_number: encoding_number; vc_payload_kind: payload_kind; + vc_options: Pb_option.set; } and variant_constructor_type = diff --git a/src/compilerlib/pb_codegen_ocaml_type_dump.ml b/src/compilerlib/pb_codegen_ocaml_type_dump.ml index e12afdab..6b454069 100644 --- a/src/compilerlib/pb_codegen_ocaml_type_dump.ml +++ b/src/compilerlib/pb_codegen_ocaml_type_dump.ml @@ -74,29 +74,6 @@ module PP = struct | Constant_literal s -> Printf.sprintf "Constant_literal %S" (String.escaped s) - (* Helper function to convert value to string *) - let rec string_of_value value = - match value with - | Pb_option.Scalar_value c -> string_of_constant c - | Message_literal ml -> string_of_message_literal ml - | List_literal ll -> string_of_list_literal ll - - (* Helper function to convert message_literal to string *) - and string_of_message_literal ml = - "{" - ^ String.concat ", " - (List.map - (fun (k, v) -> Printf.sprintf "%S: %s" k (string_of_value v)) - ml) - ^ "}" - - (* Helper function to convert list_literal to string *) - and string_of_list_literal ll = - "[" ^ String.concat ", " (List.map string_of_value ll) ^ "]" - - (* Function to convert options (message_literal) to string *) - let string_of_options options = string_of_message_literal options - (* Helper function to convert default_value to string *) let string_of_default_value dv = match dv with @@ -170,7 +147,9 @@ module PP = struct F.linep sc " Field Type: %s\n" (string_of_variant_constructor_type vc.vc_field_type); F.linep sc " Encoding Number: %d, Payload Kind: %s" vc.vc_encoding_number - (string_of_payload_kind vc.vc_payload_kind) + (string_of_payload_kind vc.vc_payload_kind); + F.linep sc " Options: %s" + (Format.asprintf "%a" Pb_option.pp_set vc.vc_options) (* Helper function to convert variant_constructor_type to string *) and string_of_variant_constructor_type vct = @@ -188,7 +167,8 @@ module PP = struct and print_record_field sc record_field = F.linep sc "- Field: %s" record_field.rf_label; print_record_field_type sc record_field.rf_field_type; - F.linep sc " Field options: %s" (string_of_options record_field.rf_options) + F.linep sc " Field options: %s" + (Format.asprintf "%a" Pb_option.pp_set record_field.rf_options) (* Recursive function to print a const_variant *) let rec print_const_variant sc const_variant = @@ -200,7 +180,8 @@ module PP = struct F.linep sc " Constructor: %s" cvc.cvc_name; F.linep sc " Binary Value: %d, String Value: %s" cvc.cvc_binary_value cvc.cvc_string_value; - F.linep sc " Options: %s" (string_of_options cvc.cvc_options) + F.linep sc " Options: %s" + (Format.asprintf "%a" Pb_option.pp_set cvc.cvc_options) (* Recursive function to print the type_spec *) let print_type_spec sc type_spec = @@ -214,7 +195,8 @@ module PP = struct let print_type sc type_ = F.linep sc "Module Prefix: %s" type_.module_prefix; print_type_spec sc type_.spec; - F.linep sc "Options: %s" (string_of_options type_.type_options); + F.linep sc "Options: %s" + (Format.asprintf "%a" Pb_option.pp_set type_.type_options); match type_.type_level_ppx_extension with | Some ext -> F.linep sc "PPX Extension: %s" ext | None -> () diff --git a/src/compilerlib/pb_codegen_pp.ml b/src/compilerlib/pb_codegen_pp.ml index fdbefc49..9d53cf8e 100644 --- a/src/compilerlib/pb_codegen_pp.ml +++ b/src/compilerlib/pb_codegen_pp.ml @@ -66,7 +66,9 @@ let gen_record ?and_ { Ot.r_name; r_fields } sc = * requirement is indeed comming from the imposed Protobuf format) *) F.line sc - @@ sp "Pbrt.Pp.pp_record_field ~first:%b \"%s\" %s fmt %s;" + @@ sp + "Pbrt.Pp.pp_record_field ~first:%b \"%s\" \ + (Pbrt.Pp.pp_option %s) fmt %s;" first rf_label ("pp_" ^ v_name) var_name (* Rft_variant_field *) | Ot.Rft_associative (at, _, (key_type, _), (value_type, _)) -> diff --git a/src/compilerlib/pb_codegen_util.ml b/src/compilerlib/pb_codegen_util.ml index 0cb6a987..7a3bcef7 100644 --- a/src/compilerlib/pb_codegen_util.ml +++ b/src/compilerlib/pb_codegen_util.ml @@ -68,8 +68,8 @@ let string_of_record_field_type ?module_prefix = function (string_of_associative_type Ot.At_hashtable) | Ot.Rft_variant { Ot.v_name; _ } -> (match module_prefix with - | None -> v_name - | Some module_prefix -> module_prefix ^ "." ^ v_name) + | None -> v_name ^ " option" + | Some module_prefix -> module_prefix ^ "." ^ v_name ^ " option") (** [function_name_of_user_defined prefix user_defined] returns the function name of the form `(module'.'?)prefix_(type_name)`. diff --git a/src/compilerlib/pb_format_util.ml b/src/compilerlib/pb_format_util.ml index 78381fff..0c2a6885 100644 --- a/src/compilerlib/pb_format_util.ml +++ b/src/compilerlib/pb_format_util.ml @@ -1,6 +1,5 @@ open Format - (* Not available in 4.03 *) let pp_print_option ?(none = fun _ () -> ()) pp_v ppf = function | None -> none ppf () diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index f4403a45..554d4966 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -1,3 +1,28 @@ +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + type constant = | Constant_string of string | Constant_bool of bool @@ -5,6 +30,10 @@ type constant = | Constant_float of float | Constant_literal of string +type option_name = + | Simple_name of string + | Extension_name of string + type message_literal = (string * value) list and list_literal = value list @@ -13,19 +42,92 @@ and value = | Message_literal of message_literal | List_literal of list_literal -type option_name = string type t = option_name * value type set = t list +let stringify_option_name = function + | Simple_name s -> s + | Extension_name s -> "(" ^ s ^ ")" + +let option_name_equal a b = + match a, b with + | Simple_name a, Simple_name b -> String.equal a b + | Extension_name a, Extension_name b -> String.equal a b + | _ -> false + let empty = [] -let add t option_name value = (option_name, value) :: t -let merge t1 t2 = t2 @ t1 + +let rec merge_value v1 v2 = + match v1, v2 with + | Message_literal ml1, Message_literal ml2 -> + (* In this case, both the existing and new values are messages. + Iterate through the fields of the new value. + For each field, check if a field with the same name exists in the existing value. + If it does and both field values are messages, merge them recursively. + If it does not, add the new field to the existing message. *) + let rec merge_lists list1 list2 = + match list2 with + | [] -> list1 + | (field, value) :: rest -> + let updated_list, is_merged = + List.fold_left + (fun (acc, merged) (f, v) -> + if String.equal f field then ( + match value, v with + | Message_literal _, Message_literal _ -> + ( acc @ [ f, merge_value value v ], + true (* recursively merges two message literals *) ) + | _ -> acc @ [ f, value ], merged + ) else + acc @ [ f, v ], merged) + ([], false) list1 + in + if is_merged then + (* If the current field of list2 was found in list1 and the two + values merged, continue with the rest of list2. The current field of + list2 is not added to updated_list as its value has already been + included during the merge. *) + merge_lists updated_list rest + else + (* If the current field of list2 was not found in list1, add it to + updated_list. *) + merge_lists (updated_list @ [ field, value ]) rest + in + Message_literal (merge_lists ml1 ml2) + | _ -> + (* FIXME: This overrides the scalar value of an existing option with the + scalar value of a new option, which is not allowed as per Protocol Buffer + Language Specification. *) + v2 + +let add option_set option_name value = + match + List.partition + (fun ((name, _) : t) -> option_name_equal name option_name) + option_set + with + | [], _ -> + (* If the option does not currently exist in the set, add it *) + (option_name, value) :: option_set + | [ (_, existing_value) ], remainder -> + (* If the option already exists in the set, merge it's value with the new value *) + let merged_value = merge_value existing_value value in + (option_name, merged_value) :: remainder + | _ -> + (* This is a sanity check. As we use an equality function, List.partition should + * always partition the list into two lists where the first list has at most one element. + * Hence, the condition that results in a call to failwith should never be satisfied. *) + failwith + "This should not happen, partition should result in at most single item \ + in left component" let get t option_name = - match List.assoc option_name t with - | c -> Some c + match List.find (fun (other, _) -> option_name_equal option_name other) t with + | _, c -> Some c | exception Not_found -> None +let get_ext t option_name = get t (Extension_name option_name) + let pp_constant ppf = function | Constant_string s -> Format.fprintf ppf "%S" s | Constant_bool b -> Format.fprintf ppf "%B" b @@ -56,7 +158,9 @@ and pp_message_field ppf (field, value) = Format.fprintf ppf "%S: %a" field pp_value value let pp_t ppf (name, value) = - Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" name pp_value value + Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" + (stringify_option_name name) + pp_value value let pp_set ppf set = Format.fprintf ppf "[@[%a@]]" diff --git a/src/compilerlib/pb_option.mli b/src/compilerlib/pb_option.mli index ee9c5afc..1df2d0b9 100644 --- a/src/compilerlib/pb_option.mli +++ b/src/compilerlib/pb_option.mli @@ -1,4 +1,73 @@ -(** Protobuf File/Message/Field options *) +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + +(** Protobuf File/Message/Field options + +This module represents "compiled" option set, which is high level +representation, as opposed to low-level representation in Pb_raw_option module. + +For the following "raw" set of options: + +{[ + option (google.api.http).custom.kind = "FETCH"; + option (google.api.http).custom.path = "/foo/bar/baz/{id}"; + option (google.api.http).additional_bindings = { + get: "/foo/bar/baz/{id}" + }; + option (google.api.http).additional_bindings = { + post: "/foo/bar/baz/" + body: "*" + }; +]} + +The "compiled" representation will have only one option [(google.api.http)], +which is a message: + +{[ + option (google.api.http) = { + custom: { + kind: "FETCH" + path: "/foo/bar/baz/{id}" + } + additional_bindings: [ + { + get: "/foo/bar/baz/{id}" + }, + { + post: "/foo/bar/baz/" + body: "*" + } + ] + }; +]} + +Option normalization is happening in [Pb_typing_validation.normalize_option], +destructured field assigments are normalized back to nested messages. See +[Pb_typing_validation.compile_option] to see the full process of option +compilation. +*) (** Protobuf constant @@ -18,24 +87,32 @@ and value = | Message_literal of message_literal | List_literal of list_literal -type option_name = string -(** Option identifier *) +(** Top level option name *) +type option_name = + | Simple_name of string + | Extension_name of string type t = option_name * value type set = t list -(** Collection of options - - Can be used for field/message or file options *) +(** Compiled collection of options *) +val stringify_option_name : option_name -> string val empty : set -val add : set -> string -> value -> set -val merge : set -> set -> set -(** [merge s1 s2] adds all the options from [s2] to [s1]. This means - than in case of duplicates [s2] options will override [s1] options. *) +val add : set -> option_name -> value -> set +(** [add set name value] adds option [(name, value)] into the [set]. Option name +and value are expected to be normalized (see +[Pb_typing_validation.normalize_option]). [add] is merging nested message +literals within option value with the ones that were previously added to the +[set]. *) + +val get : set -> option_name -> value option + +val get_ext : set -> string -> value option +(** [get_ext set name] is a helper that retrieves [Extension_name name] option +from [set] *) -val get : set -> string -> value option val pp_constant : Format.formatter -> constant -> unit val pp_value : Format.formatter -> value -> unit val pp_message_literal : Format.formatter -> message_literal -> unit diff --git a/src/compilerlib/pb_parsing_parse_tree.ml b/src/compilerlib/pb_parsing_parse_tree.ml index 5ee3ebc5..023d3b6e 100644 --- a/src/compilerlib/pb_parsing_parse_tree.ml +++ b/src/compilerlib/pb_parsing_parse_tree.ml @@ -45,7 +45,7 @@ type 'a field = { field_number: int; field_label: 'a; field_type: Pb_field_type.unresolved_t; - field_options: Pb_option.set; + field_options: Pb_raw_option.set; } (** message field. @@ -63,12 +63,12 @@ type map_field = { map_number: int; map_key_type: Pb_field_type.map_key_type; map_value_type: Pb_field_type.unresolved_t; - map_options: Pb_option.set; + map_options: Pb_raw_option.set; } type oneof_body_content = | Oneof_field of oneof_field - | Oneof_option of Pb_option.t + | Oneof_option of Pb_raw_option.t type oneof = { oneof_name: string; @@ -79,12 +79,12 @@ type oneof = { type enum_value = { enum_value_name: string; enum_value_int: int; - enum_value_options: Pb_option.set; + enum_value_options: Pb_raw_option.set; } type enum_body_content = | Enum_value of enum_value - | Enum_option of Pb_option.t + | Enum_option of Pb_raw_option.t type enum = { enum_id: int; @@ -113,7 +113,7 @@ type message_body_content = | Message_enum of enum | Message_extension of extension_range list | Message_reserved of extension_range list - | Message_option of Pb_option.t + | Message_option of Pb_raw_option.t and message = { id: int; @@ -129,7 +129,7 @@ and message = { type rpc = { rpc_name: string; - rpc_options: Pb_option.set; + rpc_options: Pb_raw_option.set; rpc_req_stream: bool; rpc_req: Pb_field_type.unresolved_t; rpc_res_stream: bool; @@ -138,7 +138,7 @@ type rpc = { type service_body_content = | Service_rpc of rpc - | Service_option of Pb_option.t + | Service_option of Pb_raw_option.t type service = { service_name: string; @@ -160,7 +160,7 @@ type proto = { proto_file_name: string option; syntax: string option; imports: import list; - file_options: Pb_option.set; + file_options: Pb_raw_option.set; package: string option; messages: message list; services: service list; @@ -197,7 +197,7 @@ let pp_field pp_label ppf field = field_options = %a;@,\ }@]" field.field_name field.field_number pp_label field.field_label - Pb_field_type.pp_unresolved_t field.field_type Pb_option.pp_set + Pb_field_type.pp_unresolved_t field.field_type Pb_raw_option.pp_set field.field_options let pp_message_field ppf field = pp_field pp_message_field_label ppf field @@ -214,11 +214,11 @@ let pp_map_field ppf map_field = }@]" map_field.map_name map_field.map_number Pb_field_type.pp_map_key_type map_field.map_key_type Pb_field_type.pp_unresolved_t - map_field.map_value_type Pb_option.pp_set map_field.map_options + map_field.map_value_type Pb_raw_option.pp_set map_field.map_options let pp_oneof_body_content ppf = function | Oneof_field field -> pp_oneof_field ppf field - | Oneof_option option -> Pb_option.pp_t ppf option + | Oneof_option option -> Pb_raw_option.pp_t ppf option let pp_oneof ppf oneof = fprintf ppf "{@[%s = %S;@,%s = [@[%a@]];@,@]}" "oneof_name" @@ -235,7 +235,7 @@ let pp_enum_value ppf enum_value = let pp_enum_body_content ppf enum_body_content = match enum_body_content with | Enum_value enum_value -> pp_enum_value ppf enum_value - | Enum_option option -> Pb_option.pp_t ppf option + | Enum_option option -> Pb_raw_option.pp_t ppf option let pp_enum ppf enum = fprintf ppf @@ -278,7 +278,7 @@ let rec pp_message_body_content ppf msg_body_content = ~pp_sep:(fun ppf () -> fprintf ppf ";@,") pp_extension_range) res_ranges - | Message_option option -> Pb_option.pp_t ppf option + | Message_option option -> Pb_raw_option.pp_t ppf option and pp_message ppf message = fprintf ppf @@ -299,14 +299,14 @@ let pp_rpc ppf rpc = rpc_res_stream = %b;@,\ rpc_res = %a;@,\ }@]" - rpc.rpc_name Pb_option.pp_set rpc.rpc_options rpc.rpc_req_stream + rpc.rpc_name Pb_raw_option.pp_set rpc.rpc_options rpc.rpc_req_stream Pb_field_type.pp_unresolved_t rpc.rpc_req rpc.rpc_res_stream Pb_field_type.pp_unresolved_t rpc.rpc_res let rec pp_service_body_content ppf service_body_content = match service_body_content with | Service_rpc rpc -> pp_rpc ppf rpc - | Service_option option -> Pb_option.pp_t ppf option + | Service_option option -> Pb_raw_option.pp_t ppf option and pp_service ppf service = fprintf ppf "{@[@,service_name = %S;@,service_body = [@[%a@]];@,}@]" @@ -344,7 +344,7 @@ let pp_proto ppf proto = (pp_print_option ~none:pp_none pp_print_string) proto.syntax (pp_print_list ~pp_sep:(fun ppf () -> fprintf ppf ";@,") pp_import) - proto.imports Pb_option.pp_set proto.file_options + proto.imports Pb_raw_option.pp_set proto.file_options (pp_print_option ~none:pp_none pp_print_string) proto.package (pp_print_list ~pp_sep:(fun ppf () -> fprintf ppf ";@,") pp_message) diff --git a/src/compilerlib/pb_parsing_parser.mly b/src/compilerlib/pb_parsing_parser.mly index f130effa..0187e0a2 100644 --- a/src/compilerlib/pb_parsing_parser.mly +++ b/src/compilerlib/pb_parsing_parser.mly @@ -68,7 +68,7 @@ /*Entry points*/ %start field_options_ -%type field_options_ +%type field_options_ %start normal_field_ %type normal_field_ %start enum_value_ @@ -86,7 +86,7 @@ %start import_ %type import_ %start option_ -%type option_ +%type option_ %start extension_range_list_ %type extension_range_list_ %start extension_ @@ -129,7 +129,7 @@ proto: proto_content: | import {Pb_parsing_util.proto ~import:$1 ()} - | option {Pb_parsing_util.proto ~file_option:$1 ()} + | option { (let x : Pb_raw_option.t = $1 in Pb_parsing_util.proto ~file_option:x ())} | package_declaration {Pb_parsing_util.proto ~package:$1 ()} | message {Pb_parsing_util.proto ~message:$1 ()} | service {Pb_parsing_util.proto ~service:$1 ()} @@ -227,16 +227,16 @@ rpc : rpc_options : | T_lbrace rpc_options_list T_rbrace { $2 } | T_lbrace rpc_options_list T_rbrace semicolon { $2 } - | T_lbrace T_rbrace { Pb_option.empty } - | T_lbrace T_rbrace semicolon { Pb_option.empty }; + | T_lbrace T_rbrace { Pb_raw_option.empty } + | T_lbrace T_rbrace semicolon { Pb_raw_option.empty }; rpc_options_list : | rpc_option { let option_name, option_value = $1 in - Pb_option.add Pb_option.empty option_name option_value + Pb_raw_option.add Pb_raw_option.empty option_name option_value } | rpc_option rpc_options_list { - Pb_option.add $2 (fst $1) (snd $1) + Pb_raw_option.add $2 (fst $1) (snd $1) } rpc_option : @@ -347,32 +347,30 @@ label : field_options : | T_lbracket field_option_list T_rbracket { $2 } - | T_lbracket T_rbracket { Pb_option.empty }; + | T_lbracket T_rbracket { Pb_raw_option.empty }; field_option_list : | field_option { let option_name, option_value = $1 in - Pb_option.add Pb_option.empty option_name option_value + Pb_raw_option.add Pb_raw_option.empty option_name option_value } | field_option T_comma field_option_list { - Pb_option.add $3 (fst $1) (snd $1) + Pb_raw_option.add $3 (fst $1) (snd $1) } field_option : - | T_ident T_equal option_value { (snd $1, $3) } - | T_lparen T_ident T_rparen T_equal option_value { (snd $2, $5)} - | T_lparen T_ident T_rparen T_ident T_equal option_value { ((snd $2) ^ (snd $4), $6)} + | option_identifier T_equal option_value { ($1, $3) } option_identifier_item : - | T_ident {snd $1} - | T_lparen T_ident T_rparen {snd $2} + | T_ident {snd $1 |> Pb_parsing_util.option_name_of_ident} + | T_lparen T_ident T_rparen {snd $2 |> Pb_parsing_util.option_name_extension} option_identifier : | option_identifier_item {$1} - | option_identifier T_ident {$1 ^ (snd $2)} + | option_identifier_item option_identifier {$1 @ $2} option : - | T_option option_identifier T_equal option_value semicolon { ($2, $4) } + | T_option option_identifier T_equal option_value semicolon { (let foo: Pb_raw_option.t = ($2, $4) in foo) } constant : | T_int { Pb_option.Constant_int $1 } diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index 3ed8463e..c91f63af 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -26,7 +26,7 @@ module E = Pb_exception module Pt = Pb_parsing_parse_tree -let field ?(options = Pb_option.empty) ~label ~number ~type_ name = +let field ?(options = Pb_raw_option.empty) ~label ~number ~type_ name = { Pt.field_name = name; Pt.field_number = number; @@ -35,7 +35,7 @@ let field ?(options = Pb_option.empty) ~label ~number ~type_ name = Pt.field_options = options; } -let map_field ?options:(map_options = Pb_option.empty) ~number ~key_type +let map_field ?options:(map_options = Pb_raw_option.empty) ~number ~key_type ~value_type name = let map_key_type = Pb_field_type.parse key_type |> function @@ -54,7 +54,7 @@ let map_field ?options:(map_options = Pb_option.empty) ~number ~key_type Pt.map_options; } -let oneof_field ?(options = Pb_option.empty) ~number ~type_ name = +let oneof_field ?(options = Pb_raw_option.empty) ~number ~type_ name = Pt.Oneof_field { Pt.field_name = name; @@ -68,7 +68,7 @@ let oneof_option option_ = Pt.Oneof_option option_ let oneof ?(oneof_body = []) name = { Pt.oneof_name = name; Pt.oneof_body } let message_counter = ref 0 -let enum_value ~int_value ?(options = Pb_option.empty) name = +let enum_value ~int_value ?(options = Pb_raw_option.empty) name = Pt.( Enum_value { @@ -114,8 +114,8 @@ let message ~content message_name = let service_body_option option_ = Pt.Service_option option_ let service_body_rpc rpc = Pt.Service_rpc rpc -let rpc ?(options = Pb_option.empty) ~req_stream ~req ~res_stream ~res rpc_name - = +let rpc ?(options = Pb_raw_option.empty) ~req_stream ~req ~res_stream ~res + rpc_name = Pt. { rpc_name; @@ -128,6 +128,18 @@ let rpc ?(options = Pb_option.empty) ~req_stream ~req ~res_stream ~res rpc_name let option_map items = Pb_option.Message_literal items let option_list items = Pb_option.List_literal items + +let option_name_of_ident ident = + let ident = + if Pb_util.String.starts_with ~prefix:"." ident then + String.sub ident 1 (String.length ident - 1) + else + ident + in + ident |> String.split_on_char '.' + |> List.map (fun x -> Pb_raw_option.Simple_name x) + +let option_name_extension ident = [ Pb_raw_option.Extension_name ident ] let service ~content service_name = Pt.{ service_name; service_body = content } let import ?public file_name = @@ -184,7 +196,7 @@ let proto ?syntax ?file_option ?package ?import ?message ?service ?enum ?proto package = None; messages = []; services = []; - file_options = Pb_option.empty; + file_options = Pb_raw_option.empty; enums = []; extends = []; } @@ -235,7 +247,7 @@ let proto ?syntax ?file_option ?package ?import ?message ?service ?enum ?proto match file_option with | None -> proto | Some i -> - let file_options = Pb_option.add file_options (fst i) (snd i) in + let file_options = Pb_raw_option.add file_options (fst i) (snd i) in Pt.{ proto with file_options } in @@ -275,7 +287,7 @@ let finalize_syntax3 proto = in messages. Optional is now allowed, but default values might not be. *) let verify_no_default_field_options field_name message_name field_options = - match Pb_option.get field_options "default" with + match Pb_raw_option.get field_options [ Simple_name "default" ] with | None -> () | Some _ -> E.default_field_option_not_supported ~field_name ~message_name in @@ -315,8 +327,8 @@ let finalize_syntax3 proto = | #Pb_field_type.builtin_type_floating_point | `Bool -> let field_options = - Pb_option.( - add field_options "packed" + Pb_raw_option.( + add_or_replace field_options [ Simple_name "packed" ] (Scalar_value (Constant_bool true))) in { field with Pt.field_options } diff --git a/src/compilerlib/pb_parsing_util.mli b/src/compilerlib/pb_parsing_util.mli index f9bfdaa3..a99e49e3 100644 --- a/src/compilerlib/pb_parsing_util.mli +++ b/src/compilerlib/pb_parsing_util.mli @@ -33,7 +33,7 @@ module Pt = Pb_parsing_parse_tree (** {2 Creators } *) val field : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> label:Pt.message_field_label -> number:int -> type_:string -> @@ -41,7 +41,7 @@ val field : Pt.message_field val map_field : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> number:int -> key_type:string -> value_type:string -> @@ -49,22 +49,22 @@ val map_field : Pt.map_field val oneof_field : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> number:int -> type_:string -> string -> Pt.oneof_body_content -val oneof_option : Pb_option.t -> Pt.oneof_body_content +val oneof_option : Pb_raw_option.t -> Pt.oneof_body_content val oneof : ?oneof_body:Pt.oneof_body_content list -> string -> Pt.oneof val message_body_field : Pt.message_field -> Pt.message_body_content val message_body_map_field : Pt.map_field -> Pt.message_body_content val message_body_oneof_field : Pt.oneof -> Pt.message_body_content val enum_value : - int_value:int -> ?options:Pb_option.set -> string -> Pt.enum_body_content + int_value:int -> ?options:Pb_raw_option.set -> string -> Pt.enum_body_content -val enum_option : Pb_option.t -> Pt.enum_body_content +val enum_option : Pb_raw_option.t -> Pt.enum_body_content val enum : ?enum_body:Pt.enum_body_content list -> string -> Pt.enum val extension_range_single_number : int -> Pt.extension_range @@ -75,11 +75,11 @@ val message_body_sub : Pt.message -> Pt.message_body_content val message_body_enum : Pt.enum -> Pt.message_body_content val message_body_extension : Pt.extension_range list -> Pt.message_body_content val message_body_reserved : Pt.extension_range list -> Pt.message_body_content -val message_body_option : Pb_option.t -> Pt.message_body_content +val message_body_option : Pb_raw_option.t -> Pt.message_body_content val message : content:Pt.message_body_content list -> string -> Pt.message val rpc : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> req_stream:bool -> req:string -> res_stream:bool -> @@ -89,7 +89,9 @@ val rpc : val option_map : Pb_option.message_literal -> Pb_option.value val option_list : Pb_option.list_literal -> Pb_option.value -val service_body_option : Pb_option.t -> Pt.service_body_content +val option_name_of_ident : string -> Pb_raw_option.option_name +val option_name_extension : string -> Pb_raw_option.option_name +val service_body_option : Pb_raw_option.t -> Pt.service_body_content val service_body_rpc : Pt.rpc -> Pt.service_body_content val service : content:Pt.service_body_content list -> string -> Pt.service val import : ?public:unit -> string -> Pt.import @@ -97,7 +99,7 @@ val extend : string -> Pt.message_field list -> Pt.extend val proto : ?syntax:string -> - ?file_option:Pb_option.t -> + ?file_option:Pb_raw_option.t -> ?package:string -> ?import:Pt.import -> ?message:Pt.message -> diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml new file mode 100644 index 00000000..30ec47fb --- /dev/null +++ b/src/compilerlib/pb_raw_option.ml @@ -0,0 +1,108 @@ +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + +type name_part = Pb_option.option_name = + | Simple_name of string + | Extension_name of string + +type option_name = name_part list +type t = option_name * Pb_option.value +type set = t list + +let stringify_option_name name = + name + |> List.map (function + | Simple_name s -> s + | Extension_name s -> "(" ^ s ^ ")") + |> String.concat "." + +let option_name_part_equal a b = + match a, b with + | Simple_name a, Simple_name b -> String.equal a b + | Extension_name a, Extension_name b -> String.equal a b + | _ -> false + +let option_name_equal = Pb_util.List.equal option_name_part_equal +let empty = [] +let add option_set option_name value = (option_name, value) :: option_set + +let add_or_replace option_set option_name value = + let option_set = + List.filter + (fun (option_name', _) -> + not (option_name_equal option_name' option_name)) + option_set + in + add option_set option_name value + +let get t option_name = + match List.find (fun (other, _) -> option_name_equal option_name other) t with + | _, c -> Some c + | exception Not_found -> None + +let get_ext t option_name = get t [ Extension_name option_name ] +let get_simple t option_name = get t [ Simple_name option_name ] + +let assoc_option_name key alist = + try Some (List.find (fun (k, _) -> option_name_equal k key) alist |> snd) + with Not_found -> None + +let remove_assoc_option_name key alist = + List.filter (fun (k, _) -> not (option_name_equal k key)) alist + +let merge set1 set2 = + List.fold_left + (fun acc (option_name, value) -> + let acc = remove_assoc_option_name option_name acc in + add acc option_name value) + set1 set2 + +let group_list_values (set : set) : set = + let rec aux grouped = function + | [] -> + List.map + (function + | name, [ value ] -> name, value + | name, values -> name, Pb_option.List_literal (List.rev values)) + grouped + | (name, value) :: xs -> + (match assoc_option_name name grouped with + | None -> aux ((name, [ value ]) :: grouped) xs + | Some prev_values -> + let grouped = remove_assoc_option_name name grouped in + aux ((name, value :: prev_values) :: grouped) xs) + in + + aux [] set + +let pp_t ppf (name, value) = + Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" + (stringify_option_name name) + Pb_option.pp_value value + +let pp_set ppf set = + Format.fprintf ppf "[@[%a@]]" + (Format.pp_print_list ~pp_sep:(fun ppf () -> Format.fprintf ppf ",@,") pp_t) + set diff --git a/src/compilerlib/pb_raw_option.mli b/src/compilerlib/pb_raw_option.mli new file mode 100644 index 00000000..5b1cfadd --- /dev/null +++ b/src/compilerlib/pb_raw_option.mli @@ -0,0 +1,109 @@ +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + +(** Protobuf File/Message/Field raw options (i.e. exactly as they parsed) *) + +(* +Option names in Protobuf are complicated. See their syntax definition: + + +OptionName = ( SimpleName | ExtensionName ) [ dot OptionName ] . + +SimpleName = identifier . +ExtensionName = l_paren TypeName r_paren + + + +Example of option names are below: + +deprecated +json_name +(foo.bar) +abc.def.xyz +(foo).bar.(.baz.bob) + + +This module is low-level, it tracks list of options as they were parsed, option +name is a list of parts according to syntax specification. Option can be present +multiple times, which means it's a destructured list (see [group_list_values]). + +Good read on Protobuf options: https://github.com/bufbuild/protobuf-language-spec/blob/main/language-spec.md#options +*) + +type name_part = + | Simple_name of string + | Extension_name of string + +type option_name = name_part list +type t = option_name * Pb_option.value +type set = t list + +val stringify_option_name : option_name -> string +val empty : set +val add : set -> option_name -> Pb_option.value -> set +val add_or_replace : set -> option_name -> Pb_option.value -> set + +val merge : set -> set -> set +(** [merge s1 s2] adds all the options from [s2] to [s1]. This means + than in case of duplicates [s2] options will override [s1] options. *) + +val get : set -> option_name -> Pb_option.value option +val get_ext : set -> string -> Pb_option.value option +val get_simple : set -> string -> Pb_option.value option + +val group_list_values : set -> set +(** [group_list_values set] groups options with the same name into Pb_option.List_literal + +The following set of options: + +{[ + option (google.api.http).additional_bindings = { + get: "/foo/bar/baz/{id}" + }; + option (google.api.http).additional_bindings = { + post: "/foo/bar/baz/" + body: "*" + }; +]} + +Is equivalent to the below non-destructured version: + +{[ + option (google.api.http) = { + additional_bindings: [ + { + get: "/foo/bar/baz/{id}" + }, + { + post: "/foo/bar/baz/" + body: "*" + } + ] + }; +]} +*) + +val pp_t : Format.formatter -> t -> unit +val pp_set : Format.formatter -> set -> unit diff --git a/src/compilerlib/pb_typing_util.mli b/src/compilerlib/pb_typing_util.mli index 98724474..43d8ee26 100644 --- a/src/compilerlib/pb_typing_util.mli +++ b/src/compilerlib/pb_typing_util.mli @@ -50,7 +50,8 @@ val field_default : ('a, 'b) Tt.field -> Pb_option.constant option val field_options : ('a, 'b) Tt.field -> Pb_option.set -val field_option : ('a, 'b) Tt.field -> string -> Pb_option.value option +val field_option : + ('a, 'b) Tt.field -> Pb_option.option_name -> Pb_option.value option (** [field_option field option_name] returns the constant associated with [option_name]. If the fields options does not contain [option_name] [None] is returned. @@ -62,8 +63,11 @@ val type_of_id : 'a Tt.proto_type list -> int -> 'a Tt.proto_type *) val string_of_message : int -> Tt.type_scope -> 'a Tt.message -> string -val message_option : 'a Tt.message -> string -> Pb_option.value option -val enum_option : Tt.enum -> string -> Pb_option.value option + +val message_option : + 'a Tt.message -> Pb_option.option_name -> Pb_option.value option + +val enum_option : Tt.enum -> Pb_option.option_name -> Pb_option.value option (** {2 Accessor for Tt.type} *) diff --git a/src/compilerlib/pb_typing_validation.ml b/src/compilerlib/pb_typing_validation.ml index 1810b2c3..7aa45bf5 100644 --- a/src/compilerlib/pb_typing_validation.ml +++ b/src/compilerlib/pb_typing_validation.ml @@ -28,6 +28,54 @@ module Pt = Pb_parsing_parse_tree module Tt = Pb_typing_type_tree module Typing_util = Pb_typing_util +(** Re-construct nested messages out of field path *) +let normalize_option_name option_name value = + List.fold_right + (fun name_part acc -> + match name_part with + | Pb_raw_option.Simple_name name -> + Pb_option.Message_literal [ name, acc ] + | Pb_raw_option.Extension_name name -> + (* TODO: Consider supporting Extension_name in option names, as in + (foo).bar.(.baz.bob) *) + failwith + (Printf.sprintf + "normalize_option_name: Extension_name '%s' is not supported in \ + option_name" + name)) + option_name value + +let option_name_from_part = function + | Pb_raw_option.Simple_name x -> Pb_option.Simple_name x + | Pb_raw_option.Extension_name x -> Pb_option.Extension_name x + +let normalize_option option_name value = + match option_name with + | [] -> failwith "option_name can't be an empty list!" + | [ single_item ] -> + (* Only one top level component in option name - nothing fancy is required + in this case *) + option_name_from_part single_item, value + | top_level_item :: rest -> + (* Top level option is a message, and we need to reconstruct nested messages + inside the value, and leave only top level name component as actual option + name *) + let new_value = normalize_option_name rest value in + option_name_from_part top_level_item, new_value + +(** [compile_options set] is compiling raw options into Pb_option.set *) +let compile_options option_set = + (* Handle destructured lists *) + let option_set = Pb_raw_option.group_list_values option_set in + List.fold_left + (fun set (option_name, value) -> + (* Normalize option names into nested messages within values *) + let option_name, value = normalize_option option_name value in + (* Pb_option.add is smart to merge nested messages, reconstructing the + final message values *) + Pb_option.add set option_name value) + Pb_option.empty option_set + let scope_of_package : string option -> Tt.type_scope = function | Some s -> { @@ -37,7 +85,7 @@ let scope_of_package : string option -> Tt.type_scope = function | None -> Typing_util.empty_scope let get_default field_name field_options : Pb_option.constant option = - match Pb_option.get field_options "default" with + match Pb_raw_option.get_simple field_options "default" with | Some (Pb_option.Scalar_value constant) -> Some constant | Some (Pb_option.Message_literal _) -> E.invalid_default_value ~field_name @@ -51,6 +99,7 @@ let compile_field_p1 field_parsed : _ Tt.field = let { Pt.field_type; Pt.field_options; Pt.field_name; _ } = field_parsed in let field_default = get_default field_name field_options in + let field_options = compile_options field_options in { Tt.field_parsed; Tt.field_type; Tt.field_default; Tt.field_options } let compile_map_p1 map_parsed : _ Tt.map_field = @@ -63,7 +112,7 @@ let compile_map_p1 map_parsed : _ Tt.map_field = } = map_parsed in - + let map_options = compile_options map_options in Tt.{ map_name; map_number; map_key_type; map_value_type; map_options } let compile_oneof_p1 oneof_parsed : _ Tt.oneof = @@ -74,6 +123,19 @@ let compile_oneof_p1 oneof_parsed : _ Tt.oneof = Tt.oneof_options = Pb_option.empty; } in + (* Compile one-of options separately, as compilation requires to see all raw + options at once *) + let oneof_options = + oneof_parsed.Pt.oneof_body + |> Pb_util.List.filter_map (function + | Pt.Oneof_option o -> Some o + | _ -> None) + |> List.fold_left + (fun oneof_options (name, value) -> + Pb_raw_option.add oneof_options name value) + Pb_raw_option.empty + |> compile_options + in let oneof = List.fold_left (fun acc -> function @@ -82,15 +144,11 @@ let compile_oneof_p1 oneof_parsed : _ Tt.oneof = acc with Tt.oneof_fields = compile_field_p1 f :: acc.Tt.oneof_fields; } - | Pt.Oneof_option (name, value) -> - { - acc with - Tt.oneof_options = Pb_option.add acc.Tt.oneof_options name value; - }) + | _ -> acc) init oneof_parsed.Pt.oneof_body in (* now reverse the fields so they're back in the original order *) - { oneof with Tt.oneof_fields = List.rev oneof.oneof_fields } + { oneof with Tt.oneof_fields = List.rev oneof.oneof_fields; Tt.oneof_options } let not_found f : bool = try @@ -111,8 +169,7 @@ let make_proto_type ~file_name ~file_options ~id ~scope ~spec : _ Tt.proto_type { Tt.id; Tt.scope; Tt.file_name; Tt.file_options; Tt.spec } (** compile a [Pbpt] enum to a [Pbtt] type *) -let compile_enum_p1 ?(parent_options = Pb_option.empty) file_name file_options - scope parsed_enum = +let compile_enum_p1 file_name file_options scope parsed_enum = let { Pt.enum_id; enum_name; enum_body } = parsed_enum in let enum_values = @@ -120,11 +177,14 @@ let compile_enum_p1 ?(parent_options = Pb_option.empty) file_name file_options (function | Pt.Enum_value { Pt.enum_value_name; enum_value_int; enum_value_options } -> + let enum_value_options = compile_options enum_value_options in Some Tt.{ enum_value_name; enum_value_int; enum_value_options } | _ -> None) enum_body in + (* Compile enum options separately, as compilation requires to see all raw + options at once *) let enum_options = enum_body |> Pb_util.List.filter_map (function @@ -132,25 +192,19 @@ let compile_enum_p1 ?(parent_options = Pb_option.empty) file_name file_options | _ -> None) |> List.fold_left (fun enum_options (name, value) -> - Pb_option.add enum_options name value) - Pb_option.empty + Pb_raw_option.add enum_options name value) + Pb_raw_option.empty + |> compile_options in - let spec = - Tt.Enum - { - Tt.enum_name; - Tt.enum_values; - Tt.enum_options = Pb_option.merge parent_options enum_options; - } - in + let spec = Tt.Enum { Tt.enum_name; Tt.enum_values; Tt.enum_options } in make_proto_type ~file_name ~file_options ~id:enum_id ~scope ~spec (** compile a [Pbpt] message a list of [Pbtt] types (ie messages can defined more than one type). *) -let rec validate_message ?(parent_options = Pb_option.empty) file_name - file_options message_scope parsed_message : _ Tt.proto_type list = +let rec validate_message file_name file_options message_scope parsed_message : + _ Tt.proto_type list = let { Pt.id; Pt.message_name; Pt.message_body } = parsed_message in let { Tt.message_names; _ } = message_scope in @@ -166,17 +220,12 @@ let rec validate_message ?(parent_options = Pb_option.empty) file_name type ('a, 'b, 'd) t = { message_body: 'a list; extensions: 'b list; - options: Pb_option.set; + options: Pb_raw_option.set; all_types: 'd list; } - let e0 parent_options = - { - message_body = []; - extensions = []; - options = parent_options; - all_types = []; - } + let e0 = + { message_body = []; extensions = []; options = []; all_types = [] } end in let acc = List.fold_left @@ -194,28 +243,23 @@ let rec validate_message ?(parent_options = Pb_option.empty) file_name let field = Tt.Message_oneof_field (compile_oneof_p1 o) in { acc with Acc.message_body = field :: message_body } | Pt.Message_sub m -> - let parent_options = options in let all_sub_types = - validate_message ~parent_options file_name file_options sub_scope m + validate_message file_name file_options sub_scope m in { acc with Acc.all_types = all_types @ all_sub_types } | Pt.Message_enum parsed_enum -> - let parent_options = options in let enum = - compile_enum_p1 ~parent_options file_name file_options sub_scope - parsed_enum + compile_enum_p1 file_name file_options sub_scope parsed_enum in { acc with Acc.all_types = all_types @ [ enum ] } | Pt.Message_extension extension_ranges -> { acc with Acc.extensions = extensions @ extension_ranges } | Pt.Message_reserved _ -> acc (* TODO add support for checking reserved fields *) - | Pt.Message_option message_option -> - let options = - Pb_option.add options (fst message_option) (snd message_option) - in + | Pt.Message_option (name, value) -> + let options = Pb_raw_option.add options name value in { acc with Acc.options }) - (Acc.e0 parent_options) message_body + Acc.e0 message_body in let message_body = List.rev acc.Acc.message_body in @@ -264,7 +308,7 @@ let rec validate_message ?(parent_options = Pb_option.empty) file_name Tt.Message { Tt.extensions = acc.Acc.extensions; - message_options = acc.Acc.options; + message_options = acc.Acc.options |> compile_options; message_name; message_body; } @@ -299,6 +343,7 @@ let validate_service (scope : Tt.type_scope) ~file_name (service : Pt.service) : | `User_defined ty -> ty | _ -> E.invalid_rpc_res_type ~service_name ~rpc_name () in + let rpc_options = compile_options rpc_options in let rpc = { Tt.rpc_name; @@ -334,6 +379,7 @@ let validate (proto : Pt.proto) : _ Tt.proto = let file_name = Pb_util.Option.default "" proto_file_name in let scope = scope_of_package package in + let file_options = compile_options file_options in let pbtt_msgs = List.fold_right diff --git a/src/compilerlib/pb_typing_validation.mli b/src/compilerlib/pb_typing_validation.mli index 796a104e..17a1d20c 100644 --- a/src/compilerlib/pb_typing_validation.mli +++ b/src/compilerlib/pb_typing_validation.mli @@ -44,10 +44,11 @@ val validate : Pt.proto -> Pb_field_type.unresolved Tt.proto (** {2 Testing Only} *) val validate_message : - ?parent_options:Pb_option.set -> string -> Pb_option.set -> (* file options *) Tt.type_scope -> Pt.message -> Pb_field_type.unresolved Tt.proto_type list + +val compile_options : Pb_raw_option.set -> Pb_option.set diff --git a/src/compilerlib/pb_util.ml b/src/compilerlib/pb_util.ml index 2163d46b..dbe15c86 100644 --- a/src/compilerlib/pb_util.ml +++ b/src/compilerlib/pb_util.ml @@ -47,6 +47,22 @@ let string_fold_lefti f e0 s = in loop e0 0 +module String = struct + include String + + let starts_with ~prefix s = + let len_s = length s and len_pre = length prefix in + let rec aux i = + if i = len_pre then + true + else if unsafe_get s i <> unsafe_get prefix i then + false + else + aux (i + 1) + in + len_s >= len_pre && aux 0 +end + module Option = struct let default x = function | Some y -> y @@ -136,6 +152,12 @@ module List = struct (match f x with | Some _ as r -> r | None -> find_map f tl) + + let rec equal eq l1 l2 = + match l1, l2 with + | [], [] -> true + | [], _ :: _ | _ :: _, [] -> false + | a1 :: l1, a2 :: l2 -> eq a1 a2 && equal eq l1 l2 end module Int_map = Map.Make (struct diff --git a/src/compilerlib/pb_util.mli b/src/compilerlib/pb_util.mli index 4320c7a7..5dc120ba 100644 --- a/src/compilerlib/pb_util.mli +++ b/src/compilerlib/pb_util.mli @@ -42,6 +42,14 @@ val string_fold_lefti : ('a -> int -> char -> 'a) -> 'a -> string -> 'a val indentation_prefix : int -> string (** [indentation_prefix level] returns a string of [2 * level] spaces *) +module String : sig + val starts_with : + prefix:(* comment thwarts tools/sync_stdlib_docs *) string -> string -> bool + (** [starts_with ][~prefix s] is [true] if and only if [s] starts with + [prefix]. + *) +end + module Option : sig val default : 'a -> 'a option -> 'a (** [option_default x o] returns [x] is [o] is [None] otherwise [y] @@ -84,6 +92,19 @@ module List : sig val find_opt : ('a -> bool) -> 'a list -> 'a option val find_map : ('a -> 'b option) -> 'a list -> 'b option + + val equal : ('a -> 'a -> bool) -> 'a list -> 'a list -> bool + (** [equal eq [a1; ...; an] [b1; ..; bm]] holds when + the two input lists have the same length, and for each + pair of elements [ai], [bi] at the same position we have + [eq ai bi]. + + Note: the [eq] function may be called even if the + lists have different length. If you know your equality + + function is costly, you may want to check {!compare_lengths} + first. +*) end module Str_map : Map.S with type key = string diff --git a/src/dune b/src/dune index f6dc452c..4dd477ec 100644 --- a/src/dune +++ b/src/dune @@ -1,3 +1,5 @@ - (env - (_ (flags :standard -warn-error -a+8 -w +a-4-40-41-42-44-48-70))) + (_ + (flags :standard -warn-error -a+8 -w +a-4-40-41-42-44-48-70))) + +(data_only_dirs runtime-bs) diff --git a/src/examples/build_server.ml.expected b/src/examples/build_server.ml.expected index ef537783..44dd2584 100644 --- a/src/examples/build_server.ml.expected +++ b/src/examples/build_server.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type file_path = { path : string; diff --git a/src/examples/calculator.ml.expected b/src/examples/calculator.ml.expected index aa1ff3e7..92c79a29 100644 --- a/src/examples/calculator.ml.expected +++ b/src/examples/calculator.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type div_by_zero = unit diff --git a/src/examples/dune b/src/examples/dune index f97e3502..7f33cbb5 100644 --- a/src/examples/dune +++ b/src/examples/dune @@ -94,6 +94,18 @@ (package ocaml-protoc) (libraries pbrt pbrt_yojson pbrt_services)) +(rule + (targets oneof.ml oneof.mli) + (deps oneof.proto) + (action + (run ocaml-protoc --binary --pp --yojson --services --ml_out ./ %{deps}))) + +(test + (name oneof) + (modules oneof) ; just check that it compiles + (package ocaml-protoc) + (libraries pbrt pbrt_yojson pbrt_services)) + (include dune.inc) (rule @@ -107,13 +119,5 @@ (action (with-stdout-to dune.inc.gen - (run - %{gen-dune} - build_server - calculator - example01 - example03 - example04 - example05 - file_server - orgchart)))) + (run %{gen-dune} build_server calculator example01 example03 example04 + example05 file_server orgchart oneof)))) diff --git a/src/examples/dune.inc b/src/examples/dune.inc index e74bd2b6..517799ce 100644 --- a/src/examples/dune.inc +++ b/src/examples/dune.inc @@ -70,6 +70,16 @@ (action (diff file_server.mli.expected file_server.mli))) +(rule + (alias runtest) + (action + (diff oneof.ml.expected oneof.ml))) + +(rule + (alias runtest) + (action + (diff oneof.mli.expected oneof.mli))) + (rule (alias runtest) (action diff --git a/src/examples/example01.ml.expected b/src/examples/example01.ml.expected index a5a8177d..15e076fc 100644 --- a/src/examples/example01.ml.expected +++ b/src/examples/example01.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type person = { name : string; diff --git a/src/examples/example03.ml.expected b/src/examples/example03.ml.expected index 24f42961..0644837f 100644 --- a/src/examples/example03.ml.expected +++ b/src/examples/example03.ml.expected @@ -1,14 +1,24 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type string_some_none = unit -type string_some = +type string_some_t = | None | Some of string +and string_some = { + t : string_some_t option; +} + let rec default_string_some_none = () -let rec default_string_some (): string_some = None +let rec default_string_some_t (): string_some_t = None + +and default_string_some + ?t:((t:string_some_t option) = None) + () : string_some = { + t; +} [@@@ocaml.warning "-27-30-39"] @@ -20,7 +30,13 @@ let rec pp_string_some_none fmt (v:string_some_none) = in Pbrt.Pp.pp_brk pp_i fmt () -let rec pp_string_some fmt (v:string_some) = +let rec pp_string_some_t fmt (v:string_some_t) = match v with | None -> Format.fprintf fmt "None" | Some x -> Format.fprintf fmt "@[Some(@,%a)@]" Pbrt.Pp.pp_string x + +and pp_string_some fmt (v:string_some) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "t" (Pbrt.Pp.pp_option pp_string_some_t) fmt v.t; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/examples/example03.mli.expected b/src/examples/example03.mli.expected index 6911af79..ffee5707 100644 --- a/src/examples/example03.mli.expected +++ b/src/examples/example03.mli.expected @@ -9,17 +9,27 @@ type string_some_none = unit -type string_some = +type string_some_t = | None | Some of string +and string_some = { + t : string_some_t option; +} + (** {2 Basic values} *) val default_string_some_none : unit (** [default_string_some_none ()] is the default value for type [string_some_none] *) -val default_string_some : unit -> string_some +val default_string_some_t : unit -> string_some_t +(** [default_string_some_t ()] is the default value for type [string_some_t] *) + +val default_string_some : + ?t:string_some_t option -> + unit -> + string_some (** [default_string_some ()] is the default value for type [string_some] *) @@ -28,5 +38,8 @@ val default_string_some : unit -> string_some val pp_string_some_none : Format.formatter -> string_some_none -> unit (** [pp_string_some_none v] formats v *) +val pp_string_some_t : Format.formatter -> string_some_t -> unit +(** [pp_string_some_t v] formats v *) + val pp_string_some : Format.formatter -> string_some -> unit (** [pp_string_some v] formats v *) diff --git a/src/examples/example04.ml.expected b/src/examples/example04.ml.expected index 0f9f6b90..7effa1dd 100644 --- a/src/examples/example04.ml.expected +++ b/src/examples/example04.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type int_list_nil = unit @@ -7,10 +7,14 @@ type int_list_cons = { next : int_list; } -and int_list = +and int_list_t = | Cons of int_list_cons | Nil +and int_list = { + t : int_list_t option; +} + let rec default_int_list_nil = () let rec default_int_list_cons @@ -21,7 +25,13 @@ let rec default_int_list_cons next; } -and default_int_list () : int_list = Cons (default_int_list_cons ()) +and default_int_list_t () : int_list_t = Cons (default_int_list_cons ()) + +and default_int_list + ?t:((t:int_list_t option) = None) + () : int_list = { + t; +} [@@@ocaml.warning "-27-30-39"] @@ -40,7 +50,13 @@ let rec pp_int_list_cons fmt (v:int_list_cons) = in Pbrt.Pp.pp_brk pp_i fmt () -and pp_int_list fmt (v:int_list) = +and pp_int_list_t fmt (v:int_list_t) = match v with | Cons x -> Format.fprintf fmt "@[Cons(@,%a)@]" pp_int_list_cons x | Nil -> Format.fprintf fmt "Nil" + +and pp_int_list fmt (v:int_list) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "t" (Pbrt.Pp.pp_option pp_int_list_t) fmt v.t; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/examples/example04.mli.expected b/src/examples/example04.mli.expected index 1b65cb51..71dd0192 100644 --- a/src/examples/example04.mli.expected +++ b/src/examples/example04.mli.expected @@ -14,10 +14,14 @@ type int_list_cons = { next : int_list; } -and int_list = +and int_list_t = | Cons of int_list_cons | Nil +and int_list = { + t : int_list_t option; +} + (** {2 Basic values} *) @@ -31,7 +35,13 @@ val default_int_list_cons : int_list_cons (** [default_int_list_cons ()] is the default value for type [int_list_cons] *) -val default_int_list : unit -> int_list +val default_int_list_t : unit -> int_list_t +(** [default_int_list_t ()] is the default value for type [int_list_t] *) + +val default_int_list : + ?t:int_list_t option -> + unit -> + int_list (** [default_int_list ()] is the default value for type [int_list] *) @@ -43,5 +53,8 @@ val pp_int_list_nil : Format.formatter -> int_list_nil -> unit val pp_int_list_cons : Format.formatter -> int_list_cons -> unit (** [pp_int_list_cons v] formats v *) +val pp_int_list_t : Format.formatter -> int_list_t -> unit +(** [pp_int_list_t v] formats v *) + val pp_int_list : Format.formatter -> int_list -> unit (** [pp_int_list v] formats v *) diff --git a/src/examples/example05.ml.expected b/src/examples/example05.ml.expected index d9d52b7d..1db8fcfa 100644 --- a/src/examples/example05.ml.expected +++ b/src/examples/example05.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type person = { name : string; diff --git a/src/examples/file_server.ml.expected b/src/examples/file_server.ml.expected index 324b4cca..0294aec9 100644 --- a/src/examples/file_server.ml.expected +++ b/src/examples/file_server.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type file_chunk = { path : string; diff --git a/src/examples/oneof.ml.expected b/src/examples/oneof.ml.expected new file mode 100644 index 00000000..d31295b4 --- /dev/null +++ b/src/examples/oneof.ml.expected @@ -0,0 +1,416 @@ +[@@@ocaml.warning "-27-30-39-44"] + +type patch_copy = { + start : int64; + end_ : int64; +} + +type patch_insert = { + raw_bytes : bytes; +} + +type patch_op = + | Copy_op of patch_copy + | Insert_op of patch_insert + +and patch = { + op : patch_op option; + id : int64; +} + +type instructions = { + operations : patch list; +} + +let rec default_patch_copy + ?start:((start:int64) = 0L) + ?end_:((end_:int64) = 0L) + () : patch_copy = { + start; + end_; +} + +let rec default_patch_insert + ?raw_bytes:((raw_bytes:bytes) = Bytes.create 0) + () : patch_insert = { + raw_bytes; +} + +let rec default_patch_op () : patch_op = Copy_op (default_patch_copy ()) + +and default_patch + ?op:((op:patch_op option) = None) + ?id:((id:int64) = 0L) + () : patch = { + op; + id; +} + +let rec default_instructions + ?operations:((operations:patch list) = []) + () : instructions = { + operations; +} + +type patch_copy_mutable = { + mutable start : int64; + mutable end_ : int64; +} + +let default_patch_copy_mutable () : patch_copy_mutable = { + start = 0L; + end_ = 0L; +} + +type patch_insert_mutable = { + mutable raw_bytes : bytes; +} + +let default_patch_insert_mutable () : patch_insert_mutable = { + raw_bytes = Bytes.create 0; +} + +type patch_mutable = { + mutable op : patch_op option; + mutable id : int64; +} + +let default_patch_mutable () : patch_mutable = { + op = None; + id = 0L; +} + +type instructions_mutable = { + mutable operations : patch list; +} + +let default_instructions_mutable () : instructions_mutable = { + operations = []; +} + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Formatters} *) + +let rec pp_patch_copy fmt (v:patch_copy) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "start" Pbrt.Pp.pp_int64 fmt v.start; + Pbrt.Pp.pp_record_field ~first:false "end_" Pbrt.Pp.pp_int64 fmt v.end_; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_patch_insert fmt (v:patch_insert) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "raw_bytes" Pbrt.Pp.pp_bytes fmt v.raw_bytes; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_patch_op fmt (v:patch_op) = + match v with + | Copy_op x -> Format.fprintf fmt "@[Copy_op(@,%a)@]" pp_patch_copy x + | Insert_op x -> Format.fprintf fmt "@[Insert_op(@,%a)@]" pp_patch_insert x + +and pp_patch fmt (v:patch) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "op" (Pbrt.Pp.pp_option pp_patch_op) fmt v.op; + Pbrt.Pp.pp_record_field ~first:false "id" Pbrt.Pp.pp_int64 fmt v.id; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_instructions fmt (v:instructions) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "operations" (Pbrt.Pp.pp_list pp_patch) fmt v.operations; + in + Pbrt.Pp.pp_brk pp_i fmt () + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Protobuf Encoding} *) + +let rec encode_pb_patch_copy (v:patch_copy) encoder = + Pbrt.Encoder.int64_as_varint v.start encoder; + Pbrt.Encoder.key 1 Pbrt.Varint encoder; + Pbrt.Encoder.int64_as_varint v.end_ encoder; + Pbrt.Encoder.key 2 Pbrt.Varint encoder; + () + +let rec encode_pb_patch_insert (v:patch_insert) encoder = + Pbrt.Encoder.bytes v.raw_bytes encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + () + +let rec encode_pb_patch_op (v:patch_op) encoder = + begin match v with + | Copy_op x -> + Pbrt.Encoder.nested encode_pb_patch_copy x encoder; + Pbrt.Encoder.key 3 Pbrt.Bytes encoder; + | Insert_op x -> + Pbrt.Encoder.nested encode_pb_patch_insert x encoder; + Pbrt.Encoder.key 4 Pbrt.Bytes encoder; + end + +and encode_pb_patch (v:patch) encoder = + begin match v.op with + | Some Copy_op x -> + Pbrt.Encoder.nested encode_pb_patch_copy x encoder; + Pbrt.Encoder.key 3 Pbrt.Bytes encoder; + | Some Insert_op x -> + Pbrt.Encoder.nested encode_pb_patch_insert x encoder; + Pbrt.Encoder.key 4 Pbrt.Bytes encoder; + | None -> () + end; + Pbrt.Encoder.int64_as_varint v.id encoder; + Pbrt.Encoder.key 5 Pbrt.Varint encoder; + () + +let rec encode_pb_instructions (v:instructions) encoder = + Pbrt.List_util.rev_iter_with (fun x encoder -> + Pbrt.Encoder.nested encode_pb_patch x encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + ) v.operations encoder; + () + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Protobuf Decoding} *) + +let rec decode_pb_patch_copy d = + let v = default_patch_copy_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Varint) -> begin + v.start <- Pbrt.Decoder.int64_as_varint d; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch_copy), field(1)" pk + | Some (2, Pbrt.Varint) -> begin + v.end_ <- Pbrt.Decoder.int64_as_varint d; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch_copy), field(2)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + start = v.start; + end_ = v.end_; + } : patch_copy) + +let rec decode_pb_patch_insert d = + let v = default_patch_insert_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.raw_bytes <- Pbrt.Decoder.bytes d; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch_insert), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + raw_bytes = v.raw_bytes; + } : patch_insert) + +let rec decode_pb_patch_op d = + let rec loop () = + let ret:patch_op = match Pbrt.Decoder.key d with + | None -> Pbrt.Decoder.malformed_variant "patch_op" + | Some (3, _) -> (Copy_op (decode_pb_patch_copy (Pbrt.Decoder.nested d)) : patch_op) + | Some (4, _) -> (Insert_op (decode_pb_patch_insert (Pbrt.Decoder.nested d)) : patch_op) + | Some (n, payload_kind) -> ( + Pbrt.Decoder.skip d payload_kind; + loop () + ) + in + ret + in + loop () + +and decode_pb_patch d = + let v = default_patch_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (3, Pbrt.Bytes) -> begin + v.op <- Some (Copy_op (decode_pb_patch_copy (Pbrt.Decoder.nested d))); + end + | Some (3, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch), field(3)" pk + | Some (4, Pbrt.Bytes) -> begin + v.op <- Some (Insert_op (decode_pb_patch_insert (Pbrt.Decoder.nested d))); + end + | Some (4, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch), field(4)" pk + | Some (5, Pbrt.Varint) -> begin + v.id <- Pbrt.Decoder.int64_as_varint d; + end + | Some (5, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch), field(5)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + op = v.op; + id = v.id; + } : patch) + +let rec decode_pb_instructions d = + let v = default_instructions_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.operations <- List.rev v.operations; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.operations <- (decode_pb_patch (Pbrt.Decoder.nested d)) :: v.operations; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(instructions), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + operations = v.operations; + } : instructions) + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Protobuf YoJson Encoding} *) + +let rec encode_json_patch_copy (v:patch_copy) = + let assoc = [] in + let assoc = ("start", Pbrt_yojson.make_string (Int64.to_string v.start)) :: assoc in + let assoc = ("end", Pbrt_yojson.make_string (Int64.to_string v.end_)) :: assoc in + `Assoc assoc + +let rec encode_json_patch_insert (v:patch_insert) = + let assoc = [] in + let assoc = ("rawBytes", Pbrt_yojson.make_bytes v.raw_bytes) :: assoc in + `Assoc assoc + +let rec encode_json_patch_op (v:patch_op) = + begin match v with + | Copy_op v -> `Assoc [("copyOp", encode_json_patch_copy v)] + | Insert_op v -> `Assoc [("insertOp", encode_json_patch_insert v)] + end + +and encode_json_patch (v:patch) = + let assoc = [] in + let assoc = match v.op with + | Some (Copy_op v) -> + ("copyOp", encode_json_patch_copy v) :: assoc + | Some (Insert_op v) -> + ("insertOp", encode_json_patch_insert v) :: assoc + | None -> assoc + in (* match v.op *) + let assoc = ("id", Pbrt_yojson.make_string (Int64.to_string v.id)) :: assoc in + `Assoc assoc + +let rec encode_json_instructions (v:instructions) = + let assoc = [] in + let assoc = + let l = v.operations |> List.map encode_json_patch in + ("operations", `List l) :: assoc + in + `Assoc assoc + +[@@@ocaml.warning "-27-30-39"] + +(** {2 JSON Decoding} *) + +let rec decode_json_patch_copy d = + let v = default_patch_copy_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("start", json_value) -> + v.start <- Pbrt_yojson.int64 json_value "patch_copy" "start" + | ("end", json_value) -> + v.end_ <- Pbrt_yojson.int64 json_value "patch_copy" "end_" + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + start = v.start; + end_ = v.end_; + } : patch_copy) + +let rec decode_json_patch_insert d = + let v = default_patch_insert_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("rawBytes", json_value) -> + v.raw_bytes <- Pbrt_yojson.bytes json_value "patch_insert" "raw_bytes" + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + raw_bytes = v.raw_bytes; + } : patch_insert) + +let rec decode_json_patch_op json = + let assoc = match json with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_yojson.E.malformed_variant "patch_op" + | ("copyOp", json_value)::_ -> + (Copy_op ((decode_json_patch_copy json_value)) : patch_op) + | ("insertOp", json_value)::_ -> + (Insert_op ((decode_json_patch_insert json_value)) : patch_op) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_json_patch d = + let v = default_patch_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("copyOp", json_value) -> + v.op <- Some (Copy_op ((decode_json_patch_copy json_value))) + | ("insertOp", json_value) -> + v.op <- Some (Insert_op ((decode_json_patch_insert json_value))) + | ("id", json_value) -> + v.id <- Pbrt_yojson.int64 json_value "patch" "id" + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + op = v.op; + id = v.id; + } : patch) + +let rec decode_json_instructions d = + let v = default_instructions_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("operations", `List l) -> begin + v.operations <- List.map (function + | json_value -> (decode_json_patch json_value) + ) l; + end + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + operations = v.operations; + } : instructions) diff --git a/src/examples/oneof.mli.expected b/src/examples/oneof.mli.expected new file mode 100644 index 00000000..b7037350 --- /dev/null +++ b/src/examples/oneof.mli.expected @@ -0,0 +1,155 @@ + +(** Code for oneof.proto *) + +(* generated from "oneof.proto", do not edit *) + + + +(** {2 Types} *) + +type patch_copy = { + start : int64; + end_ : int64; +} + +type patch_insert = { + raw_bytes : bytes; +} + +type patch_op = + | Copy_op of patch_copy + | Insert_op of patch_insert + +and patch = { + op : patch_op option; + id : int64; +} + +type instructions = { + operations : patch list; +} + + +(** {2 Basic values} *) + +val default_patch_copy : + ?start:int64 -> + ?end_:int64 -> + unit -> + patch_copy +(** [default_patch_copy ()] is the default value for type [patch_copy] *) + +val default_patch_insert : + ?raw_bytes:bytes -> + unit -> + patch_insert +(** [default_patch_insert ()] is the default value for type [patch_insert] *) + +val default_patch_op : unit -> patch_op +(** [default_patch_op ()] is the default value for type [patch_op] *) + +val default_patch : + ?op:patch_op option -> + ?id:int64 -> + unit -> + patch +(** [default_patch ()] is the default value for type [patch] *) + +val default_instructions : + ?operations:patch list -> + unit -> + instructions +(** [default_instructions ()] is the default value for type [instructions] *) + + +(** {2 Formatters} *) + +val pp_patch_copy : Format.formatter -> patch_copy -> unit +(** [pp_patch_copy v] formats v *) + +val pp_patch_insert : Format.formatter -> patch_insert -> unit +(** [pp_patch_insert v] formats v *) + +val pp_patch_op : Format.formatter -> patch_op -> unit +(** [pp_patch_op v] formats v *) + +val pp_patch : Format.formatter -> patch -> unit +(** [pp_patch v] formats v *) + +val pp_instructions : Format.formatter -> instructions -> unit +(** [pp_instructions v] formats v *) + + +(** {2 Protobuf Encoding} *) + +val encode_pb_patch_copy : patch_copy -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch_copy v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_patch_insert : patch_insert -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch_insert v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_patch_op : patch_op -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch_op v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_patch : patch -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_instructions : instructions -> Pbrt.Encoder.t -> unit +(** [encode_pb_instructions v encoder] encodes [v] with the given [encoder] *) + + +(** {2 Protobuf Decoding} *) + +val decode_pb_patch_copy : Pbrt.Decoder.t -> patch_copy +(** [decode_pb_patch_copy decoder] decodes a [patch_copy] binary value from [decoder] *) + +val decode_pb_patch_insert : Pbrt.Decoder.t -> patch_insert +(** [decode_pb_patch_insert decoder] decodes a [patch_insert] binary value from [decoder] *) + +val decode_pb_patch_op : Pbrt.Decoder.t -> patch_op +(** [decode_pb_patch_op decoder] decodes a [patch_op] binary value from [decoder] *) + +val decode_pb_patch : Pbrt.Decoder.t -> patch +(** [decode_pb_patch decoder] decodes a [patch] binary value from [decoder] *) + +val decode_pb_instructions : Pbrt.Decoder.t -> instructions +(** [decode_pb_instructions decoder] decodes a [instructions] binary value from [decoder] *) + + +(** {2 Protobuf YoJson Encoding} *) + +val encode_json_patch_copy : patch_copy -> Yojson.Basic.t +(** [encode_json_patch_copy v encoder] encodes [v] to to json *) + +val encode_json_patch_insert : patch_insert -> Yojson.Basic.t +(** [encode_json_patch_insert v encoder] encodes [v] to to json *) + +val encode_json_patch_op : patch_op -> Yojson.Basic.t +(** [encode_json_patch_op v encoder] encodes [v] to to json *) + +val encode_json_patch : patch -> Yojson.Basic.t +(** [encode_json_patch v encoder] encodes [v] to to json *) + +val encode_json_instructions : instructions -> Yojson.Basic.t +(** [encode_json_instructions v encoder] encodes [v] to to json *) + + +(** {2 JSON Decoding} *) + +val decode_json_patch_copy : Yojson.Basic.t -> patch_copy +(** [decode_json_patch_copy decoder] decodes a [patch_copy] value from [decoder] *) + +val decode_json_patch_insert : Yojson.Basic.t -> patch_insert +(** [decode_json_patch_insert decoder] decodes a [patch_insert] value from [decoder] *) + +val decode_json_patch_op : Yojson.Basic.t -> patch_op +(** [decode_json_patch_op decoder] decodes a [patch_op] value from [decoder] *) + +val decode_json_patch : Yojson.Basic.t -> patch +(** [decode_json_patch decoder] decodes a [patch] value from [decoder] *) + +val decode_json_instructions : Yojson.Basic.t -> instructions +(** [decode_json_instructions decoder] decodes a [instructions] value from [decoder] *) + + +(** {2 Services} *) diff --git a/src/examples/oneof.proto b/src/examples/oneof.proto new file mode 100644 index 00000000..0489c704 --- /dev/null +++ b/src/examples/oneof.proto @@ -0,0 +1,22 @@ +syntax="proto3"; + +message Patch { + message Copy { + int64 start =1; + int64 end=2; + } + + message Insert { + bytes raw_bytes=1; + + } + oneof op { + Copy copy_op=3; + Insert insert_op=4; + } + int64 id = 5; +} + +message Instructions { + repeated Patch operations=1; +} diff --git a/src/examples/orgchart.ml.expected b/src/examples/orgchart.ml.expected index bb9379b4..f6933126 100644 --- a/src/examples/orgchart.ml.expected +++ b/src/examples/orgchart.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type person = { name : string; diff --git a/src/ocaml-protoc/dune b/src/ocaml-protoc/dune index 7204b55e..7c12257f 100644 --- a/src/ocaml-protoc/dune +++ b/src/ocaml-protoc/dune @@ -16,5 +16,5 @@ (re_export pbrt))) (documentation - (package ocaml-protoc) - (mld_files index)) + (package ocaml-protoc) + (mld_files index)) diff --git a/src/ocaml-protoc/ocaml_protoc_cmdline.ml b/src/ocaml-protoc/ocaml_protoc_cmdline.ml index 1f0a5e2a..f665f04a 100644 --- a/src/ocaml-protoc/ocaml_protoc_cmdline.ml +++ b/src/ocaml-protoc/ocaml_protoc_cmdline.ml @@ -77,7 +77,7 @@ module File_options = struct (** Converts the command line values to Parse Tree file options *) - let to_file_options t : Pb_option.set = + let to_file_options t : Pb_raw_option.set = let { int32_type; int64_type; ocaml_file_ppx; ocaml_all_types_ppx } = t in let map x f options = @@ -85,17 +85,19 @@ module File_options = struct | None -> options | Some x -> let option_name, option_value = f x in - Pb_option.add options option_name option_value + Pb_raw_option.add options option_name option_value in - Pb_option.empty + let open Pb_raw_option in + empty |> map int32_type (fun s -> - "int32_type", Pb_option.(Scalar_value (Constant_literal s))) + [ Extension_name "int32_type" ], Scalar_value (Constant_literal s)) |> map int64_type (fun s -> - "int64_type", Pb_option.(Scalar_value (Constant_literal s))) + [ Extension_name "int64_type" ], Scalar_value (Constant_literal s)) |> map ocaml_file_ppx (fun s -> - "ocaml_file_ppx", Pb_option.(Scalar_value (Constant_string s))) + [ Extension_name "ocaml_file_ppx" ], Scalar_value (Constant_string s)) |> map ocaml_all_types_ppx (fun s -> - "ocaml_all_types_ppx", Pb_option.(Scalar_value (Constant_string s))) + ( [ Extension_name "ocaml_all_types_ppx" ], + Scalar_value (Constant_string s) )) end (** Command line argument for the ocaml-protoc *) @@ -112,6 +114,8 @@ module Cmdline = struct pp: bool ref; (** whether pretty printing is enabled *) dump_type_repr: bool ref; (** whether comments with debug ocaml type representation are added *) + pb_options: bool ref; + (** generate decoding for protobuf options (protobuf text format) *) services: bool ref; (** whether services code generation is enabled *) make: bool ref; (** whether to generate "make" functions *) mutable cmd_line_file_options: File_options.t; @@ -132,6 +136,7 @@ module Cmdline = struct bs = ref false; pp = ref false; dump_type_repr = ref false; + pb_options = ref false; services = ref false; make = ref false; cmd_line_file_options = File_options.make (); @@ -148,6 +153,9 @@ module Cmdline = struct Arg.Set t.dump_type_repr, " generate comments with internal representation on generated OCaml \ types (useful for debugging ocaml-protoc itself)" ); + ( "--pb_options", + Arg.Set t.pb_options, + " generate decoders for protobuf options (proto text format)" ); ( "--services", Arg.Set t.services, " generate code for services (requires json+binary)" ); diff --git a/src/ocaml-protoc/ocaml_protoc_compilation.ml b/src/ocaml-protoc/ocaml_protoc_compilation.ml index f6ab4eb4..3e8f0e84 100644 --- a/src/ocaml-protoc/ocaml_protoc_compilation.ml +++ b/src/ocaml-protoc/ocaml_protoc_compilation.ml @@ -76,7 +76,7 @@ let compile cmdline cmd_line_files_options : Ot.proto * _ = { proto with Pt.file_options = - Pb_option.merge proto.Pt.file_options cmd_line_files_options; + Pb_raw_option.merge proto.Pt.file_options cmd_line_files_options; }) protos in diff --git a/src/ocaml-protoc/ocaml_protoc_generation.ml b/src/ocaml-protoc/ocaml_protoc_generation.ml index a1cc999b..e7d55a2f 100644 --- a/src/ocaml-protoc/ocaml_protoc_generation.ml +++ b/src/ocaml-protoc/ocaml_protoc_generation.ml @@ -60,6 +60,10 @@ let generate_code ocaml_types ~proto_file_options cmdline : unit = [ Pb_codegen_ocaml_type_dump.plugin ] else []); + (if !(cmdline.Cmdline.pb_options) then + [ Pb_codegen_decode_pb_options.plugin ] + else + []); (if !(cmdline.Cmdline.pp) then [ Pb_codegen_pp.plugin ] else diff --git a/src/ocaml-protoc/ocaml_protoc_generation.mli b/src/ocaml-protoc/ocaml_protoc_generation.mli index 9a4295f0..d397f80f 100644 --- a/src/ocaml-protoc/ocaml_protoc_generation.mli +++ b/src/ocaml-protoc/ocaml_protoc_generation.mli @@ -4,4 +4,4 @@ module Ot = Pb_codegen_ocaml_type module Cmdline = Ocaml_protoc_cmdline.Cmdline val generate_code : - Ot.proto -> proto_file_options:Pb_option.set -> Cmdline.t -> unit + Ot.proto -> proto_file_options:Pb_raw_option.set -> Cmdline.t -> unit diff --git a/src/runtime-pb-options/dune b/src/runtime-pb-options/dune new file mode 100644 index 00000000..f62703c0 --- /dev/null +++ b/src/runtime-pb-options/dune @@ -0,0 +1,6 @@ +(library + (name pbrt_pb_options) + (public_name ocaml-protoc.rt-pb-options) + (wrapped false) + (libraries + (re_export ocaml-protoc.compiler-lib))) diff --git a/src/runtime-pb-options/pbrt_pb_options.ml b/src/runtime-pb-options/pbrt_pb_options.ml new file mode 100644 index 00000000..2bdd18ff --- /dev/null +++ b/src/runtime-pb-options/pbrt_pb_options.ml @@ -0,0 +1,147 @@ +module E = struct + type error = + | Unexpected_option_type of string * string + | Malformed_variant of string + + exception Failure of error + + let unexpected_option_type record_name field_name = + raise (Failure (Unexpected_option_type (record_name, field_name))) + + let malformed_variant variant_name = + raise (Failure (Malformed_variant variant_name)) + + let string_of_error = function + | Unexpected_option_type (record_name, field_name) -> + Printf.sprintf "Unexpected option type (record name:%s, field_name:%s)" + record_name field_name + | Malformed_variant variant_name -> + Printf.sprintf "Malformed variant (variant name: %s)" variant_name + + let () = + Printexc.register_printer (fun exn -> + match exn with + | Failure e -> Some (string_of_error e) + | _ -> None) +end + +open Ocaml_protoc_compiler_lib + +let unescape_string str = + let buffer = Buffer.create (String.length str) in + let rec aux i = + if i < String.length str then ( + match str.[i] with + | '\\' -> + (match str.[i + 1] with + | 'a' -> + Buffer.add_char buffer '\007'; + aux (i + 2) + | 'b' -> + Buffer.add_char buffer '\b'; + aux (i + 2) + | 'f' -> + Buffer.add_char buffer '\012'; + aux (i + 2) + | 'n' -> + Buffer.add_char buffer '\n'; + aux (i + 2) + | 'r' -> + Buffer.add_char buffer '\r'; + aux (i + 2) + | 't' -> + Buffer.add_char buffer '\t'; + aux (i + 2) + | 'v' -> + Buffer.add_char buffer '\011'; + aux (i + 2) + | '?' -> + Buffer.add_char buffer '?'; + aux (i + 2) + | '\\' -> + Buffer.add_char buffer '\\'; + aux (i + 2) + | '\'' -> + Buffer.add_char buffer '\''; + aux (i + 2) + | '"' -> + Buffer.add_char buffer '"'; + aux (i + 2) + | 'x' -> + (* handle hexadecimal escape *) + let hex = String.sub str (i + 2) 2 in + Buffer.add_char buffer (Char.chr (int_of_string ("0x" ^ hex))); + aux (i + 4) + | 'u' -> + (* handle Unicode escape with 4 hex digits *) + let unicode = String.sub str (i + 2) 4 in + Buffer.add_char buffer (Char.chr (int_of_string ("0x" ^ unicode))); + aux (i + 6) + | 'U' -> + (* handle Unicode escape with 5 hex digits *) + let unicode = String.sub str (i + 2) 5 in + Buffer.add_char buffer (Char.chr (int_of_string ("0x" ^ unicode))); + aux (i + 7) + | c when c >= '0' && c <= '7' -> + (* handle octal escape *) + let end_idx = min (i + 4) (String.length str) in + let rec find_octal_end idx = + if idx < end_idx && str.[idx] >= '0' && str.[idx] <= '7' then + find_octal_end (idx + 1) + else + idx + in + let octal_end = find_octal_end (i + 2) in + let octal = String.sub str (i + 1) (octal_end - i - 1) in + Buffer.add_char buffer (Char.chr (int_of_string ("0o" ^ octal))); + aux octal_end + | c -> failwith (Printf.sprintf "Invalid escape sequence: \\%c" c)) + | c -> + Buffer.add_char buffer c; + aux (i + 1) + ) + in + aux 0; + Buffer.contents buffer + +let int32 v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> Int32.of_float v + | Pb_option.Scalar_value (Constant_int v) -> Int32.of_int v + | _ -> E.unexpected_option_type record_name field_name + +let float v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> v + | Pb_option.Scalar_value (Constant_int v) -> float_of_int v + | _ -> E.unexpected_option_type record_name field_name + +let int64 v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> Int64.of_float v + | Pb_option.Scalar_value (Constant_int v) -> Int64.of_int v + | _ -> E.unexpected_option_type record_name field_name + +let int v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> int_of_float v + | Pb_option.Scalar_value (Constant_int v) -> v + | _ -> E.unexpected_option_type record_name field_name + +let string v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_string v) -> unescape_string v + | _ -> E.unexpected_option_type record_name field_name + +let bool v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_bool v) -> v + | _ -> E.unexpected_option_type record_name field_name + +let bytes v record_name field_name = + string v record_name field_name |> Bytes.of_string + +let unit v record_name field_name = + match v with + | Pb_option.Message_literal [] -> () + | _ -> E.unexpected_option_type record_name field_name diff --git a/src/runtime-pb-options/pbrt_pb_options.mli b/src/runtime-pb-options/pbrt_pb_options.mli new file mode 100644 index 00000000..062dff7a --- /dev/null +++ b/src/runtime-pb-options/pbrt_pb_options.mli @@ -0,0 +1,34 @@ +(** Protobuf JSON encoding runtime *) + +(** All exception which could be raised by the generated JSON encoder + and decode function *) +module E : sig + type error = + | Unexpected_option_type of string * string + | Malformed_variant of string + + exception Failure of error + (** Decoding/Encoding failure *) + + val unexpected_option_type : string -> string -> 'a + (** [unexpected_option_type record_name field_name] raises + [Failure (Unexpected_json_type (record_name, field_name))] *) + + val malformed_variant : string -> 'a + (** [malformed_variant variant_name] raise + [Failure (Malformed_variant variant_name)] *) +end + +open Ocaml_protoc_compiler_lib + +(** Helper module for the generated code for common + functionality *) + +val string : Pb_option.value -> string -> string -> string +val float : Pb_option.value -> string -> string -> float +val int32 : Pb_option.value -> string -> string -> int32 +val int64 : Pb_option.value -> string -> string -> int64 +val int : Pb_option.value -> string -> string -> int +val bool : Pb_option.value -> string -> string -> bool +val bytes : Pb_option.value -> string -> string -> bytes +val unit : Pb_option.value -> string -> string -> unit diff --git a/src/runtime-services/dune b/src/runtime-services/dune index 77e192ed..44170aab 100644 --- a/src/runtime-services/dune +++ b/src/runtime-services/dune @@ -1,4 +1,3 @@ - (library (name pbrt_services) (public_name pbrt_services) diff --git a/src/runtime-yojson/dune b/src/runtime-yojson/dune index c7e629dc..26710039 100644 --- a/src/runtime-yojson/dune +++ b/src/runtime-yojson/dune @@ -1,5 +1,6 @@ - (library - (public_name pbrt_yojson) - (wrapped false) - (libraries (re_export yojson) base64)) + (public_name pbrt_yojson) + (wrapped false) + (libraries + (re_export yojson) + base64)) diff --git a/src/runtime/dune b/src/runtime/dune index e79ebbf9..dbb53caa 100644 --- a/src/runtime/dune +++ b/src/runtime/dune @@ -2,7 +2,10 @@ (name pbrt) (public_name pbrt) (synopsis "Runtime library for ocaml-protoc") - (foreign_stubs (language c) (flags :standard -std=c99 -O2) (names stubs)) + (foreign_stubs + (language c) + (flags :standard -std=c99 -O2) + (names stubs)) ; we need to increase -inline, so that the varint encoder/decoder can ; be remembered by the inliner. (ocamlopt_flags :standard -inline 100)) diff --git a/src/runtime/stubs.c b/src/runtime/stubs.c index eceaf382..739cab64 100644 --- a/src/runtime/stubs.c +++ b/src/runtime/stubs.c @@ -65,7 +65,7 @@ CAMLprim value caml_pbrt_varint_byte(value _str, value _idx, value _i) { CAMLparam3(_str, _idx, _i); char *str = Bytes_val(_str); int idx = Int_val(_idx); - int64_t i = Int64_val(_idx); + int64_t i = Int64_val(_i); pbrt_varint(str + idx, i); CAMLreturn(Val_unit); } diff --git a/src/tests/benchmark/benchmark_single_ml.ml b/src/tests/benchmark/benchmark_single_ml.ml index 6a52e2de..36658596 100644 --- a/src/tests/benchmark/benchmark_single_ml.ml +++ b/src/tests/benchmark/benchmark_single_ml.ml @@ -45,8 +45,12 @@ let make_test_requests ~number_of_sample test_ids = let file_name = Printf.sprintf "test_%s_%i.data" (string_of_test_id test_id) difficulty in - let encode = Bench_t.{ type_ = Encode difficulty; file_name; test_id } in - let decode = Bench_t.{ type_ = Decode; file_name; test_id } in + let encode = + Bench_t.{ type_ = { t = Some (Encode difficulty) }; file_name; test_id } + in + let decode = + Bench_t.{ type_ = { t = Some Decode }; file_name; test_id } + in let init_cases, test_cases = acc in let test_cases = Util.append_n test_cases encode number_of_sample in @@ -150,10 +154,10 @@ let print_compare_type ~metric responses test_ids = (fun data -> let open Bench_t in match data, metric with - | Encode { encode_time; _ }, `Encode_time -> + | Some (Encode { encode_time; _ }), `Encode_time -> sum := !sum +. encode_time; incr counter - | Decode { decode_time; _ }, `Decode_time -> + | Some (Decode { decode_time; _ }), `Decode_time -> sum := !sum +. decode_time; incr counter | _ -> ()) diff --git a/src/tests/benchmark/dune b/src/tests/benchmark/dune index b52ecb90..e37b4e70 100644 --- a/src/tests/benchmark/dune +++ b/src/tests/benchmark/dune @@ -6,6 +6,5 @@ (executable (name benchmark_single_ml) - (modules benchmark_single_ml ocaml_test_types ocaml_test_runner - benchmark) + (modules benchmark_single_ml ocaml_test_types ocaml_test_runner benchmark) (libraries pbrt unix)) diff --git a/src/tests/benchmark/ocaml_test_runner.ml b/src/tests/benchmark/ocaml_test_runner.ml index 4a316ba6..53c8c1f3 100644 --- a/src/tests/benchmark/ocaml_test_runner.ml +++ b/src/tests/benchmark/ocaml_test_runner.ml @@ -27,8 +27,9 @@ end module Make (T : T_sig) : Runner_sig = struct let run { Benchmark.type_; file_name; test_id } = - match type_ with - | Benchmark.Encode difficulty -> + match type_.t with + | None -> failwith "missing benchmark" + | Some (Encode difficulty) -> let t0 = Unix.gettimeofday () in let encoder = Pbrt.Encoder.create () in @@ -53,8 +54,8 @@ module Make (T : T_sig) : Runner_sig = struct } in - Benchmark.{ difficulty_size; test_id; data = Encode encode_data } - | Benchmark.Decode -> + Benchmark.{ difficulty_size; test_id; data = Some (Encode encode_data) } + | Some Decode -> let t0 = Unix.gettimeofday () in let ic = open_in file_name in let len = in_channel_length ic in @@ -69,11 +70,12 @@ module Make (T : T_sig) : Runner_sig = struct difficulty_size = T.difficulty_size v; test_id; data = - Decode - { - Benchmark.from_file_time = t1 -. t0; - Benchmark.decode_time = t2 -. t1; - }; + Some + (Decode + { + Benchmark.from_file_time = t1 -. t0; + Benchmark.decode_time = t2 -. t1; + }); } end (* Make *) diff --git a/src/tests/expectation/dune b/src/tests/expectation/dune index bbcc4c9f..75676633 100644 --- a/src/tests/expectation/dune +++ b/src/tests/expectation/dune @@ -1,9 +1,31 @@ (test - (name tests) + (name test_option_parsing) + (modules Test_option_parsing) (libraries pbrt ocaml-protoc.compiler-lib) (package ocaml-protoc) (flags :standard -open Ocaml_protoc_compiler_lib)) +(test + (name test_option_compilation) + (modules Test_option_compilation) + (libraries pbrt ocaml-protoc.compiler-lib) + (package ocaml-protoc) + (flags :standard -open Ocaml_protoc_compiler_lib)) + +(test + (name it_compiles) + (modules It_compiles Option_processing) + (libraries pbrt ocaml-protoc.compiler-lib) + (package ocaml-protoc) + (flags :standard -open Ocaml_protoc_compiler_lib)) + +(test + (name test_decode_pb_options) + (libraries pbrt ocaml-protoc.compiler-lib ocaml-protoc.rt-pb-options) + (package ocaml-protoc) + (flags :standard -open Ocaml_protoc_compiler_lib) + (modules Test_decode_pb_options Validate)) + (rule (targets option_processing.ml option_processing.mli) (deps option_processing.proto) @@ -14,3 +36,14 @@ (alias runtest) (action (diff option_processing.ml.expected option_processing.ml))) + +(rule + (targets validate.ml validate.mli) + (deps validate.proto) + (action + (run ocaml-protoc --pb_options --pp --ml_out ./ %{deps}))) + +(rule + (alias runtest) + (action + (diff validate.ml.expected validate.ml))) diff --git a/src/tests/expectation/it_compiles.ml b/src/tests/expectation/it_compiles.ml new file mode 100644 index 00000000..844e98a6 --- /dev/null +++ b/src/tests/expectation/it_compiles.ml @@ -0,0 +1,3 @@ +[@@@warning "-66"] + +open! Option_processing diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index d36a0f95..95634a35 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type payment_system = | Cash @@ -11,9 +11,10 @@ type person_location = { lng : float; } -type person_id = +type person_xyz = | X of string | Y of int32 + | Z of float and person = { id : int64; @@ -21,9 +22,11 @@ and person = { name : string; home : person_location option; picture : bytes; - id : person_id; + xyz : person_xyz option; } +type destructured_options = unit + let rec default_payment_system () = (Cash:payment_system) let rec default_person_location @@ -34,7 +37,7 @@ let rec default_person_location lng; } -let rec default_person_id () : person_id = X ("") +let rec default_person_xyz () : person_xyz = X ("") and default_person ?id:((id:int64) = 0L) @@ -42,16 +45,18 @@ and default_person ?name:((name:string) = "") ?home:((home:person_location option) = None) ?picture:((picture:bytes) = Bytes.create 0) - ?id:((id:person_id) = X ("")) + ?xyz:((xyz:person_xyz option) = None) () : person = { id; email; name; home; picture; - id; + xyz; } +let rec default_destructured_options = () + [@@@ocaml.warning "-27-30-39"] (** {2 Dump of internal representation for generated OCaml types} *) @@ -62,17 +67,27 @@ and default_person Const Variant: payment_system Constructor: Cash Binary Value: 0, String Value: CASH - Options: {"label": Constant_string "Cash"} + Options: [{ + "(label)": "Cash" + }] Constructor: Credit_card Binary Value: 1, String Value: CREDIT_CARD - Options: {"label": Constant_string "Credit Card"} + Options: [{ + "(label)": "Credit Card" + }] Constructor: Debit_card Binary Value: 2, String Value: DEBIT_CARD - Options: {"label": Constant_string "Debit Card"} + Options: [{ + "(label)": "Debit Card" + }] Constructor: App Binary Value: 3, String Value: APP - Options: {"label": Constant_string "Mobile App"} - Options: {"label": Constant_string "Payment method"} + Options: [{ + "(label)": "Mobile App" + }] + Options: [{ + "(label)": "Payment method" + }] *) (* ----------------------------------------------------- *) @@ -81,26 +96,43 @@ and default_person Record: person_location - Field: lat Rft_nolabel (Field Type: Ft_basic_type: Bt_float, Encoding: 1, Payload Kind: Pk_bits64) - Field options: {"validate.rules.double": {"gte": Constant_int -90, "lte": Constant_int 90}} + Field options: [{ + "(validate.rules)": {"double": {"gte": -90, + "lte": 90}} + }] - Field: lng Rft_nolabel (Field Type: Ft_basic_type: Bt_float, Encoding: 2, Payload Kind: Pk_bits64) - Field options: {"validate.rules.double": {"gte": Constant_int -180, "lte": Constant_int 180}} - Options: {"validate.disabled": Constant_bool true} + Field options: [{ + "(validate.rules)": {"double": {"gte": -180, + "lte": 180}} + }] + Options: [] *) (* ----------------------------------------------------- *) (* Module Prefix: Option_processing - Variant: person_id + Variant: person_xyz Constructor: X Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_string Encoding Number: 6, Payload Kind: Pk_bytes + Options: [{ + "(validate.rules)": {"string": {"prefix": "foo"}} + }] Constructor: Y Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_int32 Encoding Number: 7, Payload Kind: Pk_varint (zigzag: false) - Options: {} + Options: [{ + "(validate.rules)": {"int32": {"gt": 0}} + }] + Constructor: Z + Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_float + + Encoding Number: 8, Payload Kind: Pk_bits32 + Options: [] + Options: [] *) (* @@ -108,21 +140,51 @@ and default_person Record: person - Field: id Rft_nolabel (Field Type: Ft_basic_type: Bt_int64, Encoding: 1, Payload Kind: Pk_varint (zigzag: false)) - Field options: {"validate.rules.uint64.gt": Constant_int 999} + Field options: [{ + "(validate.rules)": {"uint64": {"gt": 999}} + }] - Field: email Rft_nolabel (Field Type: Ft_basic_type: Bt_string, Encoding: 2, Payload Kind: Pk_bytes) - Field options: {"validate.rules.string.email": Constant_bool true} + Field options: [{ + "(validate.rules)": {"string": {"email": true}} + }] - Field: name Rft_nolabel (Field Type: Ft_basic_type: Bt_string, Encoding: 3, Payload Kind: Pk_bytes) - Field options: {"validate.rules.string": {"pattern": Constant_string "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", "max_bytes": Constant_int 256}} + Field options: [{ + "(validate.rules)": {"string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256}} + }] - Field: home Rft_optional (Field Type: Ft_user_defined_type: person_location, Encoding: 4, Payload Kind: Pk_bytes, Default Value: None) - Field options: {"validate.rules.message.required": Constant_bool true} + Field options: [{ + "(validate.rules)": {"message": {"required": true}} + }] - Field: picture Rft_nolabel (Field Type: Ft_basic_type: Bt_bytes, Encoding: 5, Payload Kind: Pk_bytes) - Field options: {"validate.rules.bytes": {"not_in": [Constant_string "foo", Constant_string "bar", Constant_string "baz"]}} - - Field: id - Rft_variant: person_id - Field options: {"validate.required": Constant_bool true} - Options: {"validate.disabled": Constant_bool true} + Field options: [{ + "(validate.rules)": {"bytes": {"not_in": ["foo", + "bar", + "baz"]}} + }] + - Field: xyz + Rft_variant: person_xyz + Field options: [{ + "(validate.required)": true + }] + Options: [{ + "(validate.disabled)": true + }] +*) + +(* ----------------------------------------------------- *) +(* + Module Prefix: Option_processing + Empty Record: destructured_options + Options: [{ + "(google.api.http)": {"custom": {"path": "/foo/bar/baz/{id}", + "kind": "FETCH"}, + "additional_bindings": [{"post": "/foo/bar/baz/", + "body": "*"}, + {"get": "/foo/bar/baz/{id}"}]} + }] *) diff --git a/src/tests/expectation/option_processing.proto b/src/tests/expectation/option_processing.proto index 15f96445..c7af9c19 100644 --- a/src/tests/expectation/option_processing.proto +++ b/src/tests/expectation/option_processing.proto @@ -32,10 +32,23 @@ message Person { bytes picture = 5 [(validate.rules).bytes = {not_in: ["foo", "bar", "baz"]}]; - oneof id { + oneof xyz { option (validate.required) = true; - string x = 6; - int32 y = 7; + string x = 6 [(validate.rules).string.prefix = "foo"]; + int32 y = 7 [(validate.rules).int32.gt = 0]; + float z = 8; } } + +message DestructuredOptions { + option (google.api.http).custom.kind = "FETCH"; + option (google.api.http).custom.path = "/foo/bar/baz/{id}"; + option (google.api.http).additional_bindings = { + get: "/foo/bar/baz/{id}" + }; + option (google.api.http).additional_bindings = { + post: "/foo/bar/baz/", + body: "*" + }; +} diff --git a/src/tests/expectation/test_decode_pb_options.expected b/src/tests/expectation/test_decode_pb_options.expected new file mode 100644 index 00000000..47bbcfd3 --- /dev/null +++ b/src/tests/expectation/test_decode_pb_options.expected @@ -0,0 +1,87 @@ +====================== ====================== +[{ + "(validate.rules)": {"uint64": {"gt": 999}} + }] +===================== ====================== +======================= ======================= +{ message = None; + type_ = Some(Uint64({ const = None; lt = None; lte = None; gt = Some(999); gte = None; in_ = []; not_in = []; ignore_empty = None; })); +} +====================== ======================= + + +====================== ====================== +[{ + "(validate.rules)": {"string": {"email": true}} + }] +===================== ====================== +======================= ======================= +{ message = None; + type_ = + Some( + String( + { const = None; + len = None; + min_len = None; + max_len = None; + len_bytes = None; + min_bytes = None; + max_bytes = None; + pattern = None; + prefix = None; + suffix = None; + contains = None; + not_contains = None; + in_ = []; + not_in = []; + well_known = Some(Email(true)); + strict = Some(true); + ignore_empty = None; + })); +} +====================== ======================= + + +====================== ====================== +[{ + "(validate.rules)": {"string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256}} + }] +===================== ====================== +======================= ======================= +{ message = None; + type_ = + Some( + String( + { const = None; + len = None; + min_len = None; + max_len = None; + len_bytes = None; + min_bytes = None; + max_bytes = Some(256); + pattern = Some("^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$"); + prefix = None; + suffix = None; + contains = None; + not_contains = None; + in_ = []; + not_in = []; + well_known = None; + strict = Some(true); + ignore_empty = None; + })); +} +====================== ======================= + + +====================== ====================== +[{ + "(validate.rules)": {"message": {"required": true}} + }] +===================== ====================== +======================= ======================= +{ message = Some({ skip = None; required = Some(true); }); type_ = None; } +====================== ======================= + + diff --git a/src/tests/expectation/test_decode_pb_options.ml b/src/tests/expectation/test_decode_pb_options.ml new file mode 100644 index 00000000..e36402b6 --- /dev/null +++ b/src/tests/expectation/test_decode_pb_options.ml @@ -0,0 +1,74 @@ +module E = Pb_exception +module Pt = Pb_parsing_parse_tree + +let process_field_options ppf field = + let options = + field.Pt.field_options |> Pb_typing_validation.compile_options + in + if options <> Pb_option.empty then ( + let parsed = + Pb_option.get_ext options "validate.rules" + |> Option.map Validate.decode_pb_options_field_rules + in + Format.fprintf ppf + "====================== \ + ======================@.%a@.===================== \ + ======================@.======================= \ + =======================@.%a@.====================== \ + =======================@.@.@." + Pb_option.pp_set options + (Format.pp_print_option Validate.pp_field_rules) + parsed; + () + ) + +let run proto = + let protos = + Pb_parsing.parse_file + (fun f -> + match f with + | "test.proto" -> f, proto + | _ -> f, "") + "test.proto" + in + let ppf = Format.std_formatter in + Format.set_margin 150; + protos + |> List.iter (fun proto -> + proto.Pt.messages + |> List.iter (fun message -> + message.Pt.message_body + |> List.iter (function + | Pt.Message_field field -> process_field_options ppf field + | _ -> ()))) + +let test_cases = + [ + {| + syntax = "proto3"; + + package examplepb; + + import "validate/validate.proto"; + + message Person { + uint64 id = 1 [(validate.rules).uint64.gt = 999]; + + string email = 2 [(validate.rules).string.email = true]; + + string name = 3 [(validate.rules).string = { + pattern: "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + max_bytes: 256, + }]; + + Location home = 4 [(validate.rules).message.required = true]; + + message Location { + double lat = 1 [(validate.rules).double = {gte: -90, lte: 90}]; + double lng = 2 [(validate.rules).double = {gte: -180, lte: 180}]; + } + } + |}; + ] + +let () = List.iter run test_cases diff --git a/src/tests/expectation/test_option_compilation.expected b/src/tests/expectation/test_option_compilation.expected new file mode 100644 index 00000000..ce8305cb --- /dev/null +++ b/src/tests/expectation/test_option_compilation.expected @@ -0,0 +1,78 @@ +====================== ====================== + + message M { + option packed = true; + } + +===================== ====================== +======================= ======================= +-- message options -- +RAW: +[{ + "packed": true + }] + +COMPILED: +[{ + "packed": true + }] +====================== ======================= + + +====================== ====================== + + message PackedField { + repeated float inner = 1 [packed=true]; + } + +===================== ====================== +======================= ======================= +-- field options -- +RAW: +[{ + "packed": true + }] + +COMPILED: +[{ + "packed": true + }] + +-- message options -- +RAW: +[] + +COMPILED: +[] +====================== ======================= + + +====================== ====================== + + syntax = "proto3"; + message PackedField { + repeated float inner = 1 [packed=true]; + } + +===================== ====================== +======================= ======================= +-- field options -- +RAW: +[{ + "packed": true + }] + +COMPILED: +[{ + "packed": true + }] + +-- message options -- +RAW: +[] + +COMPILED: +[] +====================== ======================= + + diff --git a/src/tests/expectation/test_option_compilation.ml b/src/tests/expectation/test_option_compilation.ml new file mode 100644 index 00000000..8ea69c3a --- /dev/null +++ b/src/tests/expectation/test_option_compilation.ml @@ -0,0 +1,74 @@ +module E = Pb_exception +module Pt = Pb_parsing_parse_tree + +let pp_compiled ppf options = + Format.fprintf ppf "RAW:@.%a@.@.COMPILED:@.%a" Pb_raw_option.pp_set options + Pb_option.pp_set + (Pb_typing_validation.compile_options options) + +let run proto = + let maybe_protos = + try + Pb_parsing.parse_file + (fun f -> + match f with + | "test.proto" -> f, proto + | _ -> f, "") + "test.proto" + |> Result.ok + with e -> Error e + in + let pp_maybe_protos ppf = function + | Ok [ (proto : Pt.proto) ] -> + (match proto.messages with + | [ message ] -> + let raw_options = + message.message_body + |> List.filter_map (function + | Pt.Message_option opt -> Some opt + | Pt.Message_field field -> + Format.fprintf ppf "-- field options --@.%a@.@." pp_compiled + field.field_options; + None + | _ -> None) + |> List.fold_left + (fun oneof_options (name, value) -> + Pb_raw_option.add oneof_options name value) + Pb_raw_option.empty + in + Format.fprintf ppf "-- message options --@.%a" pp_compiled raw_options + | _ -> Format.fprintf ppf "[!] Only one message is expected") + | Ok _ -> Format.fprintf ppf "[!] Only one proto is expected" + | Error exn -> Format.fprintf ppf "[!] EXN: %s" (Printexc.to_string exn) + in + let ppf = Format.std_formatter in + Format.set_margin 149; + Format.fprintf ppf + "====================== \ + ======================@.%a@.===================== \ + ======================@.======================= \ + =======================@.%a@.====================== =======================@.@.@." + Format.pp_print_string proto pp_maybe_protos maybe_protos + +let test_cases = + [ + {| + message M { + option packed = true; + } + |}; + {| + message PackedField { + repeated float inner = 1 [packed=true]; + } + |}; + {| + syntax = "proto3"; + message PackedField { + repeated float inner = 1 [packed=true]; + } + |}; + ] + +let () = List.iter run test_cases diff --git a/src/tests/expectation/tests.expected b/src/tests/expectation/test_option_parsing.expected similarity index 97% rename from src/tests/expectation/tests.expected rename to src/tests/expectation/test_option_parsing.expected index a80793fd..47c8f61b 100644 --- a/src/tests/expectation/tests.expected +++ b/src/tests/expectation/test_option_parsing.expected @@ -273,7 +273,7 @@ id = 7; message_name = "OptionMessage"; message_body = [{ - "my_option": true + "(my_option)": true }; { field_name = "id"; @@ -281,7 +281,7 @@ field_label = `Nolabel; field_type = Int32; field_options = [{ - "my_field_option": "value" + "(my_field_option)": "value" }]; }; { @@ -713,7 +713,7 @@ field_label = `Nolabel; field_type = Uint64; field_options = [{ - "validate.rules.uint64.gt": 999 + "(validate.rules).uint64.gt": 999 }]; }; { @@ -722,7 +722,7 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "validate.rules.string.email": true + "(validate.rules).string.email": true }]; }; { @@ -731,7 +731,7 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "validate.rules.string": { + "(validate.rules).string": { "pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", "max_bytes": 256} }]; @@ -746,7 +746,7 @@ from_root: false }; field_options = [{ - "validate.rules.message.required": true + "(validate.rules).message.required": true }]; }; { @@ -759,7 +759,7 @@ field_type = Double; field_options = [ { - "validate.rules.double": { + "(validate.rules).double": { "gte": -90, "lte": 90} }]; @@ -771,7 +771,7 @@ field_type = Double; field_options = [ { - "validate.rules.double": { + "(validate.rules).double": { "gte": -180, "lte": 180} }]; @@ -783,7 +783,7 @@ message_name = "Other"; message_body = [{oneof_name = "id"; oneof_body = [{ - "validate.required": true + "(validate.required)": true }; { field_name = "x"; @@ -792,7 +792,7 @@ field_type = String; field_options = [ { - "validate.rules.string.len": 5 + "(validate.rules).string.len": 5 }]; }; { @@ -822,7 +822,7 @@ field_label = `Nolabel; field_type = Uint32; field_options = [{ - "validate.rules.uint32": { + "(validate.rules).uint32": { "in": [1, 2, 3]} @@ -834,7 +834,7 @@ field_label = `Nolabel; field_type = Float; field_options = [{ - "validate.rules.float": { + "(validate.rules).float": { "not_in": [0, 0.990000]} }]; @@ -927,7 +927,7 @@ { service_name = "ShelfServiceV2"; service_body = [{ - "some.config": "service_shelf" + "(some.config)": "service_shelf" }; { rpc_name = "ListShelves"; @@ -996,10 +996,10 @@ { rpc_name = "GetShelf"; rpc_options = [{ - "const.config": "rpc_shelf" + "(const.config)": "rpc_shelf" }, { - "google.api.http": { + "(google.api.http)": { "post": "/v1/shelves/{shelf}", "body": "body"} }]; diff --git a/src/tests/expectation/tests.ml b/src/tests/expectation/test_option_parsing.ml similarity index 99% rename from src/tests/expectation/tests.ml rename to src/tests/expectation/test_option_parsing.ml index f0cec1ce..d2875fd6 100644 --- a/src/tests/expectation/tests.ml +++ b/src/tests/expectation/test_option_parsing.ml @@ -225,7 +225,7 @@ let test_cases = rpc GetShelfWithSemicolon (GetShelfRequest) returns (GetShelfResponse) {}; } - |} + |}; ] let () = List.iter run test_cases diff --git a/src/tests/expectation/validate.ml.expected b/src/tests/expectation/validate.ml.expected new file mode 100644 index 00000000..70e3fb0d --- /dev/null +++ b/src/tests/expectation/validate.ml.expected @@ -0,0 +1,2480 @@ +[@@@ocaml.warning "-27-30-39-44"] + +type message_options = { + disabled : bool option; + ignored : bool option; +} + +type oneof_options = { + required : bool option; +} + +type message_rules = { + skip : bool option; + required : bool option; +} + +type float_rules = { + const : float option; + lt : float option; + lte : float option; + gt : float option; + gte : float option; + in_ : float list; + not_in : float list; + ignore_empty : bool option; +} + +type double_rules = { + const : float option; + lt : float option; + lte : float option; + gt : float option; + gte : float option; + in_ : float list; + not_in : float list; + ignore_empty : bool option; +} + +type int32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type int64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type uint32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type uint64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type sint32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type sint64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type fixed32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type fixed64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type sfixed32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type sfixed64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type bool_rules = { + const : bool option; +} + +type known_regex = + | Unknown + | Http_header_name + | Http_header_value + +type string_rules_well_known = + | Email of bool + | Hostname of bool + | Ip of bool + | Ipv4 of bool + | Ipv6 of bool + | Uri of bool + | Uri_ref of bool + | Address of bool + | Uuid of bool + | Well_known_regex of known_regex + +and string_rules = { + const : string option; + len : int64 option; + min_len : int64 option; + max_len : int64 option; + len_bytes : int64 option; + min_bytes : int64 option; + max_bytes : int64 option; + pattern : string option; + prefix : string option; + suffix : string option; + contains : string option; + not_contains : string option; + in_ : string list; + not_in : string list; + well_known : string_rules_well_known option; + strict : bool option; + ignore_empty : bool option; +} + +type bytes_rules_well_known = + | Ip of bool + | Ipv4 of bool + | Ipv6 of bool + +and bytes_rules = { + const : bytes option; + len : int64 option; + min_len : int64 option; + max_len : int64 option; + pattern : string option; + prefix : bytes option; + suffix : bytes option; + contains : bytes option; + in_ : bytes list; + not_in : bytes list; + well_known : bytes_rules_well_known option; + ignore_empty : bool option; +} + +type enum_rules = { + const : int32 option; + defined_only : bool option; + in_ : int32 list; + not_in : int32 list; +} + +type any_rules = { + required : bool option; + in_ : string list; + not_in : string list; +} + +type field_rules_type = + | Float of float_rules + | Double of double_rules + | Int32 of int32_rules + | Int64 of int64_rules + | Uint32 of uint32_rules + | Uint64 of uint64_rules + | Sint32 of sint32_rules + | Sint64 of sint64_rules + | Fixed32 of fixed32_rules + | Fixed64 of fixed64_rules + | Sfixed32 of sfixed32_rules + | Sfixed64 of sfixed64_rules + | Bool of bool_rules + | String of string_rules + | Bytes of bytes_rules + | Enum of enum_rules + | Repeated of repeated_rules + | Map of map_rules + | Any of any_rules + +and field_rules = { + message : message_rules option; + type_ : field_rules_type option; +} + +and repeated_rules = { + min_items : int64 option; + max_items : int64 option; + unique : bool option; + items : field_rules option; + ignore_empty : bool option; +} + +and map_rules = { + min_pairs : int64 option; + max_pairs : int64 option; + no_sparse : bool option; + keys : field_rules option; + values : field_rules option; + ignore_empty : bool option; +} + +type field_options = { + rules : field_rules option; +} + +let rec default_message_options + ?disabled:((disabled:bool option) = None) + ?ignored:((ignored:bool option) = None) + () : message_options = { + disabled; + ignored; +} + +let rec default_oneof_options + ?required:((required:bool option) = None) + () : oneof_options = { + required; +} + +let rec default_message_rules + ?skip:((skip:bool option) = None) + ?required:((required:bool option) = None) + () : message_rules = { + skip; + required; +} + +let rec default_float_rules + ?const:((const:float option) = None) + ?lt:((lt:float option) = None) + ?lte:((lte:float option) = None) + ?gt:((gt:float option) = None) + ?gte:((gte:float option) = None) + ?in_:((in_:float list) = []) + ?not_in:((not_in:float list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : float_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_double_rules + ?const:((const:float option) = None) + ?lt:((lt:float option) = None) + ?lte:((lte:float option) = None) + ?gt:((gt:float option) = None) + ?gte:((gte:float option) = None) + ?in_:((in_:float list) = []) + ?not_in:((not_in:float list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : double_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_int32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : int32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_int64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : int64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_uint32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : uint32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_uint64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : uint64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sint32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sint32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sint64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sint64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_fixed32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : fixed32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_fixed64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : fixed64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sfixed32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sfixed32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sfixed64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sfixed64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_bool_rules + ?const:((const:bool option) = None) + () : bool_rules = { + const; +} + +let rec default_known_regex () = (Unknown:known_regex) + +let rec default_string_rules_well_known () : string_rules_well_known = Email (false) + +and default_string_rules + ?const:((const:string option) = None) + ?len:((len:int64 option) = None) + ?min_len:((min_len:int64 option) = None) + ?max_len:((max_len:int64 option) = None) + ?len_bytes:((len_bytes:int64 option) = None) + ?min_bytes:((min_bytes:int64 option) = None) + ?max_bytes:((max_bytes:int64 option) = None) + ?pattern:((pattern:string option) = None) + ?prefix:((prefix:string option) = None) + ?suffix:((suffix:string option) = None) + ?contains:((contains:string option) = None) + ?not_contains:((not_contains:string option) = None) + ?in_:((in_:string list) = []) + ?not_in:((not_in:string list) = []) + ?well_known:((well_known:string_rules_well_known option) = None) + ?strict:((strict:bool option) = Some (true)) + ?ignore_empty:((ignore_empty:bool option) = None) + () : string_rules = { + const; + len; + min_len; + max_len; + len_bytes; + min_bytes; + max_bytes; + pattern; + prefix; + suffix; + contains; + not_contains; + in_; + not_in; + well_known; + strict; + ignore_empty; +} + +let rec default_bytes_rules_well_known () : bytes_rules_well_known = Ip (false) + +and default_bytes_rules + ?const:((const:bytes option) = None) + ?len:((len:int64 option) = None) + ?min_len:((min_len:int64 option) = None) + ?max_len:((max_len:int64 option) = None) + ?pattern:((pattern:string option) = None) + ?prefix:((prefix:bytes option) = None) + ?suffix:((suffix:bytes option) = None) + ?contains:((contains:bytes option) = None) + ?in_:((in_:bytes list) = []) + ?not_in:((not_in:bytes list) = []) + ?well_known:((well_known:bytes_rules_well_known option) = None) + ?ignore_empty:((ignore_empty:bool option) = None) + () : bytes_rules = { + const; + len; + min_len; + max_len; + pattern; + prefix; + suffix; + contains; + in_; + not_in; + well_known; + ignore_empty; +} + +let rec default_enum_rules + ?const:((const:int32 option) = None) + ?defined_only:((defined_only:bool option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + () : enum_rules = { + const; + defined_only; + in_; + not_in; +} + +let rec default_any_rules + ?required:((required:bool option) = None) + ?in_:((in_:string list) = []) + ?not_in:((not_in:string list) = []) + () : any_rules = { + required; + in_; + not_in; +} + +let rec default_field_rules_type () : field_rules_type = Float (default_float_rules ()) + +and default_field_rules + ?message:((message:message_rules option) = None) + ?type_:((type_:field_rules_type option) = None) + () : field_rules = { + message; + type_; +} + +and default_repeated_rules + ?min_items:((min_items:int64 option) = None) + ?max_items:((max_items:int64 option) = None) + ?unique:((unique:bool option) = None) + ?items:((items:field_rules option) = None) + ?ignore_empty:((ignore_empty:bool option) = None) + () : repeated_rules = { + min_items; + max_items; + unique; + items; + ignore_empty; +} + +and default_map_rules + ?min_pairs:((min_pairs:int64 option) = None) + ?max_pairs:((max_pairs:int64 option) = None) + ?no_sparse:((no_sparse:bool option) = None) + ?keys:((keys:field_rules option) = None) + ?values:((values:field_rules option) = None) + ?ignore_empty:((ignore_empty:bool option) = None) + () : map_rules = { + min_pairs; + max_pairs; + no_sparse; + keys; + values; + ignore_empty; +} + +let rec default_field_options + ?rules:((rules:field_rules option) = None) + () : field_options = { + rules; +} + +type message_options_mutable = { + mutable disabled : bool option; + mutable ignored : bool option; +} + +let default_message_options_mutable () : message_options_mutable = { + disabled = None; + ignored = None; +} + +type oneof_options_mutable = { + mutable required : bool option; +} + +let default_oneof_options_mutable () : oneof_options_mutable = { + required = None; +} + +type message_rules_mutable = { + mutable skip : bool option; + mutable required : bool option; +} + +let default_message_rules_mutable () : message_rules_mutable = { + skip = None; + required = None; +} + +type float_rules_mutable = { + mutable const : float option; + mutable lt : float option; + mutable lte : float option; + mutable gt : float option; + mutable gte : float option; + mutable in_ : float list; + mutable not_in : float list; + mutable ignore_empty : bool option; +} + +let default_float_rules_mutable () : float_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type double_rules_mutable = { + mutable const : float option; + mutable lt : float option; + mutable lte : float option; + mutable gt : float option; + mutable gte : float option; + mutable in_ : float list; + mutable not_in : float list; + mutable ignore_empty : bool option; +} + +let default_double_rules_mutable () : double_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type int32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_int32_rules_mutable () : int32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type int64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_int64_rules_mutable () : int64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type uint32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_uint32_rules_mutable () : uint32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type uint64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_uint64_rules_mutable () : uint64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sint32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_sint32_rules_mutable () : sint32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sint64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_sint64_rules_mutable () : sint64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type fixed32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_fixed32_rules_mutable () : fixed32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type fixed64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_fixed64_rules_mutable () : fixed64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sfixed32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_sfixed32_rules_mutable () : sfixed32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sfixed64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_sfixed64_rules_mutable () : sfixed64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type bool_rules_mutable = { + mutable const : bool option; +} + +let default_bool_rules_mutable () : bool_rules_mutable = { + const = None; +} + +type string_rules_mutable = { + mutable const : string option; + mutable len : int64 option; + mutable min_len : int64 option; + mutable max_len : int64 option; + mutable len_bytes : int64 option; + mutable min_bytes : int64 option; + mutable max_bytes : int64 option; + mutable pattern : string option; + mutable prefix : string option; + mutable suffix : string option; + mutable contains : string option; + mutable not_contains : string option; + mutable in_ : string list; + mutable not_in : string list; + mutable well_known : string_rules_well_known option; + mutable strict : bool option; + mutable ignore_empty : bool option; +} + +let default_string_rules_mutable () : string_rules_mutable = { + const = None; + len = None; + min_len = None; + max_len = None; + len_bytes = None; + min_bytes = None; + max_bytes = None; + pattern = None; + prefix = None; + suffix = None; + contains = None; + not_contains = None; + in_ = []; + not_in = []; + well_known = None; + strict = Some (true); + ignore_empty = None; +} + +type bytes_rules_mutable = { + mutable const : bytes option; + mutable len : int64 option; + mutable min_len : int64 option; + mutable max_len : int64 option; + mutable pattern : string option; + mutable prefix : bytes option; + mutable suffix : bytes option; + mutable contains : bytes option; + mutable in_ : bytes list; + mutable not_in : bytes list; + mutable well_known : bytes_rules_well_known option; + mutable ignore_empty : bool option; +} + +let default_bytes_rules_mutable () : bytes_rules_mutable = { + const = None; + len = None; + min_len = None; + max_len = None; + pattern = None; + prefix = None; + suffix = None; + contains = None; + in_ = []; + not_in = []; + well_known = None; + ignore_empty = None; +} + +type enum_rules_mutable = { + mutable const : int32 option; + mutable defined_only : bool option; + mutable in_ : int32 list; + mutable not_in : int32 list; +} + +let default_enum_rules_mutable () : enum_rules_mutable = { + const = None; + defined_only = None; + in_ = []; + not_in = []; +} + +type any_rules_mutable = { + mutable required : bool option; + mutable in_ : string list; + mutable not_in : string list; +} + +let default_any_rules_mutable () : any_rules_mutable = { + required = None; + in_ = []; + not_in = []; +} + +type field_rules_mutable = { + mutable message : message_rules option; + mutable type_ : field_rules_type option; +} + +let default_field_rules_mutable () : field_rules_mutable = { + message = None; + type_ = None; +} + +type repeated_rules_mutable = { + mutable min_items : int64 option; + mutable max_items : int64 option; + mutable unique : bool option; + mutable items : field_rules option; + mutable ignore_empty : bool option; +} + +let default_repeated_rules_mutable () : repeated_rules_mutable = { + min_items = None; + max_items = None; + unique = None; + items = None; + ignore_empty = None; +} + +type map_rules_mutable = { + mutable min_pairs : int64 option; + mutable max_pairs : int64 option; + mutable no_sparse : bool option; + mutable keys : field_rules option; + mutable values : field_rules option; + mutable ignore_empty : bool option; +} + +let default_map_rules_mutable () : map_rules_mutable = { + min_pairs = None; + max_pairs = None; + no_sparse = None; + keys = None; + values = None; + ignore_empty = None; +} + +type field_options_mutable = { + mutable rules : field_rules option; +} + +let default_field_options_mutable () : field_options_mutable = { + rules = None; +} + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Pb_option.set Decoding} *) + +let rec decode_pb_options_message_options d = + let v = default_message_options_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("disabled", pb_options_value) -> + v.disabled <- Some (Pbrt_pb_options.bool pb_options_value "message_options" "disabled") + | ("ignored", pb_options_value) -> + v.ignored <- Some (Pbrt_pb_options.bool pb_options_value "message_options" "ignored") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + disabled = v.disabled; + ignored = v.ignored; + } : message_options) + +let rec decode_pb_options_oneof_options d = + let v = default_oneof_options_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("required", pb_options_value) -> + v.required <- Some (Pbrt_pb_options.bool pb_options_value "oneof_options" "required") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + required = v.required; + } : oneof_options) + +let rec decode_pb_options_message_rules d = + let v = default_message_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("skip", pb_options_value) -> + v.skip <- Some (Pbrt_pb_options.bool pb_options_value "message_rules" "skip") + | ("required", pb_options_value) -> + v.required <- Some (Pbrt_pb_options.bool pb_options_value "message_rules" "required") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + skip = v.skip; + required = v.required; + } : message_rules) + +let rec decode_pb_options_float_rules d = + let v = default_float_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "float_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "float_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "float_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : float_rules) + +let rec decode_pb_options_double_rules d = + let v = default_double_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "double_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "double_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "double_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : double_rules) + +let rec decode_pb_options_int32_rules d = + let v = default_int32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "int32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "int32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "int32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : int32_rules) + +let rec decode_pb_options_int64_rules d = + let v = default_int64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "int64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "int64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "int64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : int64_rules) + +let rec decode_pb_options_uint32_rules d = + let v = default_uint32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "uint32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "uint32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "uint32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : uint32_rules) + +let rec decode_pb_options_uint64_rules d = + let v = default_uint64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "uint64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "uint64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "uint64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : uint64_rules) + +let rec decode_pb_options_sint32_rules d = + let v = default_sint32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sint32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sint32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sint32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sint32_rules) + +let rec decode_pb_options_sint64_rules d = + let v = default_sint64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sint64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sint64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sint64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sint64_rules) + +let rec decode_pb_options_fixed32_rules d = + let v = default_fixed32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "fixed32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : fixed32_rules) + +let rec decode_pb_options_fixed64_rules d = + let v = default_fixed64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "fixed64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : fixed64_rules) + +let rec decode_pb_options_sfixed32_rules d = + let v = default_sfixed32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sfixed32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sfixed32_rules) + +let rec decode_pb_options_sfixed64_rules d = + let v = default_sfixed64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sfixed64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sfixed64_rules) + +let rec decode_pb_options_bool_rules d = + let v = default_bool_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.bool pb_options_value "bool_rules" "const") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + } : bool_rules) + +let rec decode_pb_options_known_regex pb_options = + match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Scalar_value (Constant_literal "UNKNOWN") -> (Unknown : known_regex) + | Ocaml_protoc_compiler_lib.Pb_option.Scalar_value (Constant_literal "HTTP_HEADER_NAME") -> (Http_header_name : known_regex) + | Ocaml_protoc_compiler_lib.Pb_option.Scalar_value (Constant_literal "HTTP_HEADER_VALUE") -> (Http_header_value : known_regex) + | _ -> Pbrt_pb_options.E.malformed_variant "known_regex" + +let rec decode_pb_options_string_rules_well_known pb_options = + let assoc = match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_pb_options.E.malformed_variant "string_rules_well_known" + | ("email", pb_options_value)::_ -> + (Email (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Email") : string_rules_well_known) + | ("hostname", pb_options_value)::_ -> + (Hostname (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Hostname") : string_rules_well_known) + | ("ip", pb_options_value)::_ -> + (Ip (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Ip") : string_rules_well_known) + | ("ipv4", pb_options_value)::_ -> + (Ipv4 (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Ipv4") : string_rules_well_known) + | ("ipv6", pb_options_value)::_ -> + (Ipv6 (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Ipv6") : string_rules_well_known) + | ("uri", pb_options_value)::_ -> + (Uri (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Uri") : string_rules_well_known) + | ("uriRef", pb_options_value)::_ -> + (Uri_ref (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Uri_ref") : string_rules_well_known) + | ("address", pb_options_value)::_ -> + (Address (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Address") : string_rules_well_known) + | ("uuid", pb_options_value)::_ -> + (Uuid (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Uuid") : string_rules_well_known) + | ("wellKnownRegex", pb_options_value)::_ -> + (Well_known_regex ((decode_pb_options_known_regex pb_options_value)) : string_rules_well_known) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_pb_options_string_rules d = + let v = default_string_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "const") + | ("len", pb_options_value) -> + v.len <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "len") + | ("min_len", pb_options_value) -> + v.min_len <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "min_len") + | ("max_len", pb_options_value) -> + v.max_len <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "max_len") + | ("len_bytes", pb_options_value) -> + v.len_bytes <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "len_bytes") + | ("min_bytes", pb_options_value) -> + v.min_bytes <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "min_bytes") + | ("max_bytes", pb_options_value) -> + v.max_bytes <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "max_bytes") + | ("pattern", pb_options_value) -> + v.pattern <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "pattern") + | ("prefix", pb_options_value) -> + v.prefix <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "prefix") + | ("suffix", pb_options_value) -> + v.suffix <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "suffix") + | ("contains", pb_options_value) -> + v.contains <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "contains") + | ("not_contains", pb_options_value) -> + v.not_contains <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "not_contains") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "string_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "string_rules" "not_in" + ) l; + end + | ("email", pb_options_value) -> + v.well_known <- Some (Email (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("hostname", pb_options_value) -> + v.well_known <- Some (Hostname (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("ip", pb_options_value) -> + v.well_known <- Some (Ip (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("ipv4", pb_options_value) -> + v.well_known <- Some (Ipv4 (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("ipv6", pb_options_value) -> + v.well_known <- Some (Ipv6 (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("uri", pb_options_value) -> + v.well_known <- Some (Uri (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("uriRef", pb_options_value) -> + v.well_known <- Some (Uri_ref (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("address", pb_options_value) -> + v.well_known <- Some (Address (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("uuid", pb_options_value) -> + v.well_known <- Some (Uuid (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("wellKnownRegex", pb_options_value) -> + v.well_known <- Some (Well_known_regex ((decode_pb_options_known_regex pb_options_value))) + | ("strict", pb_options_value) -> + v.strict <- Some (Pbrt_pb_options.bool pb_options_value "string_rules" "strict") + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "string_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + len = v.len; + min_len = v.min_len; + max_len = v.max_len; + len_bytes = v.len_bytes; + min_bytes = v.min_bytes; + max_bytes = v.max_bytes; + pattern = v.pattern; + prefix = v.prefix; + suffix = v.suffix; + contains = v.contains; + not_contains = v.not_contains; + in_ = v.in_; + not_in = v.not_in; + well_known = v.well_known; + strict = v.strict; + ignore_empty = v.ignore_empty; + } : string_rules) + +let rec decode_pb_options_bytes_rules_well_known pb_options = + let assoc = match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_pb_options.E.malformed_variant "bytes_rules_well_known" + | ("ip", pb_options_value)::_ -> + (Ip (Pbrt_pb_options.bool pb_options_value "bytes_rules_well_known" "Ip") : bytes_rules_well_known) + | ("ipv4", pb_options_value)::_ -> + (Ipv4 (Pbrt_pb_options.bool pb_options_value "bytes_rules_well_known" "Ipv4") : bytes_rules_well_known) + | ("ipv6", pb_options_value)::_ -> + (Ipv6 (Pbrt_pb_options.bool pb_options_value "bytes_rules_well_known" "Ipv6") : bytes_rules_well_known) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_pb_options_bytes_rules d = + let v = default_bytes_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "const") + | ("len", pb_options_value) -> + v.len <- Some (Pbrt_pb_options.int64 pb_options_value "bytes_rules" "len") + | ("min_len", pb_options_value) -> + v.min_len <- Some (Pbrt_pb_options.int64 pb_options_value "bytes_rules" "min_len") + | ("max_len", pb_options_value) -> + v.max_len <- Some (Pbrt_pb_options.int64 pb_options_value "bytes_rules" "max_len") + | ("pattern", pb_options_value) -> + v.pattern <- Some (Pbrt_pb_options.string pb_options_value "bytes_rules" "pattern") + | ("prefix", pb_options_value) -> + v.prefix <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "prefix") + | ("suffix", pb_options_value) -> + v.suffix <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "suffix") + | ("contains", pb_options_value) -> + v.contains <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "contains") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.bytes pb_options_value "bytes_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.bytes pb_options_value "bytes_rules" "not_in" + ) l; + end + | ("ip", pb_options_value) -> + v.well_known <- Some (Ip (Pbrt_pb_options.bool pb_options_value "bytes_rules" "well_known")) + | ("ipv4", pb_options_value) -> + v.well_known <- Some (Ipv4 (Pbrt_pb_options.bool pb_options_value "bytes_rules" "well_known")) + | ("ipv6", pb_options_value) -> + v.well_known <- Some (Ipv6 (Pbrt_pb_options.bool pb_options_value "bytes_rules" "well_known")) + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "bytes_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + len = v.len; + min_len = v.min_len; + max_len = v.max_len; + pattern = v.pattern; + prefix = v.prefix; + suffix = v.suffix; + contains = v.contains; + in_ = v.in_; + not_in = v.not_in; + well_known = v.well_known; + ignore_empty = v.ignore_empty; + } : bytes_rules) + +let rec decode_pb_options_enum_rules d = + let v = default_enum_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "enum_rules" "const") + | ("defined_only", pb_options_value) -> + v.defined_only <- Some (Pbrt_pb_options.bool pb_options_value "enum_rules" "defined_only") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "enum_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "enum_rules" "not_in" + ) l; + end + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + defined_only = v.defined_only; + in_ = v.in_; + not_in = v.not_in; + } : enum_rules) + +let rec decode_pb_options_any_rules d = + let v = default_any_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("required", pb_options_value) -> + v.required <- Some (Pbrt_pb_options.bool pb_options_value "any_rules" "required") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "any_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "any_rules" "not_in" + ) l; + end + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + required = v.required; + in_ = v.in_; + not_in = v.not_in; + } : any_rules) + +let rec decode_pb_options_field_rules_type pb_options = + let assoc = match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_pb_options.E.malformed_variant "field_rules_type" + | ("float", pb_options_value)::_ -> + (Float ((decode_pb_options_float_rules pb_options_value)) : field_rules_type) + | ("double", pb_options_value)::_ -> + (Double ((decode_pb_options_double_rules pb_options_value)) : field_rules_type) + | ("int32", pb_options_value)::_ -> + (Int32 ((decode_pb_options_int32_rules pb_options_value)) : field_rules_type) + | ("int64", pb_options_value)::_ -> + (Int64 ((decode_pb_options_int64_rules pb_options_value)) : field_rules_type) + | ("uint32", pb_options_value)::_ -> + (Uint32 ((decode_pb_options_uint32_rules pb_options_value)) : field_rules_type) + | ("uint64", pb_options_value)::_ -> + (Uint64 ((decode_pb_options_uint64_rules pb_options_value)) : field_rules_type) + | ("sint32", pb_options_value)::_ -> + (Sint32 ((decode_pb_options_sint32_rules pb_options_value)) : field_rules_type) + | ("sint64", pb_options_value)::_ -> + (Sint64 ((decode_pb_options_sint64_rules pb_options_value)) : field_rules_type) + | ("fixed32", pb_options_value)::_ -> + (Fixed32 ((decode_pb_options_fixed32_rules pb_options_value)) : field_rules_type) + | ("fixed64", pb_options_value)::_ -> + (Fixed64 ((decode_pb_options_fixed64_rules pb_options_value)) : field_rules_type) + | ("sfixed32", pb_options_value)::_ -> + (Sfixed32 ((decode_pb_options_sfixed32_rules pb_options_value)) : field_rules_type) + | ("sfixed64", pb_options_value)::_ -> + (Sfixed64 ((decode_pb_options_sfixed64_rules pb_options_value)) : field_rules_type) + | ("bool", pb_options_value)::_ -> + (Bool ((decode_pb_options_bool_rules pb_options_value)) : field_rules_type) + | ("string", pb_options_value)::_ -> + (String ((decode_pb_options_string_rules pb_options_value)) : field_rules_type) + | ("bytes", pb_options_value)::_ -> + (Bytes ((decode_pb_options_bytes_rules pb_options_value)) : field_rules_type) + | ("enum", pb_options_value)::_ -> + (Enum ((decode_pb_options_enum_rules pb_options_value)) : field_rules_type) + | ("repeated", pb_options_value)::_ -> + (Repeated ((decode_pb_options_repeated_rules pb_options_value)) : field_rules_type) + | ("map", pb_options_value)::_ -> + (Map ((decode_pb_options_map_rules pb_options_value)) : field_rules_type) + | ("any", pb_options_value)::_ -> + (Any ((decode_pb_options_any_rules pb_options_value)) : field_rules_type) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_pb_options_field_rules d = + let v = default_field_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("message", pb_options_value) -> + v.message <- Some ((decode_pb_options_message_rules pb_options_value)) + | ("float", pb_options_value) -> + v.type_ <- Some (Float ((decode_pb_options_float_rules pb_options_value))) + | ("double", pb_options_value) -> + v.type_ <- Some (Double ((decode_pb_options_double_rules pb_options_value))) + | ("int32", pb_options_value) -> + v.type_ <- Some (Int32 ((decode_pb_options_int32_rules pb_options_value))) + | ("int64", pb_options_value) -> + v.type_ <- Some (Int64 ((decode_pb_options_int64_rules pb_options_value))) + | ("uint32", pb_options_value) -> + v.type_ <- Some (Uint32 ((decode_pb_options_uint32_rules pb_options_value))) + | ("uint64", pb_options_value) -> + v.type_ <- Some (Uint64 ((decode_pb_options_uint64_rules pb_options_value))) + | ("sint32", pb_options_value) -> + v.type_ <- Some (Sint32 ((decode_pb_options_sint32_rules pb_options_value))) + | ("sint64", pb_options_value) -> + v.type_ <- Some (Sint64 ((decode_pb_options_sint64_rules pb_options_value))) + | ("fixed32", pb_options_value) -> + v.type_ <- Some (Fixed32 ((decode_pb_options_fixed32_rules pb_options_value))) + | ("fixed64", pb_options_value) -> + v.type_ <- Some (Fixed64 ((decode_pb_options_fixed64_rules pb_options_value))) + | ("sfixed32", pb_options_value) -> + v.type_ <- Some (Sfixed32 ((decode_pb_options_sfixed32_rules pb_options_value))) + | ("sfixed64", pb_options_value) -> + v.type_ <- Some (Sfixed64 ((decode_pb_options_sfixed64_rules pb_options_value))) + | ("bool", pb_options_value) -> + v.type_ <- Some (Bool ((decode_pb_options_bool_rules pb_options_value))) + | ("string", pb_options_value) -> + v.type_ <- Some (String ((decode_pb_options_string_rules pb_options_value))) + | ("bytes", pb_options_value) -> + v.type_ <- Some (Bytes ((decode_pb_options_bytes_rules pb_options_value))) + | ("enum", pb_options_value) -> + v.type_ <- Some (Enum ((decode_pb_options_enum_rules pb_options_value))) + | ("repeated", pb_options_value) -> + v.type_ <- Some (Repeated ((decode_pb_options_repeated_rules pb_options_value))) + | ("map", pb_options_value) -> + v.type_ <- Some (Map ((decode_pb_options_map_rules pb_options_value))) + | ("any", pb_options_value) -> + v.type_ <- Some (Any ((decode_pb_options_any_rules pb_options_value))) + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + message = v.message; + type_ = v.type_; + } : field_rules) + +and decode_pb_options_repeated_rules d = + let v = default_repeated_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("min_items", pb_options_value) -> + v.min_items <- Some (Pbrt_pb_options.int64 pb_options_value "repeated_rules" "min_items") + | ("max_items", pb_options_value) -> + v.max_items <- Some (Pbrt_pb_options.int64 pb_options_value "repeated_rules" "max_items") + | ("unique", pb_options_value) -> + v.unique <- Some (Pbrt_pb_options.bool pb_options_value "repeated_rules" "unique") + | ("items", pb_options_value) -> + v.items <- Some ((decode_pb_options_field_rules pb_options_value)) + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "repeated_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + min_items = v.min_items; + max_items = v.max_items; + unique = v.unique; + items = v.items; + ignore_empty = v.ignore_empty; + } : repeated_rules) + +and decode_pb_options_map_rules d = + let v = default_map_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("min_pairs", pb_options_value) -> + v.min_pairs <- Some (Pbrt_pb_options.int64 pb_options_value "map_rules" "min_pairs") + | ("max_pairs", pb_options_value) -> + v.max_pairs <- Some (Pbrt_pb_options.int64 pb_options_value "map_rules" "max_pairs") + | ("no_sparse", pb_options_value) -> + v.no_sparse <- Some (Pbrt_pb_options.bool pb_options_value "map_rules" "no_sparse") + | ("keys", pb_options_value) -> + v.keys <- Some ((decode_pb_options_field_rules pb_options_value)) + | ("values", pb_options_value) -> + v.values <- Some ((decode_pb_options_field_rules pb_options_value)) + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "map_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + min_pairs = v.min_pairs; + max_pairs = v.max_pairs; + no_sparse = v.no_sparse; + keys = v.keys; + values = v.values; + ignore_empty = v.ignore_empty; + } : map_rules) + +let rec decode_pb_options_field_options d = + let v = default_field_options_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("rules", pb_options_value) -> + v.rules <- Some ((decode_pb_options_field_rules pb_options_value)) + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + rules = v.rules; + } : field_options) + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Formatters} *) + +let rec pp_message_options fmt (v:message_options) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "disabled" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.disabled; + Pbrt.Pp.pp_record_field ~first:false "ignored" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignored; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_oneof_options fmt (v:oneof_options) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "required" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.required; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_message_rules fmt (v:message_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "skip" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.skip; + Pbrt.Pp.pp_record_field ~first:false "required" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.required; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_float_rules fmt (v:float_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_double_rules fmt (v:double_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_int32_rules fmt (v:int32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_int64_rules fmt (v:int64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_uint32_rules fmt (v:uint32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_uint64_rules fmt (v:uint64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sint32_rules fmt (v:sint32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sint64_rules fmt (v:sint64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_fixed32_rules fmt (v:fixed32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_fixed64_rules fmt (v:fixed64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sfixed32_rules fmt (v:sfixed32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sfixed64_rules fmt (v:sfixed64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_bool_rules fmt (v:bool_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.const; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_known_regex fmt (v:known_regex) = + match v with + | Unknown -> Format.fprintf fmt "Unknown" + | Http_header_name -> Format.fprintf fmt "Http_header_name" + | Http_header_value -> Format.fprintf fmt "Http_header_value" + +let rec pp_string_rules_well_known fmt (v:string_rules_well_known) = + match v with + | Email x -> Format.fprintf fmt "@[Email(@,%a)@]" Pbrt.Pp.pp_bool x + | Hostname x -> Format.fprintf fmt "@[Hostname(@,%a)@]" Pbrt.Pp.pp_bool x + | Ip x -> Format.fprintf fmt "@[Ip(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv4 x -> Format.fprintf fmt "@[Ipv4(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv6 x -> Format.fprintf fmt "@[Ipv6(@,%a)@]" Pbrt.Pp.pp_bool x + | Uri x -> Format.fprintf fmt "@[Uri(@,%a)@]" Pbrt.Pp.pp_bool x + | Uri_ref x -> Format.fprintf fmt "@[Uri_ref(@,%a)@]" Pbrt.Pp.pp_bool x + | Address x -> Format.fprintf fmt "@[Address(@,%a)@]" Pbrt.Pp.pp_bool x + | Uuid x -> Format.fprintf fmt "@[Uuid(@,%a)@]" Pbrt.Pp.pp_bool x + | Well_known_regex x -> Format.fprintf fmt "@[Well_known_regex(@,%a)@]" pp_known_regex x + +and pp_string_rules fmt (v:string_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.len; + Pbrt.Pp.pp_record_field ~first:false "min_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_len; + Pbrt.Pp.pp_record_field ~first:false "max_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_len; + Pbrt.Pp.pp_record_field ~first:false "len_bytes" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.len_bytes; + Pbrt.Pp.pp_record_field ~first:false "min_bytes" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_bytes; + Pbrt.Pp.pp_record_field ~first:false "max_bytes" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_bytes; + Pbrt.Pp.pp_record_field ~first:false "pattern" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.pattern; + Pbrt.Pp.pp_record_field ~first:false "prefix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.prefix; + Pbrt.Pp.pp_record_field ~first:false "suffix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.suffix; + Pbrt.Pp.pp_record_field ~first:false "contains" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.contains; + Pbrt.Pp.pp_record_field ~first:false "not_contains" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.not_contains; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "well_known" (Pbrt.Pp.pp_option pp_string_rules_well_known) fmt v.well_known; + Pbrt.Pp.pp_record_field ~first:false "strict" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.strict; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_bytes_rules_well_known fmt (v:bytes_rules_well_known) = + match v with + | Ip x -> Format.fprintf fmt "@[Ip(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv4 x -> Format.fprintf fmt "@[Ipv4(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv6 x -> Format.fprintf fmt "@[Ipv6(@,%a)@]" Pbrt.Pp.pp_bool x + +and pp_bytes_rules fmt (v:bytes_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.len; + Pbrt.Pp.pp_record_field ~first:false "min_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_len; + Pbrt.Pp.pp_record_field ~first:false "max_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_len; + Pbrt.Pp.pp_record_field ~first:false "pattern" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.pattern; + Pbrt.Pp.pp_record_field ~first:false "prefix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.prefix; + Pbrt.Pp.pp_record_field ~first:false "suffix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.suffix; + Pbrt.Pp.pp_record_field ~first:false "contains" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.contains; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_bytes) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_bytes) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "well_known" (Pbrt.Pp.pp_option pp_bytes_rules_well_known) fmt v.well_known; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_enum_rules fmt (v:enum_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "defined_only" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.defined_only; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_any_rules fmt (v:any_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "required" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.required; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.not_in; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_field_rules_type fmt (v:field_rules_type) = + match v with + | Float x -> Format.fprintf fmt "@[Float(@,%a)@]" pp_float_rules x + | Double x -> Format.fprintf fmt "@[Double(@,%a)@]" pp_double_rules x + | Int32 x -> Format.fprintf fmt "@[Int32(@,%a)@]" pp_int32_rules x + | Int64 x -> Format.fprintf fmt "@[Int64(@,%a)@]" pp_int64_rules x + | Uint32 x -> Format.fprintf fmt "@[Uint32(@,%a)@]" pp_uint32_rules x + | Uint64 x -> Format.fprintf fmt "@[Uint64(@,%a)@]" pp_uint64_rules x + | Sint32 x -> Format.fprintf fmt "@[Sint32(@,%a)@]" pp_sint32_rules x + | Sint64 x -> Format.fprintf fmt "@[Sint64(@,%a)@]" pp_sint64_rules x + | Fixed32 x -> Format.fprintf fmt "@[Fixed32(@,%a)@]" pp_fixed32_rules x + | Fixed64 x -> Format.fprintf fmt "@[Fixed64(@,%a)@]" pp_fixed64_rules x + | Sfixed32 x -> Format.fprintf fmt "@[Sfixed32(@,%a)@]" pp_sfixed32_rules x + | Sfixed64 x -> Format.fprintf fmt "@[Sfixed64(@,%a)@]" pp_sfixed64_rules x + | Bool x -> Format.fprintf fmt "@[Bool(@,%a)@]" pp_bool_rules x + | String x -> Format.fprintf fmt "@[String(@,%a)@]" pp_string_rules x + | Bytes x -> Format.fprintf fmt "@[Bytes(@,%a)@]" pp_bytes_rules x + | Enum x -> Format.fprintf fmt "@[Enum(@,%a)@]" pp_enum_rules x + | Repeated x -> Format.fprintf fmt "@[Repeated(@,%a)@]" pp_repeated_rules x + | Map x -> Format.fprintf fmt "@[Map(@,%a)@]" pp_map_rules x + | Any x -> Format.fprintf fmt "@[Any(@,%a)@]" pp_any_rules x + +and pp_field_rules fmt (v:field_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "message" (Pbrt.Pp.pp_option pp_message_rules) fmt v.message; + Pbrt.Pp.pp_record_field ~first:false "type_" (Pbrt.Pp.pp_option pp_field_rules_type) fmt v.type_; + in + Pbrt.Pp.pp_brk pp_i fmt () + +and pp_repeated_rules fmt (v:repeated_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "min_items" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_items; + Pbrt.Pp.pp_record_field ~first:false "max_items" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_items; + Pbrt.Pp.pp_record_field ~first:false "unique" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.unique; + Pbrt.Pp.pp_record_field ~first:false "items" (Pbrt.Pp.pp_option pp_field_rules) fmt v.items; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +and pp_map_rules fmt (v:map_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "min_pairs" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_pairs; + Pbrt.Pp.pp_record_field ~first:false "max_pairs" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_pairs; + Pbrt.Pp.pp_record_field ~first:false "no_sparse" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.no_sparse; + Pbrt.Pp.pp_record_field ~first:false "keys" (Pbrt.Pp.pp_option pp_field_rules) fmt v.keys; + Pbrt.Pp.pp_record_field ~first:false "values" (Pbrt.Pp.pp_option pp_field_rules) fmt v.values; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_field_options fmt (v:field_options) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "rules" (Pbrt.Pp.pp_option pp_field_rules) fmt v.rules; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/tests/expectation/validate.proto b/src/tests/expectation/validate.proto new file mode 100644 index 00000000..cb0ada05 --- /dev/null +++ b/src/tests/expectation/validate.proto @@ -0,0 +1,883 @@ +// Copyright 2024 protoc-gen-validate contributors +// Origin: https://github.com/bufbuild/protoc-gen-validate/blob/main/validate/validate.proto + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// NOTE: this file was modified a bit from the upstream version, extends were +// replaced with actual messages, google protobuf imports commented out, +// Duration and Timestamp rules were commented out for now. + + +syntax = "proto2"; +package validate; + +option go_package = "github.com/envoyproxy/protoc-gen-validate/validate"; +option java_package = "io.envoyproxy.pgv.validate"; + +// import "google/protobuf/descriptor.proto"; +// import "google/protobuf/duration.proto"; +// import "google/protobuf/timestamp.proto"; + +// Validation rules applied at the message level +message MessageOptions { + // Disabled nullifies any validation rules for this message, including any + // message fields associated with it that do support validation. + optional bool disabled = 1071; + // Ignore skips generation of validation methods for this message. + optional bool ignored = 1072; +} + +// Validation rules applied at the oneof level +message OneofOptions { + // Required ensures that exactly one the field options in a oneof is set; + // validation fails if no fields in the oneof are set. + optional bool required = 1071; +} + +// Validation rules applied at the field level +message FieldOptions { + // Rules specify the validations to be performed on this field. By default, + // no validation is performed against a field. + optional FieldRules rules = 1071; +} + +// FieldRules encapsulates the rules for each type of field. Depending on the +// field, the correct set should be used to ensure proper validations. +message FieldRules { + optional MessageRules message = 17; + oneof type { + // Scalar Field Types + FloatRules float = 1; + DoubleRules double = 2; + Int32Rules int32 = 3; + Int64Rules int64 = 4; + UInt32Rules uint32 = 5; + UInt64Rules uint64 = 6; + SInt32Rules sint32 = 7; + SInt64Rules sint64 = 8; + Fixed32Rules fixed32 = 9; + Fixed64Rules fixed64 = 10; + SFixed32Rules sfixed32 = 11; + SFixed64Rules sfixed64 = 12; + BoolRules bool = 13; + StringRules string = 14; + BytesRules bytes = 15; + + // Complex Field Types + EnumRules enum = 16; + RepeatedRules repeated = 18; + MapRules map = 19; + + // Well-Known Field Types + AnyRules any = 20; + //DurationRules duration = 21; + //TimestampRules timestamp = 22; + } +} + +// FloatRules describes the constraints applied to `float` values +message FloatRules { + // Const specifies that this field must be exactly the specified value + optional float const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional float lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional float lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional float gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional float gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated float in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated float not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// DoubleRules describes the constraints applied to `double` values +message DoubleRules { + // Const specifies that this field must be exactly the specified value + optional double const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional double lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional double lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional double gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional double gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated double in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated double not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Int32Rules describes the constraints applied to `int32` values +message Int32Rules { + // Const specifies that this field must be exactly the specified value + optional int32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional int32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional int32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional int32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional int32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated int32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Int64Rules describes the constraints applied to `int64` values +message Int64Rules { + // Const specifies that this field must be exactly the specified value + optional int64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional int64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional int64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional int64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional int64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated int64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// UInt32Rules describes the constraints applied to `uint32` values +message UInt32Rules { + // Const specifies that this field must be exactly the specified value + optional uint32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional uint32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional uint32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional uint32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional uint32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated uint32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated uint32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// UInt64Rules describes the constraints applied to `uint64` values +message UInt64Rules { + // Const specifies that this field must be exactly the specified value + optional uint64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional uint64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional uint64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional uint64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional uint64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated uint64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated uint64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SInt32Rules describes the constraints applied to `sint32` values +message SInt32Rules { + // Const specifies that this field must be exactly the specified value + optional sint32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sint32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sint32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sint32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sint32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sint32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sint32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SInt64Rules describes the constraints applied to `sint64` values +message SInt64Rules { + // Const specifies that this field must be exactly the specified value + optional sint64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sint64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sint64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sint64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sint64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sint64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sint64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Fixed32Rules describes the constraints applied to `fixed32` values +message Fixed32Rules { + // Const specifies that this field must be exactly the specified value + optional fixed32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional fixed32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional fixed32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional fixed32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional fixed32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated fixed32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated fixed32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Fixed64Rules describes the constraints applied to `fixed64` values +message Fixed64Rules { + // Const specifies that this field must be exactly the specified value + optional fixed64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional fixed64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional fixed64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional fixed64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional fixed64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated fixed64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated fixed64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SFixed32Rules describes the constraints applied to `sfixed32` values +message SFixed32Rules { + // Const specifies that this field must be exactly the specified value + optional sfixed32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sfixed32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sfixed32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sfixed32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sfixed32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sfixed32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sfixed32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SFixed64Rules describes the constraints applied to `sfixed64` values +message SFixed64Rules { + // Const specifies that this field must be exactly the specified value + optional sfixed64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sfixed64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sfixed64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sfixed64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sfixed64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sfixed64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sfixed64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// BoolRules describes the constraints applied to `bool` values +message BoolRules { + // Const specifies that this field must be exactly the specified value + optional bool const = 1; +} + +// StringRules describe the constraints applied to `string` values +message StringRules { + // Const specifies that this field must be exactly the specified value + optional string const = 1; + + // Len specifies that this field must be the specified number of + // characters (Unicode code points). Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 len = 19; + + // MinLen specifies that this field must be the specified number of + // characters (Unicode code points) at a minimum. Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 min_len = 2; + + // MaxLen specifies that this field must be the specified number of + // characters (Unicode code points) at a maximum. Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 max_len = 3; + + // LenBytes specifies that this field must be the specified number of bytes + optional uint64 len_bytes = 20; + + // MinBytes specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 min_bytes = 4; + + // MaxBytes specifies that this field must be the specified number of bytes + // at a maximum + optional uint64 max_bytes = 5; + + // Pattern specifies that this field must match against the specified + // regular expression (RE2 syntax). The included expression should elide + // any delimiters. + optional string pattern = 6; + + // Prefix specifies that this field must have the specified substring at + // the beginning of the string. + optional string prefix = 7; + + // Suffix specifies that this field must have the specified substring at + // the end of the string. + optional string suffix = 8; + + // Contains specifies that this field must have the specified substring + // anywhere in the string. + optional string contains = 9; + + // NotContains specifies that this field cannot have the specified substring + // anywhere in the string. + optional string not_contains = 23; + + // In specifies that this field must be equal to one of the specified + // values + repeated string in = 10; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated string not_in = 11; + + // WellKnown rules provide advanced constraints against common string + // patterns + oneof well_known { + // Email specifies that the field must be a valid email address as + // defined by RFC 5322 + bool email = 12; + + // Hostname specifies that the field must be a valid hostname as + // defined by RFC 1034. This constraint does not support + // internationalized domain names (IDNs). + bool hostname = 13; + + // Ip specifies that the field must be a valid IP (v4 or v6) address. + // Valid IPv6 addresses should not include surrounding square brackets. + bool ip = 14; + + // Ipv4 specifies that the field must be a valid IPv4 address. + bool ipv4 = 15; + + // Ipv6 specifies that the field must be a valid IPv6 address. Valid + // IPv6 addresses should not include surrounding square brackets. + bool ipv6 = 16; + + // Uri specifies that the field must be a valid, absolute URI as defined + // by RFC 3986 + bool uri = 17; + + // UriRef specifies that the field must be a valid URI as defined by RFC + // 3986 and may be relative or absolute. + bool uri_ref = 18; + + // Address specifies that the field must be either a valid hostname as + // defined by RFC 1034 (which does not support internationalized domain + // names or IDNs), or it can be a valid IP (v4 or v6). + bool address = 21; + + // Uuid specifies that the field must be a valid UUID as defined by + // RFC 4122 + bool uuid = 22; + + // WellKnownRegex specifies a common well known pattern defined as a regex. + KnownRegex well_known_regex = 24; + } + + // This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable + // strict header validation. + // By default, this is true, and HTTP header validations are RFC-compliant. + // Setting to false will enable a looser validations that only disallows + // \r\n\0 characters, which can be used to bypass header matching rules. + optional bool strict = 25 [default = true]; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 26; +} + +// WellKnownRegex contain some well-known patterns. +enum KnownRegex { + UNKNOWN = 0; + + // HTTP header name as defined by RFC 7230. + HTTP_HEADER_NAME = 1; + + // HTTP header value as defined by RFC 7230. + HTTP_HEADER_VALUE = 2; +} + +// BytesRules describe the constraints applied to `bytes` values +message BytesRules { + // Const specifies that this field must be exactly the specified value + optional bytes const = 1; + + // Len specifies that this field must be the specified number of bytes + optional uint64 len = 13; + + // MinLen specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 min_len = 2; + + // MaxLen specifies that this field must be the specified number of bytes + // at a maximum + optional uint64 max_len = 3; + + // Pattern specifies that this field must match against the specified + // regular expression (RE2 syntax). The included expression should elide + // any delimiters. + optional string pattern = 4; + + // Prefix specifies that this field must have the specified bytes at the + // beginning of the string. + optional bytes prefix = 5; + + // Suffix specifies that this field must have the specified bytes at the + // end of the string. + optional bytes suffix = 6; + + // Contains specifies that this field must have the specified bytes + // anywhere in the string. + optional bytes contains = 7; + + // In specifies that this field must be equal to one of the specified + // values + repeated bytes in = 8; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated bytes not_in = 9; + + // WellKnown rules provide advanced constraints against common byte + // patterns + oneof well_known { + // Ip specifies that the field must be a valid IP (v4 or v6) address in + // byte format + bool ip = 10; + + // Ipv4 specifies that the field must be a valid IPv4 address in byte + // format + bool ipv4 = 11; + + // Ipv6 specifies that the field must be a valid IPv6 address in byte + // format + bool ipv6 = 12; + } + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 14; +} + +// EnumRules describe the constraints applied to enum values +message EnumRules { + // Const specifies that this field must be exactly the specified value + optional int32 const = 1; + + // DefinedOnly specifies that this field must be only one of the defined + // values for this enum, failing on any undefined value. + optional bool defined_only = 2; + + // In specifies that this field must be equal to one of the specified + // values + repeated int32 in = 3; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int32 not_in = 4; +} + +// MessageRules describe the constraints applied to embedded message values. +// For message-type fields, validation is performed recursively. +message MessageRules { + // Skip specifies that the validation rules of this field should not be + // evaluated + optional bool skip = 1; + + // Required specifies that this field must be set + optional bool required = 2; +} + +// RepeatedRules describe the constraints applied to `repeated` values +message RepeatedRules { + // MinItems specifies that this field must have the specified number of + // items at a minimum + optional uint64 min_items = 1; + + // MaxItems specifies that this field must have the specified number of + // items at a maximum + optional uint64 max_items = 2; + + // Unique specifies that all elements in this field must be unique. This + // constraint is only applicable to scalar and enum types (messages are not + // supported). + optional bool unique = 3; + + // Items specifies the constraints to be applied to each item in the field. + // Repeated message fields will still execute validation against each item + // unless skip is specified here. + optional FieldRules items = 4; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 5; +} + +// MapRules describe the constraints applied to `map` values +message MapRules { + // MinPairs specifies that this field must have the specified number of + // KVs at a minimum + optional uint64 min_pairs = 1; + + // MaxPairs specifies that this field must have the specified number of + // KVs at a maximum + optional uint64 max_pairs = 2; + + // NoSparse specifies values in this field cannot be unset. This only + // applies to map's with message value types. + optional bool no_sparse = 3; + + // Keys specifies the constraints to be applied to each key in the field. + optional FieldRules keys = 4; + + // Values specifies the constraints to be applied to the value of each key + // in the field. Message values will still have their validations evaluated + // unless skip is specified here. + optional FieldRules values = 5; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 6; +} + +// AnyRules describe constraints applied exclusively to the +// `google.protobuf.Any` well-known type +message AnyRules { + // Required specifies that this field must be set + optional bool required = 1; + + // In specifies that this field's `type_url` must be equal to one of the + // specified values. + repeated string in = 2; + + // NotIn specifies that this field's `type_url` must not be equal to any of + // the specified values. + repeated string not_in = 3; +} + +// // DurationRules describe the constraints applied exclusively to the +// // `google.protobuf.Duration` well-known type +// message DurationRules { +// // Required specifies that this field must be set +// optional bool required = 1; +// +// // Const specifies that this field must be exactly the specified value +// optional google.protobuf.Duration const = 2; +// +// // Lt specifies that this field must be less than the specified value, +// // exclusive +// optional google.protobuf.Duration lt = 3; +// +// // Lt specifies that this field must be less than the specified value, +// // inclusive +// optional google.protobuf.Duration lte = 4; +// +// // Gt specifies that this field must be greater than the specified value, +// // exclusive +// optional google.protobuf.Duration gt = 5; +// +// // Gte specifies that this field must be greater than the specified value, +// // inclusive +// optional google.protobuf.Duration gte = 6; +// +// // In specifies that this field must be equal to one of the specified +// // values +// repeated google.protobuf.Duration in = 7; +// +// // NotIn specifies that this field cannot be equal to one of the specified +// // values +// repeated google.protobuf.Duration not_in = 8; +// } +// +// // TimestampRules describe the constraints applied exclusively to the +// // `google.protobuf.Timestamp` well-known type +// message TimestampRules { +// // Required specifies that this field must be set +// optional bool required = 1; +// +// // Const specifies that this field must be exactly the specified value +// optional google.protobuf.Timestamp const = 2; +// +// // Lt specifies that this field must be less than the specified value, +// // exclusive +// optional google.protobuf.Timestamp lt = 3; +// +// // Lte specifies that this field must be less than the specified value, +// // inclusive +// optional google.protobuf.Timestamp lte = 4; +// +// // Gt specifies that this field must be greater than the specified value, +// // exclusive +// optional google.protobuf.Timestamp gt = 5; +// +// // Gte specifies that this field must be greater than the specified value, +// // inclusive +// optional google.protobuf.Timestamp gte = 6; +// +// // LtNow specifies that this must be less than the current time. LtNow +// // can only be used with the Within rule. +// optional bool lt_now = 7; +// +// // GtNow specifies that this must be greater than the current time. GtNow +// // can only be used with the Within rule. +// optional bool gt_now = 8; +// +// // Within specifies that this field must be within this duration of the +// // current time. This constraint can be used alone or with the LtNow and +// // GtNow rules. +// optional google.protobuf.Duration within = 9; +// } +// \ No newline at end of file diff --git a/src/tests/google_unittest/dune b/src/tests/google_unittest/dune index 17582bdc..7cd6c25a 100644 --- a/src/tests/google_unittest/dune +++ b/src/tests/google_unittest/dune @@ -1,16 +1,20 @@ (test - (name google_unittest) - (flags :standard -w -11) - (package ocaml-protoc) - (libraries pbrt)) + (name google_unittest) + (flags :standard -w -11) + (package ocaml-protoc) + (libraries pbrt)) (rule - (targets unittest.ml unittest.mli) - (deps (:file unittest.proto) unittest_import.proto) - (action (run ocaml-protoc --ml_out . -I . %{file}))) + (targets unittest.ml unittest.mli) + (deps + (:file unittest.proto) + unittest_import.proto) + (action + (run ocaml-protoc --ml_out . -I . %{file}))) (rule - (targets unittest_import.ml unittest_import.mli) - (deps (:file unittest_import.proto)) - (action (run ocaml-protoc --ml_out . -I . %{file}))) - + (targets unittest_import.ml unittest_import.mli) + (deps + (:file unittest_import.proto)) + (action + (run ocaml-protoc --ml_out . -I . %{file}))) diff --git a/src/tests/integration-tests/dune b/src/tests/integration-tests/dune index dee780fc..fb89dfbd 100644 --- a/src/tests/integration-tests/dune +++ b/src/tests/integration-tests/dune @@ -6,11 +6,14 @@ (rule (targets test01.ml test01.mli) - (deps test01.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test01.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ./ -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ocaml_all_types_ppx "deriving show" --ml_out ./ ./ - test01.proto))) + (run ocaml-protoc -I ./ -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ocaml_all_types_ppx + "deriving show" --ml_out ./ ./ test01.proto))) (executable (name test01_ml) @@ -21,7 +24,10 @@ (rule (targets test02.ml test02.mli) - (deps test02.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test02.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test02.proto))) @@ -32,7 +38,10 @@ (rule (targets test04.ml test04.mli) - (deps test04.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test04.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test04.proto))) @@ -43,7 +52,10 @@ (rule (targets test05.ml test05.mli) - (deps test05.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test05.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test05.proto))) @@ -54,7 +66,10 @@ (rule (targets test06.ml test06.mli) - (deps test06.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test06.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test06.proto))) @@ -65,7 +80,10 @@ (rule (targets test07.ml test07.mli) - (deps test07.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test07.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test07.proto))) @@ -76,7 +94,10 @@ (rule (targets test08.ml test08.mli) - (deps test08.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test08.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test08.proto))) @@ -87,7 +108,10 @@ (rule (targets test09.ml test09.mli) - (deps test09.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test09.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test09.proto))) @@ -104,7 +128,10 @@ (rule (targets test10.ml test10.mli) - (deps test10.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test10.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test10.proto))) @@ -115,7 +142,10 @@ (rule (targets test11.ml test11.mli) - (deps test11.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test11.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test11.proto))) @@ -126,7 +156,10 @@ (rule (targets test12.ml test12.mli) - (deps test12.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test12.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test12.proto))) @@ -137,7 +170,10 @@ (rule (targets test13.ml test13.mli) - (deps test13.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test13.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test13.proto))) @@ -148,7 +184,10 @@ (rule (targets test14.ml test14.mli) - (deps test14.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test14.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test14.proto))) @@ -159,10 +198,13 @@ (rule (targets test15.ml test15.mli) - (deps test15.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test15.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test15.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test15.proto))) (executable (name test15_ml) @@ -171,10 +213,13 @@ (rule (targets test16.ml test16.mli) - (deps test16.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test16.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test16.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test16.proto))) (executable (name test16_ml) @@ -183,10 +228,13 @@ (rule (targets test17.ml test17.mli) - (deps test17.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test17.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test17.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test17.proto))) (executable (name test17_ml) @@ -195,10 +243,13 @@ (rule (targets test18.ml test18.mli) - (deps test18.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test18.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test18.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test18.proto))) (executable (name test18_ml) @@ -207,10 +258,13 @@ (rule (targets test19.ml test19.mli) - (deps test19.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test19.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test19.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test19.proto))) (executable (name test19_ml) @@ -219,10 +273,13 @@ (rule (targets test20.ml test20.mli) - (deps test20.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test20.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test20.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test20.proto))) (executable (name test20_ml) @@ -233,10 +290,13 @@ (rule (targets test21.ml test21.mli) - (deps test21.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test21.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test21.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test21.proto))) (executable (name test21_ml) @@ -247,7 +307,10 @@ (rule (targets test22.ml test22.mli) - (deps test22.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test22.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test22.proto))) @@ -258,7 +321,10 @@ (rule (targets test23.ml test23.mli) - (deps test23.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test23.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test23.proto))) @@ -269,7 +335,10 @@ (rule (targets test24.ml test24.mli) - (deps test24.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test24.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test24.proto))) @@ -280,7 +349,10 @@ (rule (targets test25.ml test25.mli) - (deps test25.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test25.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test25.proto))) @@ -291,10 +363,13 @@ (rule (targets test26.ml test26.mli) - (deps test26.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test26.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action - (run ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ - test26.proto))) + (run ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ + ./ test26.proto))) (executable (name test26_ml) @@ -303,7 +378,10 @@ (rule (targets test27.ml test27.mli) - (deps test27.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps + test27.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ test27.proto))) @@ -316,7 +394,8 @@ (targets test_proto3_optional.ml test_proto3_optional.mli) (deps (:proto test_proto3_optional.proto) - ../../include/ocaml-protoc/ocamloptions.proto) + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ %{proto}))) @@ -329,7 +408,8 @@ (targets test_make.ml test_make.mli) (deps (:proto test_make.proto) - ../../include/ocaml-protoc/ocamloptions.proto) + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --make --ml_out ./ %{proto}))) diff --git a/src/tests/integration-tests/test01_ml.ml b/src/tests/integration-tests/test01_ml.ml index 4fc73a7f..92436c1e 100644 --- a/src/tests/integration-tests/test01_ml.ml +++ b/src/tests/integration-tests/test01_ml.ml @@ -9,7 +9,7 @@ let decode_ref_data () = last_name = "Doe"; date_of_birth = 19820429l; tel_number = None; - employment = Employed_by "Google"; + employment = Some (Employed_by "Google"); marital_status = None; gender = Some Male; }; @@ -19,7 +19,7 @@ let decode_ref_data () = last_name = "Dupont"; date_of_birth = 19820306l; tel_number = Some { area_code = 917l; number = 1111111l }; - employment = Employed_by "INRIA"; + employment = Some (Employed_by "INRIA"); marital_status = None; gender = Some Female; }; @@ -52,7 +52,7 @@ let () = last_name = "Ransan"; date_of_birth = 19820429l; tel_number = None; - employment = Self_employed 0l; + employment = None; marital_status = None; gender = None; } diff --git a/src/tests/integration-tests/test07_ml.ml b/src/tests/integration-tests/test07_ml.ml index ebd845df..65e13c63 100644 --- a/src/tests/integration-tests/test07_ml.ml +++ b/src/tests/integration-tests/test07_ml.ml @@ -3,8 +3,28 @@ module T = Test07 let decode_ref_data () = { T.value = 1l; - T.left = T.Node { T.value = 2l; T.left = T.Empty 0l; T.right = T.Empty 0l }; - T.right = T.Node { T.value = 3l; T.left = T.Empty 0l; T.right = T.Empty 0l }; + T.left = + { + t = + Some + (T.Node + { + T.value = 2l; + T.left = { t = Some (T.Empty 0l) }; + T.right = { t = Some (T.Empty 0l) }; + }); + }; + T.right = + { + t = + Some + (T.Node + { + T.value = 3l; + T.left = { t = Some (T.Empty 0l) }; + T.right = { t = Some (T.Empty 0l) }; + }); + }; } let () = diff --git a/src/tests/integration-tests/test08_ml.ml b/src/tests/integration-tests/test08_ml.ml index c4b4f19c..dd8025e2 100644 --- a/src/tests/integration-tests/test08_ml.ml +++ b/src/tests/integration-tests/test08_ml.ml @@ -1,12 +1,36 @@ module T = Test08 -let decode_ref_data () = - T.Node - { - T.value = 1l; - T.left = T.Node { T.value = 2l; T.left = T.Empty 0l; right = T.Empty 0l }; - T.right = T.Node { T.value = 3l; T.left = T.Empty 0l; right = T.Empty 0l }; - } +let decode_ref_data () : T.tree = + { + t = + Some + (T.Node + { + T.value = 1l; + T.left = + { + t = + Some + (T.Node + { + T.value = 2l; + T.left = { t = Some (T.Empty 0l) }; + right = { t = Some (T.Empty 0l) }; + }); + }; + T.right = + { + t = + Some + (T.Node + { + T.value = 3l; + T.left = { t = Some (T.Empty 0l) }; + right = { t = Some (T.Empty 0l) }; + }); + }; + }); + } let () = let mode = Test_util.parse_args () in diff --git a/src/tests/integration-tests/test11_ml.ml b/src/tests/integration-tests/test11_ml.ml index 1ea47ee6..74a3c8e7 100644 --- a/src/tests/integration-tests/test11_ml.ml +++ b/src/tests/integration-tests/test11_ml.ml @@ -12,7 +12,7 @@ let create_ref_data n = T.last_name = "Doe"; T.date_of_birth = Int32.of_int n; T.tel_number = None; - T.employment = T.Employed_by "Google"; + T.employment = Some (T.Employed_by "Google"); T.marital_status = None; }; T.p2 = @@ -21,7 +21,7 @@ let create_ref_data n = T.last_name = "Dupont"; T.date_of_birth = 19820306l; T.tel_number = Some { T.area_code = 917l; T.number = 1111111l }; - T.employment = T.Employed_by "INRIA"; + T.employment = Some (T.Employed_by "INRIA"); T.marital_status = None; }; T.contact_numbers = diff --git a/src/tests/integration-tests/test13_ml.ml b/src/tests/integration-tests/test13_ml.ml index 12bb5c3f..f8cade3e 100644 --- a/src/tests/integration-tests/test13_ml.ml +++ b/src/tests/integration-tests/test13_ml.ml @@ -3,8 +3,17 @@ module T = Test13 let decode_pb_ref_data () = T. { - p2 = { empty = (); sub = Sub_empty }; - p1 = { l = [ Empty; Int 1l; Empty; Int 2l ] }; + p2 = { empty = (); sub = Some Sub_empty }; + p1 = + { + l = + [ + { t = Some Empty }; + { t = Some (Int 1l) }; + { t = Some Empty }; + { t = Some (Int 2l) }; + ]; + }; } let mode = Test_util.parse_args () diff --git a/src/tests/integration-tests/test14_ml.ml b/src/tests/integration-tests/test14_ml.ml index 4e2e7b6b..d16ee5b5 100644 --- a/src/tests/integration-tests/test14_ml.ml +++ b/src/tests/integration-tests/test14_ml.ml @@ -4,10 +4,10 @@ let decode_pb_ref_data () = T. { da = { aa = [ 1l; 2l; 3l; 4l ] }; - db = Ba { aa = [ 1l; 2l; 3l; 4l ] }; + db = { sub = Some (Ba { aa = [ 1l; 2l; 3l; 4l ] }) }; dc = { - sub = Ca { aa = [ 1l; 2l; 3l; 4l ] }; + sub = Some (Ca { aa = [ 1l; 2l; 3l; 4l ] }); cc = Some { aa = [ 1l; 2l; 3l; 4l ] }; }; } diff --git a/src/tests/integration-tests/test17_ml.ml b/src/tests/integration-tests/test17_ml.ml index 77c1b8ab..2b5eebbf 100644 --- a/src/tests/integration-tests/test17_ml.ml +++ b/src/tests/integration-tests/test17_ml.ml @@ -1,7 +1,7 @@ module T = Test17 let decode_pb_ref_data () = - T.{ m1 = { i1 = 1; i2 = 2 }; m2 = 1; m3 = 1; o = M4 4 } + T.{ m1 = { i1 = 1; i2 = 2 }; m2 = 1; m3 = 1; o = Some (M4 4) } let mode = Test_util.parse_args () diff --git a/src/tests/integration-tests/test18_ml.ml b/src/tests/integration-tests/test18_ml.ml index 4f806eaa..7c4ff41b 100644 --- a/src/tests/integration-tests/test18_ml.ml +++ b/src/tests/integration-tests/test18_ml.ml @@ -9,7 +9,8 @@ let decode_pb_ref_data () = int_to_message_value = [ 1l, { mv_field = "one" }; 2l, { mv_field = "two" } ]; int_to_enum_value = [ 1l, Ev_1; 2l, Ev_2 ]; - int_to_oneof_value = [ 1l, Ov_field1 "one"; 2l, Ov_field2 2l ]; + int_to_oneof_value = + [ 1l, { t = Some (Ov_field1 "one") }; 2l, { t = Some (Ov_field2 2l) } ]; } let mode = Test_util.parse_args () diff --git a/src/tests/integration-tests/test20.proto b/src/tests/integration-tests/test20.proto index 7fc6b241..25ce0a62 100644 --- a/src/tests/integration-tests/test20.proto +++ b/src/tests/integration-tests/test20.proto @@ -12,6 +12,7 @@ message M { option (ocaml_type_ppx) = "deriving show"; required int32 f1 = 1; message Sub { + option (ocaml_type_ppx) = "deriving show"; required int32 sub_f1 = 1; } required Sub f2 = 2; diff --git a/src/tests/integration-tests/test22_ml.ml b/src/tests/integration-tests/test22_ml.ml index 1910647d..4e9ff801 100644 --- a/src/tests/integration-tests/test22_ml.ml +++ b/src/tests/integration-tests/test22_ml.ml @@ -10,7 +10,7 @@ let decode_pb_ref_data () = last_name = "Doe"; date_of_birth = 19820429l; tel_number = None; - employment = Employed_by "Google"; + employment = Some (Employed_by "Google"); marital_status = Single; gender = Male; }; @@ -21,7 +21,7 @@ let decode_pb_ref_data () = last_name = "Dupont"; date_of_birth = 19820306l; tel_number = Some { area_code = 917l; number = 1111111l }; - employment = Employed_by "INRIA"; + employment = Some (Employed_by "INRIA"); marital_status = Married; gender = Female; }; @@ -52,7 +52,7 @@ let () = last_name = ""; date_of_birth = 0l; tel_number = None; - employment = Self_employed 0l; + employment = None; marital_status = Single; gender = Male; } diff --git a/src/tests/integration-tests/test24_ml.ml b/src/tests/integration-tests/test24_ml.ml index 2e739a5d..236faad8 100644 --- a/src/tests/integration-tests/test24_ml.ml +++ b/src/tests/integration-tests/test24_ml.ml @@ -1,6 +1,6 @@ module T = Test24 -let decode_pb_ref_data () : T.a = T.Value "value" +let decode_pb_ref_data () : T.a = T.{ x = Some (Value "value") } let () = let mode = Test_util.parse_args () in diff --git a/src/tests/integration-tests/test27_ml.ml b/src/tests/integration-tests/test27_ml.ml index 6b437160..d5c14ce5 100644 --- a/src/tests/integration-tests/test27_ml.ml +++ b/src/tests/integration-tests/test27_ml.ml @@ -5,7 +5,7 @@ let test_data () = { enum1 = Value_with_option; unit_ = Some { unit_field = 1l }; - one_of_is_keyword = Some (One_of_is_keyword_field 1l); + one_of_is_keyword = Some { message = Some (One_of_is_keyword_field 1l) }; } let () = diff --git a/src/tests/unit-tests/bytecode/dune b/src/tests/unit-tests/bytecode/dune new file mode 100644 index 00000000..bcb68433 --- /dev/null +++ b/src/tests/unit-tests/bytecode/dune @@ -0,0 +1,6 @@ +(tests + (package ocaml-protoc) + (names varint wrapper_encoding pbrt_array) + (libraries pbrt ocaml-protoc.compiler-lib) + (modes byte) + (flags :standard -open Ocaml_protoc_compiler_lib)) diff --git a/src/tests/unit-tests/bytecode/pbrt_array.ml b/src/tests/unit-tests/bytecode/pbrt_array.ml new file mode 100644 index 00000000..c30749a7 --- /dev/null +++ b/src/tests/unit-tests/bytecode/pbrt_array.ml @@ -0,0 +1,55 @@ +let insert_n n : int Pbrt.Repeated_field.t = + let a = Pbrt.Repeated_field.make 0 in + let rec loop = function + | i when i = n -> () + | i -> + Pbrt.Repeated_field.add i a; + loop (i + 1) + in + loop 0; + a + +let () = + (* Small array *) + let a = insert_n 3 in + assert ([| 0; 1; 2 |] = Pbrt.Repeated_field.to_array a) + +let test_n n : unit = + let a = insert_n n in + let a = Pbrt.Repeated_field.to_array a in + Array.iteri (fun i j -> assert (i = j)) a + +let () = + (* Larger Repeated_field *) + for i = 0 to 11_000 do + test_n i + done + +let test_n n : unit = + let a = insert_n n in + let a = Pbrt.Repeated_field.map_to_array (fun x -> -x) a in + Array.iteri (fun i j -> assert (i = -j)) a + +let () = + (* Larger Repeated_field *) + for i = 0 to 5_000 do + test_n i + done + +let () = + (* Pbrt.Repeated_field.fold_left *) + let a = insert_n 3 in + let l = Pbrt.Repeated_field.fold_left (fun acc e -> e :: acc) [] a in + assert ([ 2; 1; 0 ] = l) + +let test_n n : unit = + let a = insert_n n in + let l = Pbrt.Repeated_field.map_to_list (fun x -> -x) a in + List.iteri (fun i j -> assert (i = -j)) l + +let () = + for i = 0 to 1_000 do + test_n i + done + +let () = assert (0 = Pbrt.Repeated_field.length @@ Pbrt.Repeated_field.make 100) diff --git a/src/tests/unit-tests/bytecode/varint.ml b/src/tests/unit-tests/bytecode/varint.ml new file mode 100644 index 00000000..c29495da --- /dev/null +++ b/src/tests/unit-tests/bytecode/varint.ml @@ -0,0 +1,57 @@ +(* see: + https://developers.google.com/protocol-buffers/docs/encoding#varints +*) + +module D = Pbrt.Decoder +module E = Pbrt.Encoder + +let decvarint (s : string) : int64 = + let dec = D.of_string s in + D.int64_as_varint dec + +let encvarint (i : int64) : string = + let enc = E.create () in + E.int64_as_varint i enc; + E.to_string enc + +let str_to_l s = + let l = ref [] in + String.iter (fun x -> l := x :: !l) s; + List.rev !l + +let str_to_il s = str_to_l s |> List.map Char.code + +let () = + let s = encvarint 12L in + assert (str_to_il s = [ 12 ]); + assert (decvarint s = 12L) + +let () = + let s = encvarint 0L in + assert (str_to_il s = [ 0 ]); + assert (decvarint s = 0L) + +let () = + let s = encvarint 127L in + assert (str_to_il s = [ 127 ]); + assert (decvarint s = 127L) + +let () = + let s = encvarint 128L in + assert (str_to_il s = [ 128; 1 ]); + assert (decvarint s = 128L) + +let () = + let s = encvarint 300L in + assert (str_to_il s = [ 0b1010_1100; 0b0000_0010 ]); + assert (decvarint s = 300L) + +let () = + let s = encvarint 150L in + assert (str_to_il s = [ 0x96; 1 ]); + assert (decvarint s = 150L) + +let () = + let s = encvarint 178282982111149L in + assert (str_to_il s = [ 173; 239; 197; 238; 219; 196; 40 ]); + assert (decvarint s = 178282982111149L) diff --git a/src/tests/unit-tests/bytecode/wrapper_encoding.ml b/src/tests/unit-tests/bytecode/wrapper_encoding.ml new file mode 100644 index 00000000..ceb37de2 --- /dev/null +++ b/src/tests/unit-tests/bytecode/wrapper_encoding.ml @@ -0,0 +1,44 @@ +(* unit tests for the wrapper specific encoding *) + +let spf = Printf.sprintf + +let do_test pp encode decode v = + let e = Pbrt.Encoder.create () in + encode (Some v) e; + let b = Pbrt.Encoder.to_bytes e in + (* Printf.printf "encoded: %S for %s\n" (Bytes.unsafe_to_string b) (pp v); *) + let d = Pbrt.Decoder.of_bytes b in + match decode d with + | Some x when x = v -> () + | Some y -> + Printf.eprintf "expected %s, got %s\n%!" (pp v) (pp y); + assert false + | _ -> assert false + +let round32 v = + let open Int32 in + v |> bits_of_float |> float_of_bits + +let pp_bytes b = spf "%S" (Bytes.unsafe_to_string b) + +let () = + let open Pbrt in + do_test (spf "%f") Encoder.wrapper_double_value Decoder.wrapper_double_value + 1.23; + do_test (spf "%f") Encoder.wrapper_float_value Decoder.wrapper_float_value + (round32 1.23); + do_test (spf "%LdL") Encoder.wrapper_int64_value Decoder.wrapper_int64_value + 123L; + do_test (spf "%ldl") Encoder.wrapper_int32_value Decoder.wrapper_int32_value + 123l; + do_test (spf "%b") Encoder.wrapper_bool_value Decoder.wrapper_bool_value true; + do_test (spf "%b") Encoder.wrapper_bool_value Decoder.wrapper_bool_value false; + do_test (spf "%S") Encoder.wrapper_string_value Decoder.wrapper_string_value + ""; + do_test (spf "%S") Encoder.wrapper_string_value Decoder.wrapper_string_value + "abc"; + do_test pp_bytes Encoder.wrapper_bytes_value Decoder.wrapper_bytes_value + (Bytes.of_string ""); + do_test pp_bytes Encoder.wrapper_bytes_value Decoder.wrapper_bytes_value + (Bytes.of_string "abc"); + () diff --git a/src/tests/unit-tests/dune b/src/tests/unit-tests/dune index 0a110bdf..0583504b 100644 --- a/src/tests/unit-tests/dune +++ b/src/tests/unit-tests/dune @@ -2,8 +2,7 @@ (package ocaml-protoc) (names graph_test format_play_ground lexer_comment ocaml_codegen_test parse_enum pbtt_compile_p2 test_typing verify_syntax_invariants - parse_message parse_field_options - parse_file_options parse_import pbtt_compile_p1 backend_ocaml_test - pbrt_array wrapper_encoding varint) + parse_message parse_field_options parse_file_options parse_import + pbtt_compile_p1 backend_ocaml_test pbrt_array wrapper_encoding varint) (libraries pbrt ocaml-protoc.compiler-lib) (flags :standard -open Ocaml_protoc_compiler_lib)) diff --git a/src/tests/unit-tests/parse_field_options.ml b/src/tests/unit-tests/parse_field_options.ml index b704a827..b66436cd 100644 --- a/src/tests/unit-tests/parse_field_options.ml +++ b/src/tests/unit-tests/parse_field_options.ml @@ -1,7 +1,7 @@ let parse f s = f Pb_parsing_lexer.lexer (Lexing.from_string s) let has_option set option_name = - match Pb_option.get set option_name with + match Pb_raw_option.get_simple set option_name with | None -> false | Some _ -> true @@ -9,7 +9,9 @@ module Pt = Pb_parsing_parse_tree let () = let test_default s = - Pb_option.get (parse Pb_parsing_parser.field_options_ s) "default" + Pb_raw_option.get_simple + (parse Pb_parsing_parser.field_options_ s) + "default" |> function | Some (Pb_option.Scalar_value x) -> x | _ -> assert false @@ -32,7 +34,7 @@ let () = let () = let field_options = parse Pb_parsing_parser.field_options_ "[]" in - assert (field_options = Pb_option.empty) + assert (field_options = Pb_raw_option.empty) let () = let field_options = parse Pb_parsing_parser.field_options_ "[a=1,b=true]" in @@ -46,6 +48,6 @@ let () = in assert ( Some Pb_option.(Scalar_value (Constant_literal "int")) - = Pb_option.get field_options "ocaml_type") + = Pb_raw_option.get_ext field_options "ocaml_type") let () = print_endline "Parse Field Options ... Ok" diff --git a/src/tests/unit-tests/parse_file_options.ml b/src/tests/unit-tests/parse_file_options.ml index 7247aa6e..5a94680e 100644 --- a/src/tests/unit-tests/parse_file_options.ml +++ b/src/tests/unit-tests/parse_file_options.ml @@ -8,7 +8,10 @@ module Pt = Pb_parsing_parse_tree let () = let s = "option blah = 1;" in - let fo = "blah", Pb_option.(Scalar_value (Constant_int 1)) in + let fo = + ( [ Pb_raw_option.Simple_name "blah" ], + Pb_option.(Scalar_value (Constant_int 1)) ) + in assert (fo = parse s) let () = @@ -17,10 +20,10 @@ let () = let fo_parsed = proto.Pt.file_options in assert ( Some Pb_option.(Scalar_value (Constant_int 1)) - = Pb_option.get fo_parsed "blah"); + = Pb_raw_option.get_simple fo_parsed "blah"); assert ( Some Pb_option.(Scalar_value (Constant_string "blah")) - = Pb_option.get fo_parsed "foo"); + = Pb_raw_option.get_simple fo_parsed "foo"); () let () = print_endline "Parse File Options ... Ok" diff --git a/src/tests/yojson/dune b/src/tests/yojson/dune index 9b34a351..420abbc4 100644 --- a/src/tests/yojson/dune +++ b/src/tests/yojson/dune @@ -1,11 +1,12 @@ - (test - (name yojson_unittest) - (package ocaml-protoc) - (libraries pbrt pbrt_yojson)) + (name yojson_unittest) + (package ocaml-protoc) + (libraries pbrt pbrt_yojson)) (rule - (targets yojson_unittest.ml yojson_unittest.mli) - (deps (:file yojson_unittest.proto)) - (action (run %{project_root}/src/ocaml-protoc/ocaml_protoc.exe - %{file} --yojson --ml_out=.))) + (targets yojson_unittest.ml yojson_unittest.mli) + (deps + (:protoc %{project_root}/src/ocaml-protoc/ocaml_protoc.exe) + (:file yojson_unittest.proto)) + (action + (run %{protoc} %{file} --yojson --ml_out=.))) diff --git a/src/tests/yojson/yojson/dune b/src/tests/yojson/yojson/dune index 03f6d94a..aa2c92a2 100644 --- a/src/tests/yojson/yojson/dune +++ b/src/tests/yojson/yojson/dune @@ -1,5 +1,4 @@ - (test - (name unit_tests) - (package pbrt_yojson) - (libraries yojson pbrt_yojson)) + (name unit_tests) + (package pbrt_yojson) + (libraries yojson pbrt_yojson)) diff --git a/src/tests/yojson/yojson/unit_tests.ml b/src/tests/yojson/yojson/unit_tests.ml index 4a7aaae8..c5ef64f9 100644 --- a/src/tests/yojson/yojson/unit_tests.ml +++ b/src/tests/yojson/yojson/unit_tests.ml @@ -14,4 +14,3 @@ let () = assert (true = bool (`Bool true) "r" "f"); assert (false = bool (`Bool false) "r" "f"); () -