Repository: mransan/ocaml-protoc
Pull request #245 (2024-05-01 14:43:16)

Parsing of Pb_options according to protobuf schema

Lupus: @c-cube could you please take a look? This is required for further upstreaming of validation generator.
c-cube: I can look, but I've also been slowly trying to fix integration tests on master (which were silently broken).  Would you look at #243 in the mean time?
c-cube: Right now, on my branch (and on this rebased on my branch) `dune build src/tests/integration-tests/test_make.ml` fails, and I bisected it back to either:
- 8c3dbd54081f7ecb5a842f8aba50968b228f3010
- b1002fe478eaf2828ce181ce28554aa2523dec5c

which might have broken packed repeated fields? :/
Lupus: > Right now, on my branch (and on this rebased on my branch) `dune build src/tests/integration-tests/test_make.ml` fails, and I bisected it back to either:
> 
> * [8c3dbd5](https://github.com/mransan/ocaml-protoc/commit/8c3dbd54081f7ecb5a842f8aba50968b228f3010)
> * [b1002fe](https://github.com/mransan/ocaml-protoc/commit/b1002fe478eaf2828ce181ce28554aa2523dec5c)
> 
> which might have broken packed repeated fields? :/

Yeah, something is wrong, I've got a repro, looking into this.
c-cube: merged #243 which conflicts with this, but we're close, I think :).

Patch:
diff --git a/src/compilerlib/dune b/src/compilerlib/dune
index 8a8acde..d0cd622 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_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)
+   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_decode_pb_options.ml b/src/compilerlib/pb_codegen_decode_pb_options.ml
new file mode 100644
index 0000000..5278ea4
--- /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 0000000..6f01a68
--- /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/ocaml-protoc/ocaml_protoc_cmdline.ml b/src/ocaml-protoc/ocaml_protoc_cmdline.ml
index d33a014..f665f04 100644
--- a/src/ocaml-protoc/ocaml_protoc_cmdline.ml
+++ b/src/ocaml-protoc/ocaml_protoc_cmdline.ml
@@ -114,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;
@@ -134,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 ();
@@ -150,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_generation.ml b/src/ocaml-protoc/ocaml_protoc_generation.ml
index a1cc999..e7d55a2 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/runtime-pb-options/dune b/src/runtime-pb-options/dune
new file mode 100644
index 0000000..f62703c
--- /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 0000000..2bdd18f
--- /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 0000000..062dff7
--- /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


Test patch:
diff --git a/src/tests/expectation/dune b/src/tests/expectation/dune
index 0912187..7567663 100644
--- a/src/tests/expectation/dune
+++ b/src/tests/expectation/dune
@@ -12,6 +12,20 @@
  (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)
@@ -22,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 0000000..844e98a
--- /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 72bc09b..95634a3 100644
--- a/src/tests/expectation/option_processing.ml.expected
+++ b/src/tests/expectation/option_processing.ml.expected
@@ -11,7 +11,7 @@ type person_location = {
   lng : float;
 }
 
-type person_id =
+type person_xyz =
   | X of string
   | Y of int32
   | Z of float
@@ -22,7 +22,7 @@ and person = {
   name : string;
   home : person_location option;
   picture : bytes;
-  id : person_id option;
+  xyz : person_xyz option;
 }
 
 type destructured_options = unit
@@ -37,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)
@@ -45,14 +45,14 @@ and default_person
   ?name:((name:string) = "")
   ?home:((home:person_location option) = None)
   ?picture:((picture:bytes) = Bytes.create 0)
-  ?id:((id:person_id option) = None)
+  ?xyz:((xyz:person_xyz option) = None)
   () : person  = {
   id;
   email;
   name;
   home;
   picture;
-  id;
+  xyz;
 }
 
 let rec default_destructured_options = ()
@@ -112,7 +112,7 @@ let rec default_destructured_options = ()
 (* ----------------------------------------------------- *)
 (*
   Module Prefix: Option_processing
-  Variant: person_id
+  Variant: person_xyz
     Constructor: X
       Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_string
 
@@ -166,8 +166,8 @@ let rec default_destructured_options = ()
                                              "bar",
                                              "baz"]}}
    }]
-  - Field: id
-    Rft_variant: person_id
+  - Field: xyz
+    Rft_variant: person_xyz
     Field options: [{
    "(validate.required)": true
    }]
diff --git a/src/tests/expectation/option_processing.proto b/src/tests/expectation/option_processing.proto
index 8aae5c1..c7af9c1 100644
--- a/src/tests/expectation/option_processing.proto
+++ b/src/tests/expectation/option_processing.proto
@@ -32,7 +32,7 @@ message Person {
 
   bytes picture = 5 [(validate.rules).bytes = {not_in: ["foo", "bar", "baz"]}];
 
-  oneof id {
+  oneof xyz {
     option (validate.required) = true;
 
     string x = 6 [(validate.rules).string.prefix = "foo"];
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 0000000..47bbcfd
--- /dev/null
+++ b/src/tests/expectation/test_decode_pb_options.expected
@@ -0,0 +1,87 @@
+====================== <OPTIONS> ======================
+[{
+   "(validate.rules)": {"uint64": {"gt": 999}}
+   }]
+===================== </OPTIONS> ======================
+======================= <PARSED> =======================
+{ message = None;
+  type_ = Some(Uint64({ const = None; lt = None; lte = None; gt = Some(999); gte = None; in_ = []; not_in = []; ignore_empty = None; }));
+}
+====================== </PARSED> =======================
+
+
+====================== <OPTIONS> ======================
+[{
+   "(validate.rules)": {"string": {"email": true}}
+   }]
+===================== </OPTIONS> ======================
+======================= <PARSED> =======================
+{ 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;
+        }));
+}
+====================== </PARSED> =======================
+
+
+====================== <OPTIONS> ======================
+[{
+   "(validate.rules)": {"string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$",
+                                   "max_bytes": 256}}
+   }]
+===================== </OPTIONS> ======================
+======================= <PARSED> =======================
+{ 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;
+        }));
+}
+====================== </PARSED> =======================
+
+
+====================== <OPTIONS> ======================
+[{
+   "(validate.rules)": {"message": {"required": true}}
+   }]
+===================== </OPTIONS> ======================
+======================= <PARSED> =======================
+{ message = Some({ skip = None; required = Some(true); }); type_ = None; }
+====================== </PARSED> =======================
+
+
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 0000000..e36402b
--- /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
+      "====================== <OPTIONS> \
+       ======================@.%a@.===================== </OPTIONS> \
+       ======================@.======================= <PARSED> \
+       =======================@.%a@.====================== </PARSED> \
+       =======================@.@.@."
+      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/validate.ml.expected b/src/tests/expectation/validate.ml.expected
new file mode 100644
index 0000000..70e3fb0
--- /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 "@[<hv2>Email(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Hostname x -> Format.fprintf fmt "@[<hv2>Hostname(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Ip x -> Format.fprintf fmt "@[<hv2>Ip(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Ipv4 x -> Format.fprintf fmt "@[<hv2>Ipv4(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Ipv6 x -> Format.fprintf fmt "@[<hv2>Ipv6(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Uri x -> Format.fprintf fmt "@[<hv2>Uri(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Uri_ref x -> Format.fprintf fmt "@[<hv2>Uri_ref(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Address x -> Format.fprintf fmt "@[<hv2>Address(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Uuid x -> Format.fprintf fmt "@[<hv2>Uuid(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Well_known_regex x -> Format.fprintf fmt "@[<hv2>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 "@[<hv2>Ip(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Ipv4 x -> Format.fprintf fmt "@[<hv2>Ipv4(@,%a)@]" Pbrt.Pp.pp_bool x
+  | Ipv6 x -> Format.fprintf fmt "@[<hv2>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 "@[<hv2>Float(@,%a)@]" pp_float_rules x
+  | Double x -> Format.fprintf fmt "@[<hv2>Double(@,%a)@]" pp_double_rules x
+  | Int32 x -> Format.fprintf fmt "@[<hv2>Int32(@,%a)@]" pp_int32_rules x
+  | Int64 x -> Format.fprintf fmt "@[<hv2>Int64(@,%a)@]" pp_int64_rules x
+  | Uint32 x -> Format.fprintf fmt "@[<hv2>Uint32(@,%a)@]" pp_uint32_rules x
+  | Uint64 x -> Format.fprintf fmt "@[<hv2>Uint64(@,%a)@]" pp_uint64_rules x
+  | Sint32 x -> Format.fprintf fmt "@[<hv2>Sint32(@,%a)@]" pp_sint32_rules x
+  | Sint64 x -> Format.fprintf fmt "@[<hv2>Sint64(@,%a)@]" pp_sint64_rules x
+  | Fixed32 x -> Format.fprintf fmt "@[<hv2>Fixed32(@,%a)@]" pp_fixed32_rules x
+  | Fixed64 x -> Format.fprintf fmt "@[<hv2>Fixed64(@,%a)@]" pp_fixed64_rules x
+  | Sfixed32 x -> Format.fprintf fmt "@[<hv2>Sfixed32(@,%a)@]" pp_sfixed32_rules x
+  | Sfixed64 x -> Format.fprintf fmt "@[<hv2>Sfixed64(@,%a)@]" pp_sfixed64_rules x
+  | Bool x -> Format.fprintf fmt "@[<hv2>Bool(@,%a)@]" pp_bool_rules x
+  | String x -> Format.fprintf fmt "@[<hv2>String(@,%a)@]" pp_string_rules x
+  | Bytes x -> Format.fprintf fmt "@[<hv2>Bytes(@,%a)@]" pp_bytes_rules x
+  | Enum x -> Format.fprintf fmt "@[<hv2>Enum(@,%a)@]" pp_enum_rules x
+  | Repeated x -> Format.fprintf fmt "@[<hv2>Repeated(@,%a)@]" pp_repeated_rules x
+  | Map x -> Format.fprintf fmt "@[<hv2>Map(@,%a)@]" pp_map_rules x
+  | Any x -> Format.fprintf fmt "@[<hv2>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 0000000..cb0ada0
--- /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