From 5ba710a240c8fd7504fa22f489f00e6c29d8199d Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Wed, 17 Jan 2024 12:10:08 +0400 Subject: [PATCH 01/47] Add oneof example --- src/examples/dune | 15 +- src/examples/dune.inc | 10 + src/examples/oneof.ml.expected | 414 ++++++++++++++++++++++++++++++++ src/examples/oneof.mli.expected | 155 ++++++++++++ src/examples/oneof.proto | 22 ++ 5 files changed, 615 insertions(+), 1 deletion(-) create mode 100644 src/examples/oneof.ml.expected create mode 100644 src/examples/oneof.mli.expected create mode 100644 src/examples/oneof.proto diff --git a/src/examples/dune b/src/examples/dune index f97e3502..24d338af 100644 --- a/src/examples/dune +++ b/src/examples/dune @@ -94,6 +94,18 @@ (package ocaml-protoc) (libraries pbrt pbrt_yojson pbrt_services)) +(rule + (targets oneof.ml oneof.mli) + (deps oneof.proto) + (action + (run ocaml-protoc --binary --pp --yojson --services --ml_out ./ %{deps}))) + +(test + (name oneof) + (modules oneof) ; just check that it compiles + (package ocaml-protoc) + (libraries pbrt pbrt_yojson pbrt_services)) + (include dune.inc) (rule @@ -116,4 +128,5 @@ example04 example05 file_server - orgchart)))) + orgchart + oneof)))) diff --git a/src/examples/dune.inc b/src/examples/dune.inc index e74bd2b6..517799ce 100644 --- a/src/examples/dune.inc +++ b/src/examples/dune.inc @@ -70,6 +70,16 @@ (action (diff file_server.mli.expected file_server.mli))) +(rule + (alias runtest) + (action + (diff oneof.ml.expected oneof.ml))) + +(rule + (alias runtest) + (action + (diff oneof.mli.expected oneof.mli))) + (rule (alias runtest) (action diff --git a/src/examples/oneof.ml.expected b/src/examples/oneof.ml.expected new file mode 100644 index 00000000..1852ad79 --- /dev/null +++ b/src/examples/oneof.ml.expected @@ -0,0 +1,414 @@ +[@@@ocaml.warning "-27-30-39"] + +type patch_copy = { + start : int64; + end_ : int64; +} + +type patch_insert = { + raw_bytes : bytes; +} + +type patch_op = + | Copy_op of patch_copy + | Insert_op of patch_insert + +and patch = { + op : patch_op; + id : int64; +} + +type instructions = { + operations : patch list; +} + +let rec default_patch_copy + ?start:((start:int64) = 0L) + ?end_:((end_:int64) = 0L) + () : patch_copy = { + start; + end_; +} + +let rec default_patch_insert + ?raw_bytes:((raw_bytes:bytes) = Bytes.create 0) + () : patch_insert = { + raw_bytes; +} + +let rec default_patch_op () : patch_op = Copy_op (default_patch_copy ()) + +and default_patch + ?op:((op:patch_op) = Copy_op (default_patch_copy ())) + ?id:((id:int64) = 0L) + () : patch = { + op; + id; +} + +let rec default_instructions + ?operations:((operations:patch list) = []) + () : instructions = { + operations; +} + +type patch_copy_mutable = { + mutable start : int64; + mutable end_ : int64; +} + +let default_patch_copy_mutable () : patch_copy_mutable = { + start = 0L; + end_ = 0L; +} + +type patch_insert_mutable = { + mutable raw_bytes : bytes; +} + +let default_patch_insert_mutable () : patch_insert_mutable = { + raw_bytes = Bytes.create 0; +} + +type patch_mutable = { + mutable op : patch_op; + mutable id : int64; +} + +let default_patch_mutable () : patch_mutable = { + op = Copy_op (default_patch_copy ()); + id = 0L; +} + +type instructions_mutable = { + mutable operations : patch list; +} + +let default_instructions_mutable () : instructions_mutable = { + operations = []; +} + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Formatters} *) + +let rec pp_patch_copy fmt (v:patch_copy) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "start" Pbrt.Pp.pp_int64 fmt v.start; + Pbrt.Pp.pp_record_field ~first:false "end_" Pbrt.Pp.pp_int64 fmt v.end_; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_patch_insert fmt (v:patch_insert) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "raw_bytes" Pbrt.Pp.pp_bytes fmt v.raw_bytes; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_patch_op fmt (v:patch_op) = + match v with + | Copy_op x -> Format.fprintf fmt "@[Copy_op(@,%a)@]" pp_patch_copy x + | Insert_op x -> Format.fprintf fmt "@[Insert_op(@,%a)@]" pp_patch_insert x + +and pp_patch fmt (v:patch) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "op" pp_patch_op fmt v.op; + Pbrt.Pp.pp_record_field ~first:false "id" Pbrt.Pp.pp_int64 fmt v.id; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_instructions fmt (v:instructions) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "operations" (Pbrt.Pp.pp_list pp_patch) fmt v.operations; + in + Pbrt.Pp.pp_brk pp_i fmt () + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Protobuf Encoding} *) + +let rec encode_pb_patch_copy (v:patch_copy) encoder = + Pbrt.Encoder.int64_as_varint v.start encoder; + Pbrt.Encoder.key 1 Pbrt.Varint encoder; + Pbrt.Encoder.int64_as_varint v.end_ encoder; + Pbrt.Encoder.key 2 Pbrt.Varint encoder; + () + +let rec encode_pb_patch_insert (v:patch_insert) encoder = + Pbrt.Encoder.bytes v.raw_bytes encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + () + +let rec encode_pb_patch_op (v:patch_op) encoder = + begin match v with + | Copy_op x -> + Pbrt.Encoder.nested encode_pb_patch_copy x encoder; + Pbrt.Encoder.key 3 Pbrt.Bytes encoder; + | Insert_op x -> + Pbrt.Encoder.nested encode_pb_patch_insert x encoder; + Pbrt.Encoder.key 4 Pbrt.Bytes encoder; + end + +and encode_pb_patch (v:patch) encoder = + begin match v.op with + | Copy_op x -> + Pbrt.Encoder.nested encode_pb_patch_copy x encoder; + Pbrt.Encoder.key 3 Pbrt.Bytes encoder; + | Insert_op x -> + Pbrt.Encoder.nested encode_pb_patch_insert x encoder; + Pbrt.Encoder.key 4 Pbrt.Bytes encoder; + end; + Pbrt.Encoder.int64_as_varint v.id encoder; + Pbrt.Encoder.key 5 Pbrt.Varint encoder; + () + +let rec encode_pb_instructions (v:instructions) encoder = + Pbrt.List_util.rev_iter_with (fun x encoder -> + Pbrt.Encoder.nested encode_pb_patch x encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + ) v.operations encoder; + () + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Protobuf Decoding} *) + +let rec decode_pb_patch_copy d = + let v = default_patch_copy_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Varint) -> begin + v.start <- Pbrt.Decoder.int64_as_varint d; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch_copy), field(1)" pk + | Some (2, Pbrt.Varint) -> begin + v.end_ <- Pbrt.Decoder.int64_as_varint d; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch_copy), field(2)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + start = v.start; + end_ = v.end_; + } : patch_copy) + +let rec decode_pb_patch_insert d = + let v = default_patch_insert_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.raw_bytes <- Pbrt.Decoder.bytes d; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch_insert), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + raw_bytes = v.raw_bytes; + } : patch_insert) + +let rec decode_pb_patch_op d = + let rec loop () = + let ret:patch_op = match Pbrt.Decoder.key d with + | None -> Pbrt.Decoder.malformed_variant "patch_op" + | Some (3, _) -> (Copy_op (decode_pb_patch_copy (Pbrt.Decoder.nested d)) : patch_op) + | Some (4, _) -> (Insert_op (decode_pb_patch_insert (Pbrt.Decoder.nested d)) : patch_op) + | Some (n, payload_kind) -> ( + Pbrt.Decoder.skip d payload_kind; + loop () + ) + in + ret + in + loop () + +and decode_pb_patch d = + let v = default_patch_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (3, Pbrt.Bytes) -> begin + v.op <- Copy_op (decode_pb_patch_copy (Pbrt.Decoder.nested d)); + end + | Some (3, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch), field(3)" pk + | Some (4, Pbrt.Bytes) -> begin + v.op <- Insert_op (decode_pb_patch_insert (Pbrt.Decoder.nested d)); + end + | Some (4, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch), field(4)" pk + | Some (5, Pbrt.Varint) -> begin + v.id <- Pbrt.Decoder.int64_as_varint d; + end + | Some (5, pk) -> + Pbrt.Decoder.unexpected_payload "Message(patch), field(5)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + op = v.op; + id = v.id; + } : patch) + +let rec decode_pb_instructions d = + let v = default_instructions_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.operations <- List.rev v.operations; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.operations <- (decode_pb_patch (Pbrt.Decoder.nested d)) :: v.operations; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(instructions), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + operations = v.operations; + } : instructions) + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Protobuf YoJson Encoding} *) + +let rec encode_json_patch_copy (v:patch_copy) = + let assoc = [] in + let assoc = ("start", Pbrt_yojson.make_string (Int64.to_string v.start)) :: assoc in + let assoc = ("end", Pbrt_yojson.make_string (Int64.to_string v.end_)) :: assoc in + `Assoc assoc + +let rec encode_json_patch_insert (v:patch_insert) = + let assoc = [] in + let assoc = ("rawBytes", Pbrt_yojson.make_bytes v.raw_bytes) :: assoc in + `Assoc assoc + +let rec encode_json_patch_op (v:patch_op) = + begin match v with + | Copy_op v -> `Assoc [("copyOp", encode_json_patch_copy v)] + | Insert_op v -> `Assoc [("insertOp", encode_json_patch_insert v)] + end + +and encode_json_patch (v:patch) = + let assoc = [] in + let assoc = match v.op with + | Copy_op v -> + ("copyOp", encode_json_patch_copy v) :: assoc + | Insert_op v -> + ("insertOp", encode_json_patch_insert v) :: assoc + in (* match v.op *) + let assoc = ("id", Pbrt_yojson.make_string (Int64.to_string v.id)) :: assoc in + `Assoc assoc + +let rec encode_json_instructions (v:instructions) = + let assoc = [] in + let assoc = + let l = v.operations |> List.map encode_json_patch in + ("operations", `List l) :: assoc + in + `Assoc assoc + +[@@@ocaml.warning "-27-30-39"] + +(** {2 JSON Decoding} *) + +let rec decode_json_patch_copy d = + let v = default_patch_copy_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("start", json_value) -> + v.start <- Pbrt_yojson.int64 json_value "patch_copy" "start" + | ("end", json_value) -> + v.end_ <- Pbrt_yojson.int64 json_value "patch_copy" "end_" + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + start = v.start; + end_ = v.end_; + } : patch_copy) + +let rec decode_json_patch_insert d = + let v = default_patch_insert_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("rawBytes", json_value) -> + v.raw_bytes <- Pbrt_yojson.bytes json_value "patch_insert" "raw_bytes" + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + raw_bytes = v.raw_bytes; + } : patch_insert) + +let rec decode_json_patch_op json = + let assoc = match json with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_yojson.E.malformed_variant "patch_op" + | ("copyOp", json_value)::_ -> + (Copy_op ((decode_json_patch_copy json_value)) : patch_op) + | ("insertOp", json_value)::_ -> + (Insert_op ((decode_json_patch_insert json_value)) : patch_op) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_json_patch d = + let v = default_patch_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("copyOp", json_value) -> + v.op <- Copy_op ((decode_json_patch_copy json_value)) + | ("insertOp", json_value) -> + v.op <- Insert_op ((decode_json_patch_insert json_value)) + | ("id", json_value) -> + v.id <- Pbrt_yojson.int64 json_value "patch" "id" + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + op = v.op; + id = v.id; + } : patch) + +let rec decode_json_instructions d = + let v = default_instructions_mutable () in + let assoc = match d with + | `Assoc assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("operations", `List l) -> begin + v.operations <- List.map (function + | json_value -> (decode_json_patch json_value) + ) l; + end + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + operations = v.operations; + } : instructions) diff --git a/src/examples/oneof.mli.expected b/src/examples/oneof.mli.expected new file mode 100644 index 00000000..4b48e3ac --- /dev/null +++ b/src/examples/oneof.mli.expected @@ -0,0 +1,155 @@ + +(** Code for oneof.proto *) + +(* generated from "oneof.proto", do not edit *) + + + +(** {2 Types} *) + +type patch_copy = { + start : int64; + end_ : int64; +} + +type patch_insert = { + raw_bytes : bytes; +} + +type patch_op = + | Copy_op of patch_copy + | Insert_op of patch_insert + +and patch = { + op : patch_op; + id : int64; +} + +type instructions = { + operations : patch list; +} + + +(** {2 Basic values} *) + +val default_patch_copy : + ?start:int64 -> + ?end_:int64 -> + unit -> + patch_copy +(** [default_patch_copy ()] is the default value for type [patch_copy] *) + +val default_patch_insert : + ?raw_bytes:bytes -> + unit -> + patch_insert +(** [default_patch_insert ()] is the default value for type [patch_insert] *) + +val default_patch_op : unit -> patch_op +(** [default_patch_op ()] is the default value for type [patch_op] *) + +val default_patch : + ?op:patch_op -> + ?id:int64 -> + unit -> + patch +(** [default_patch ()] is the default value for type [patch] *) + +val default_instructions : + ?operations:patch list -> + unit -> + instructions +(** [default_instructions ()] is the default value for type [instructions] *) + + +(** {2 Formatters} *) + +val pp_patch_copy : Format.formatter -> patch_copy -> unit +(** [pp_patch_copy v] formats v *) + +val pp_patch_insert : Format.formatter -> patch_insert -> unit +(** [pp_patch_insert v] formats v *) + +val pp_patch_op : Format.formatter -> patch_op -> unit +(** [pp_patch_op v] formats v *) + +val pp_patch : Format.formatter -> patch -> unit +(** [pp_patch v] formats v *) + +val pp_instructions : Format.formatter -> instructions -> unit +(** [pp_instructions v] formats v *) + + +(** {2 Protobuf Encoding} *) + +val encode_pb_patch_copy : patch_copy -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch_copy v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_patch_insert : patch_insert -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch_insert v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_patch_op : patch_op -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch_op v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_patch : patch -> Pbrt.Encoder.t -> unit +(** [encode_pb_patch v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_instructions : instructions -> Pbrt.Encoder.t -> unit +(** [encode_pb_instructions v encoder] encodes [v] with the given [encoder] *) + + +(** {2 Protobuf Decoding} *) + +val decode_pb_patch_copy : Pbrt.Decoder.t -> patch_copy +(** [decode_pb_patch_copy decoder] decodes a [patch_copy] binary value from [decoder] *) + +val decode_pb_patch_insert : Pbrt.Decoder.t -> patch_insert +(** [decode_pb_patch_insert decoder] decodes a [patch_insert] binary value from [decoder] *) + +val decode_pb_patch_op : Pbrt.Decoder.t -> patch_op +(** [decode_pb_patch_op decoder] decodes a [patch_op] binary value from [decoder] *) + +val decode_pb_patch : Pbrt.Decoder.t -> patch +(** [decode_pb_patch decoder] decodes a [patch] binary value from [decoder] *) + +val decode_pb_instructions : Pbrt.Decoder.t -> instructions +(** [decode_pb_instructions decoder] decodes a [instructions] binary value from [decoder] *) + + +(** {2 Protobuf YoJson Encoding} *) + +val encode_json_patch_copy : patch_copy -> Yojson.Basic.t +(** [encode_json_patch_copy v encoder] encodes [v] to to json *) + +val encode_json_patch_insert : patch_insert -> Yojson.Basic.t +(** [encode_json_patch_insert v encoder] encodes [v] to to json *) + +val encode_json_patch_op : patch_op -> Yojson.Basic.t +(** [encode_json_patch_op v encoder] encodes [v] to to json *) + +val encode_json_patch : patch -> Yojson.Basic.t +(** [encode_json_patch v encoder] encodes [v] to to json *) + +val encode_json_instructions : instructions -> Yojson.Basic.t +(** [encode_json_instructions v encoder] encodes [v] to to json *) + + +(** {2 JSON Decoding} *) + +val decode_json_patch_copy : Yojson.Basic.t -> patch_copy +(** [decode_json_patch_copy decoder] decodes a [patch_copy] value from [decoder] *) + +val decode_json_patch_insert : Yojson.Basic.t -> patch_insert +(** [decode_json_patch_insert decoder] decodes a [patch_insert] value from [decoder] *) + +val decode_json_patch_op : Yojson.Basic.t -> patch_op +(** [decode_json_patch_op decoder] decodes a [patch_op] value from [decoder] *) + +val decode_json_patch : Yojson.Basic.t -> patch +(** [decode_json_patch decoder] decodes a [patch] value from [decoder] *) + +val decode_json_instructions : Yojson.Basic.t -> instructions +(** [decode_json_instructions decoder] decodes a [instructions] value from [decoder] *) + + +(** {2 Services} *) diff --git a/src/examples/oneof.proto b/src/examples/oneof.proto new file mode 100644 index 00000000..0489c704 --- /dev/null +++ b/src/examples/oneof.proto @@ -0,0 +1,22 @@ +syntax="proto3"; + +message Patch { + message Copy { + int64 start =1; + int64 end=2; + } + + message Insert { + bytes raw_bytes=1; + + } + oneof op { + Copy copy_op=3; + Insert insert_op=4; + } + int64 id = 5; +} + +message Instructions { + repeated Patch operations=1; +} From 9dbbe584552b22bccb0c00bcdcb66bef13f0caee Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Wed, 17 Jan 2024 12:40:43 +0400 Subject: [PATCH 02/47] Wrap oneof fields into options --- src/compilerlib/pb_codegen_decode_binary.ml | 4 +-- src/compilerlib/pb_codegen_decode_bs.ml | 6 ++-- src/compilerlib/pb_codegen_decode_yojson.ml | 4 +-- src/compilerlib/pb_codegen_default.ml | 9 +----- src/compilerlib/pb_codegen_encode_binary.ml | 5 ++-- src/compilerlib/pb_codegen_encode_bs.ml | 5 ++-- src/compilerlib/pb_codegen_encode_yojson.ml | 5 ++-- src/compilerlib/pb_codegen_pp.ml | 4 ++- src/compilerlib/pb_codegen_util.ml | 4 +-- src/examples/oneof.ml.expected | 28 ++++++++++--------- src/examples/oneof.mli.expected | 4 +-- .../expectation/option_processing.ml.expected | 4 +-- 12 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/compilerlib/pb_codegen_decode_binary.ml b/src/compilerlib/pb_codegen_decode_binary.ml index f9e98225..b7d994b1 100644 --- a/src/compilerlib/pb_codegen_decode_binary.ml +++ b/src/compilerlib/pb_codegen_decode_binary.ml @@ -169,9 +169,9 @@ let gen_rft_variant sc r_name rf_label { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> F.line sc "Pbrt.Decoder.empty_nested d;"; - F.linep sc "v.%s <- %s;" rf_label vc_constructor + F.linep sc "v.%s <- Some %s;" rf_label vc_constructor | Ot.Vct_non_nullary_constructor field_type -> - F.linep sc "v.%s <- %s (%s);" rf_label vc_constructor + F.linep sc "v.%s <- Some (%s (%s));" rf_label vc_constructor (decode_field_expression field_type pk))) v_constructors diff --git a/src/compilerlib/pb_codegen_decode_bs.ml b/src/compilerlib/pb_codegen_decode_bs.ml index 645f782d..7a8c74cd 100644 --- a/src/compilerlib/pb_codegen_decode_bs.ml +++ b/src/compilerlib/pb_codegen_decode_bs.ml @@ -94,12 +94,14 @@ let gen_rft_variant sc ~r_name ~rf_label { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> - F.linep sc "| \"%s\" -> v.%s <- %s" json_label rf_label vc_constructor + F.linep sc "| \"%s\" -> v.%s <- Some %s" json_label rf_label + vc_constructor | Ot.Vct_non_nullary_constructor field_type -> let value_expression = value_expression ~r_name ~rf_label field_type in F.linep sc "| \"%s\" -> " json_label; F.linep sc " let json = Js.Dict.unsafeGet json \"%s\" in" json_label; - F.linep sc " v.%s <- %s (%s)" rf_label vc_constructor value_expression) + F.linep sc " v.%s <- Some (%s (%s))" rf_label vc_constructor + value_expression) v_constructors (* Generate decode function for a record *) diff --git a/src/compilerlib/pb_codegen_decode_yojson.ml b/src/compilerlib/pb_codegen_decode_yojson.ml index cd9a2e1a..2092c169 100644 --- a/src/compilerlib/pb_codegen_decode_yojson.ml +++ b/src/compilerlib/pb_codegen_decode_yojson.ml @@ -89,14 +89,14 @@ let gen_rft_variant_field sc ~r_name ~rf_label { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> - F.linep sc "| (\"%s\", _) -> v.%s <- %s" json_label rf_label + F.linep sc "| (\"%s\", _) -> v.%s <- Some %s" json_label rf_label vc_constructor | Ot.Vct_non_nullary_constructor field_type -> let match_variable_name, exp = field_pattern_match ~r_name ~rf_label field_type in F.linep sc "| (\"%s\", %s) -> " json_label match_variable_name; - F.linep sc " v.%s <- %s (%s)" rf_label vc_constructor exp) + F.linep sc " v.%s <- Some (%s (%s))" rf_label vc_constructor exp) v_constructors let gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type = diff --git a/src/compilerlib/pb_codegen_default.ml b/src/compilerlib/pb_codegen_default.ml index 19d0b4af..70f6cb3f 100644 --- a/src/compilerlib/pb_codegen_default.ml +++ b/src/compilerlib/pb_codegen_default.ml @@ -69,14 +69,7 @@ let record_field_default_info record_field = | Ot.At_hashtable -> "Hashtbl.create 128") (* TODO This initial value could be configurable either via * the default function or via a protobuf option. *) - | Ot.Rft_variant { Ot.v_constructors; _ } -> - (match v_constructors with - | [] -> assert false - | { Ot.vc_constructor; vc_field_type; _ } :: _ -> - (match vc_field_type with - | Ot.Vct_nullary -> vc_constructor - | Ot.Vct_non_nullary_constructor field_type -> - sp "%s (%s)" vc_constructor (dfvft field_type None))) + | Ot.Rft_variant _ -> "None" in field_name, default_value, type_string diff --git a/src/compilerlib/pb_codegen_encode_binary.ml b/src/compilerlib/pb_codegen_encode_binary.ml index 3dcb7b1c..3e61409a 100644 --- a/src/compilerlib/pb_codegen_encode_binary.ml +++ b/src/compilerlib/pb_codegen_encode_binary.ml @@ -145,16 +145,17 @@ let gen_rft_variant sc var_name { Ot.v_constructors; _ } = match vc_field_type with | Ot.Vct_nullary -> - F.linep sc "| %s ->" vc_constructor; + F.linep sc "| Some %s ->" vc_constructor; F.sub_scope sc (fun sc -> F.line sc "Pbrt.Encoder.empty_nested encoder;"; gen_encode_field_key sc vc_encoding_number vc_payload_kind false) | Ot.Vct_non_nullary_constructor field_type -> - F.linep sc "| %s x ->" vc_constructor; + F.linep sc "| Some %s x ->" vc_constructor; F.sub_scope sc (fun sc -> gen_encode_field_type sc ~with_key:true "x" vc_encoding_number vc_payload_kind false field_type)) v_constructors; + F.line sc "| None -> ()"; F.line sc "end;" let gen_rft_associative sc var_name associative_field = diff --git a/src/compilerlib/pb_codegen_encode_bs.ml b/src/compilerlib/pb_codegen_encode_bs.ml index 5c30c9cd..5798d6ba 100644 --- a/src/compilerlib/pb_codegen_encode_bs.ml +++ b/src/compilerlib/pb_codegen_encode_bs.ml @@ -162,14 +162,15 @@ let gen_rft_variant sc var_name rf_label { Ot.v_constructors; _ } = let json_label = Pb_codegen_util.camel_case_of_constructor vc_constructor in - F.linep sc "| %s v ->" vc_constructor; + F.linep sc "| Some (%s v) ->" vc_constructor; F.sub_scope sc (fun sc -> match vc_field_type with | Ot.Vct_nullary -> F.linep sc "Js.Dict.set json \"%s\" Js.Json.null" json_label | Ot.Vct_non_nullary_constructor field_type -> gen_field sc var_name json_label field_type vc_payload_kind)) - v_constructors); + v_constructors; + F.line sc "| None -> ()"); F.linep sc "end; (* match v.%s *)" rf_label let gen_record ?and_ { Ot.r_name; r_fields } sc = diff --git a/src/compilerlib/pb_codegen_encode_yojson.ml b/src/compilerlib/pb_codegen_encode_yojson.ml index bb3f7d06..25ecce40 100644 --- a/src/compilerlib/pb_codegen_encode_yojson.ml +++ b/src/compilerlib/pb_codegen_encode_yojson.ml @@ -133,7 +133,7 @@ let gen_rft_variant sc rf_label { Ot.v_constructors; _ } = let json_label = Pb_codegen_util.camel_case_of_constructor vc_constructor in - F.linep sc "| %s v ->" vc_constructor; + F.linep sc "| Some (%s v) ->" vc_constructor; F.sub_scope sc (fun sc -> match vc_field_type with | Ot.Vct_nullary -> @@ -144,7 +144,8 @@ let gen_rft_variant sc rf_label { Ot.v_constructors; _ } = with | None -> F.linep sc "(\"%s\", `Null) :: assoc" json_label | Some exp -> F.linep sc "%s :: assoc " exp))) - v_constructors); + v_constructors; + F.line sc "| None -> assoc"); F.linep sc "in (* match v.%s *)" rf_label diff --git a/src/compilerlib/pb_codegen_pp.ml b/src/compilerlib/pb_codegen_pp.ml index fdbefc49..9d53cf8e 100644 --- a/src/compilerlib/pb_codegen_pp.ml +++ b/src/compilerlib/pb_codegen_pp.ml @@ -66,7 +66,9 @@ let gen_record ?and_ { Ot.r_name; r_fields } sc = * requirement is indeed comming from the imposed Protobuf format) *) F.line sc - @@ sp "Pbrt.Pp.pp_record_field ~first:%b \"%s\" %s fmt %s;" + @@ sp + "Pbrt.Pp.pp_record_field ~first:%b \"%s\" \ + (Pbrt.Pp.pp_option %s) fmt %s;" first rf_label ("pp_" ^ v_name) var_name (* Rft_variant_field *) | Ot.Rft_associative (at, _, (key_type, _), (value_type, _)) -> diff --git a/src/compilerlib/pb_codegen_util.ml b/src/compilerlib/pb_codegen_util.ml index 0cb6a987..7a3bcef7 100644 --- a/src/compilerlib/pb_codegen_util.ml +++ b/src/compilerlib/pb_codegen_util.ml @@ -68,8 +68,8 @@ let string_of_record_field_type ?module_prefix = function (string_of_associative_type Ot.At_hashtable) | Ot.Rft_variant { Ot.v_name; _ } -> (match module_prefix with - | None -> v_name - | Some module_prefix -> module_prefix ^ "." ^ v_name) + | None -> v_name ^ " option" + | Some module_prefix -> module_prefix ^ "." ^ v_name ^ " option") (** [function_name_of_user_defined prefix user_defined] returns the function name of the form `(module'.'?)prefix_(type_name)`. diff --git a/src/examples/oneof.ml.expected b/src/examples/oneof.ml.expected index 1852ad79..ec600fde 100644 --- a/src/examples/oneof.ml.expected +++ b/src/examples/oneof.ml.expected @@ -14,7 +14,7 @@ type patch_op = | Insert_op of patch_insert and patch = { - op : patch_op; + op : patch_op option; id : int64; } @@ -39,7 +39,7 @@ let rec default_patch_insert let rec default_patch_op () : patch_op = Copy_op (default_patch_copy ()) and default_patch - ?op:((op:patch_op) = Copy_op (default_patch_copy ())) + ?op:((op:patch_op option) = None) ?id:((id:int64) = 0L) () : patch = { op; @@ -71,12 +71,12 @@ let default_patch_insert_mutable () : patch_insert_mutable = { } type patch_mutable = { - mutable op : patch_op; + mutable op : patch_op option; mutable id : int64; } let default_patch_mutable () : patch_mutable = { - op = Copy_op (default_patch_copy ()); + op = None; id = 0L; } @@ -112,7 +112,7 @@ let rec pp_patch_op fmt (v:patch_op) = and pp_patch fmt (v:patch) = let pp_i fmt () = - Pbrt.Pp.pp_record_field ~first:true "op" pp_patch_op fmt v.op; + Pbrt.Pp.pp_record_field ~first:true "op" (Pbrt.Pp.pp_option pp_patch_op) fmt v.op; Pbrt.Pp.pp_record_field ~first:false "id" Pbrt.Pp.pp_int64 fmt v.id; in Pbrt.Pp.pp_brk pp_i fmt () @@ -151,12 +151,13 @@ let rec encode_pb_patch_op (v:patch_op) encoder = and encode_pb_patch (v:patch) encoder = begin match v.op with - | Copy_op x -> + | Some Copy_op x -> Pbrt.Encoder.nested encode_pb_patch_copy x encoder; Pbrt.Encoder.key 3 Pbrt.Bytes encoder; - | Insert_op x -> + | Some Insert_op x -> Pbrt.Encoder.nested encode_pb_patch_insert x encoder; Pbrt.Encoder.key 4 Pbrt.Bytes encoder; + | None -> () end; Pbrt.Encoder.int64_as_varint v.id encoder; Pbrt.Encoder.key 5 Pbrt.Varint encoder; @@ -238,12 +239,12 @@ and decode_pb_patch d = | None -> ( ); continue__ := false | Some (3, Pbrt.Bytes) -> begin - v.op <- Copy_op (decode_pb_patch_copy (Pbrt.Decoder.nested d)); + v.op <- Some (Copy_op (decode_pb_patch_copy (Pbrt.Decoder.nested d))); end | Some (3, pk) -> Pbrt.Decoder.unexpected_payload "Message(patch), field(3)" pk | Some (4, Pbrt.Bytes) -> begin - v.op <- Insert_op (decode_pb_patch_insert (Pbrt.Decoder.nested d)); + v.op <- Some (Insert_op (decode_pb_patch_insert (Pbrt.Decoder.nested d))); end | Some (4, pk) -> Pbrt.Decoder.unexpected_payload "Message(patch), field(4)" pk @@ -302,10 +303,11 @@ let rec encode_json_patch_op (v:patch_op) = and encode_json_patch (v:patch) = let assoc = [] in let assoc = match v.op with - | Copy_op v -> + | Some (Copy_op v) -> ("copyOp", encode_json_patch_copy v) :: assoc - | Insert_op v -> + | Some (Insert_op v) -> ("insertOp", encode_json_patch_insert v) :: assoc + | None -> assoc in (* match v.op *) let assoc = ("id", Pbrt_yojson.make_string (Int64.to_string v.id)) :: assoc in `Assoc assoc @@ -381,9 +383,9 @@ and decode_json_patch d = in List.iter (function | ("copyOp", json_value) -> - v.op <- Copy_op ((decode_json_patch_copy json_value)) + v.op <- Some (Copy_op ((decode_json_patch_copy json_value))) | ("insertOp", json_value) -> - v.op <- Insert_op ((decode_json_patch_insert json_value)) + v.op <- Some (Insert_op ((decode_json_patch_insert json_value))) | ("id", json_value) -> v.id <- Pbrt_yojson.int64 json_value "patch" "id" diff --git a/src/examples/oneof.mli.expected b/src/examples/oneof.mli.expected index 4b48e3ac..b7037350 100644 --- a/src/examples/oneof.mli.expected +++ b/src/examples/oneof.mli.expected @@ -21,7 +21,7 @@ type patch_op = | Insert_op of patch_insert and patch = { - op : patch_op; + op : patch_op option; id : int64; } @@ -49,7 +49,7 @@ val default_patch_op : unit -> patch_op (** [default_patch_op ()] is the default value for type [patch_op] *) val default_patch : - ?op:patch_op -> + ?op:patch_op option -> ?id:int64 -> unit -> patch diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index d36a0f95..3e1a3439 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -21,7 +21,7 @@ and person = { name : string; home : person_location option; picture : bytes; - id : person_id; + id : person_id option; } let rec default_payment_system () = (Cash:payment_system) @@ -42,7 +42,7 @@ and default_person ?name:((name:string) = "") ?home:((home:person_location option) = None) ?picture:((picture:bytes) = Bytes.create 0) - ?id:((id:person_id) = X ("")) + ?id:((id:person_id option) = None) () : person = { id; email; From 29a8921fc7edf3e78b78177eceee4bb6d7231021 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Fri, 19 Jan 2024 14:30:15 +0400 Subject: [PATCH 03/47] Drop special-casing for messages with only oneof Now oneofs there are also properly encoded as options --- src/compilerlib/pb_codegen_backend.ml | 15 --------------- src/examples/example03.ml.expected | 22 +++++++++++++++++++--- src/examples/example03.mli.expected | 17 +++++++++++++++-- src/examples/example04.ml.expected | 22 +++++++++++++++++++--- src/examples/example04.mli.expected | 17 +++++++++++++++-- 5 files changed, 68 insertions(+), 25 deletions(-) diff --git a/src/compilerlib/pb_codegen_backend.ml b/src/compilerlib/pb_codegen_backend.ml index 14194ced..81a721e2 100644 --- a/src/compilerlib/pb_codegen_backend.ml +++ b/src/compilerlib/pb_codegen_backend.ml @@ -411,21 +411,6 @@ let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) } in [ type_ ] - | Tt.Message_oneof_field f :: [] -> - let outer_message_names = message_names @ [ message_name ] in - let variant = - variant_of_oneof ~unsigned_tag ~outer_message_names ~all_types - file_options file_name f - in - [ - Ot. - { - module_prefix; - spec = Variant variant; - type_level_ppx_extension; - type_options = message_options; - }; - ] | _ -> let variants, fields = List.fold_left diff --git a/src/examples/example03.ml.expected b/src/examples/example03.ml.expected index 24f42961..5b8cc697 100644 --- a/src/examples/example03.ml.expected +++ b/src/examples/example03.ml.expected @@ -2,13 +2,23 @@ type string_some_none = unit -type string_some = +type string_some_t = | None | Some of string +and string_some = { + t : string_some_t option; +} + let rec default_string_some_none = () -let rec default_string_some (): string_some = None +let rec default_string_some_t (): string_some_t = None + +and default_string_some + ?t:((t:string_some_t option) = None) + () : string_some = { + t; +} [@@@ocaml.warning "-27-30-39"] @@ -20,7 +30,13 @@ let rec pp_string_some_none fmt (v:string_some_none) = in Pbrt.Pp.pp_brk pp_i fmt () -let rec pp_string_some fmt (v:string_some) = +let rec pp_string_some_t fmt (v:string_some_t) = match v with | None -> Format.fprintf fmt "None" | Some x -> Format.fprintf fmt "@[Some(@,%a)@]" Pbrt.Pp.pp_string x + +and pp_string_some fmt (v:string_some) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "t" (Pbrt.Pp.pp_option pp_string_some_t) fmt v.t; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/examples/example03.mli.expected b/src/examples/example03.mli.expected index 6911af79..ffee5707 100644 --- a/src/examples/example03.mli.expected +++ b/src/examples/example03.mli.expected @@ -9,17 +9,27 @@ type string_some_none = unit -type string_some = +type string_some_t = | None | Some of string +and string_some = { + t : string_some_t option; +} + (** {2 Basic values} *) val default_string_some_none : unit (** [default_string_some_none ()] is the default value for type [string_some_none] *) -val default_string_some : unit -> string_some +val default_string_some_t : unit -> string_some_t +(** [default_string_some_t ()] is the default value for type [string_some_t] *) + +val default_string_some : + ?t:string_some_t option -> + unit -> + string_some (** [default_string_some ()] is the default value for type [string_some] *) @@ -28,5 +38,8 @@ val default_string_some : unit -> string_some val pp_string_some_none : Format.formatter -> string_some_none -> unit (** [pp_string_some_none v] formats v *) +val pp_string_some_t : Format.formatter -> string_some_t -> unit +(** [pp_string_some_t v] formats v *) + val pp_string_some : Format.formatter -> string_some -> unit (** [pp_string_some v] formats v *) diff --git a/src/examples/example04.ml.expected b/src/examples/example04.ml.expected index 0f9f6b90..ee2b3158 100644 --- a/src/examples/example04.ml.expected +++ b/src/examples/example04.ml.expected @@ -7,10 +7,14 @@ type int_list_cons = { next : int_list; } -and int_list = +and int_list_t = | Cons of int_list_cons | Nil +and int_list = { + t : int_list_t option; +} + let rec default_int_list_nil = () let rec default_int_list_cons @@ -21,7 +25,13 @@ let rec default_int_list_cons next; } -and default_int_list () : int_list = Cons (default_int_list_cons ()) +and default_int_list_t () : int_list_t = Cons (default_int_list_cons ()) + +and default_int_list + ?t:((t:int_list_t option) = None) + () : int_list = { + t; +} [@@@ocaml.warning "-27-30-39"] @@ -40,7 +50,13 @@ let rec pp_int_list_cons fmt (v:int_list_cons) = in Pbrt.Pp.pp_brk pp_i fmt () -and pp_int_list fmt (v:int_list) = +and pp_int_list_t fmt (v:int_list_t) = match v with | Cons x -> Format.fprintf fmt "@[Cons(@,%a)@]" pp_int_list_cons x | Nil -> Format.fprintf fmt "Nil" + +and pp_int_list fmt (v:int_list) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "t" (Pbrt.Pp.pp_option pp_int_list_t) fmt v.t; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/examples/example04.mli.expected b/src/examples/example04.mli.expected index 1b65cb51..71dd0192 100644 --- a/src/examples/example04.mli.expected +++ b/src/examples/example04.mli.expected @@ -14,10 +14,14 @@ type int_list_cons = { next : int_list; } -and int_list = +and int_list_t = | Cons of int_list_cons | Nil +and int_list = { + t : int_list_t option; +} + (** {2 Basic values} *) @@ -31,7 +35,13 @@ val default_int_list_cons : int_list_cons (** [default_int_list_cons ()] is the default value for type [int_list_cons] *) -val default_int_list : unit -> int_list +val default_int_list_t : unit -> int_list_t +(** [default_int_list_t ()] is the default value for type [int_list_t] *) + +val default_int_list : + ?t:int_list_t option -> + unit -> + int_list (** [default_int_list ()] is the default value for type [int_list] *) @@ -43,5 +53,8 @@ val pp_int_list_nil : Format.formatter -> int_list_nil -> unit val pp_int_list_cons : Format.formatter -> int_list_cons -> unit (** [pp_int_list_cons v] formats v *) +val pp_int_list_t : Format.formatter -> int_list_t -> unit +(** [pp_int_list_t v] formats v *) + val pp_int_list : Format.formatter -> int_list -> unit (** [pp_int_list v] formats v *) From ed08a325903e452e56265890bd9bf73dc65fbadd Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 29 Jan 2024 10:21:27 -0500 Subject: [PATCH 04/47] enable CI --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 36cb9613..4fe09b3e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,6 +3,7 @@ on: push: branches: - master + - br-4.0 pull_request: jobs: run: From 90c7c06192a0715d510e265372ec8acbccd22c72 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sat, 10 Feb 2024 12:10:24 -0500 Subject: [PATCH 05/47] format check in ci (#237) format + check for formatting in CI --- .github/workflows/main.yml | 10 ++- benchs/bin/dune | 1 - benchs/dune | 5 +- src/compilerlib/pb_codegen_decode_bs.mli | 1 - src/compilerlib/pb_codegen_decode_yojson.ml | 82 ++++++++++----------- src/compilerlib/pb_codegen_encode_binary.ml | 2 +- src/compilerlib/pb_codegen_encode_yojson.ml | 64 +++++++--------- src/compilerlib/pb_format_util.ml | 1 - src/dune | 4 +- src/examples/dune | 13 +--- src/ocaml-protoc/dune | 4 +- src/runtime-services/dune | 1 - src/runtime-yojson/dune | 9 ++- src/runtime/dune | 5 +- src/tests/benchmark/dune | 3 +- src/tests/expectation/tests.ml | 2 +- src/tests/google_unittest/dune | 26 ++++--- src/tests/integration-tests/dune | 38 +++++----- src/tests/unit-tests/dune | 5 +- src/tests/yojson/dune | 17 +++-- src/tests/yojson/yojson/dune | 7 +- src/tests/yojson/yojson/unit_tests.ml | 1 - 22 files changed, 147 insertions(+), 154 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4fe09b3e..773324e0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,8 +15,9 @@ jobs: #- macos-latest #- windows-latest ocaml-compiler: - - 4.08.x - - 4.12.x + - '4.08' + - '4.14' + - '5.1' runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 @@ -25,6 +26,8 @@ jobs: - uses: ocaml/setup-ocaml@v2 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} + allow-prerelease-opam: true + dune-cache: true #- run: sudo apt install protobuf-compiler libprotobuf-dev - run: opam pin -n . - run: opam depext -yt ocaml-protoc @@ -32,3 +35,6 @@ jobs: - run: opam exec -- dune build @install - run: opam exec -- dune runtest #- run: opam exec -- make integration + - run: opam install ocamlformat.0.24.1 + - run: opam exec -- dune build @fmt --auto-promote + - run: git diff -q diff --git a/benchs/bin/dune b/benchs/bin/dune index c3173dd5..9fb9214d 100644 --- a/benchs/bin/dune +++ b/benchs/bin/dune @@ -1,4 +1,3 @@ - (executable (name run) (ocamlopt_flags :standard -inline 100) diff --git a/benchs/dune b/benchs/dune index 207e4ef7..b710d38b 100644 --- a/benchs/dune +++ b/benchs/dune @@ -1,7 +1,10 @@ (executable (name benchs) (ocamlopt_flags :standard -inline 100) - (foreign_stubs (language c) (flags :standard -std=c99 -O2) (names stubs)) + (foreign_stubs + (language c) + (flags :standard -std=c99 -O2) + (names stubs)) (libraries ocaml-protoc benchmark)) (rule diff --git a/src/compilerlib/pb_codegen_decode_bs.mli b/src/compilerlib/pb_codegen_decode_bs.mli index 7c0a8a1c..3aa642c1 100644 --- a/src/compilerlib/pb_codegen_decode_bs.mli +++ b/src/compilerlib/pb_codegen_decode_bs.mli @@ -1,4 +1,3 @@ - include Pb_codegen_plugin.S val plugin : Pb_codegen_plugin.t diff --git a/src/compilerlib/pb_codegen_decode_yojson.ml b/src/compilerlib/pb_codegen_decode_yojson.ml index 2092c169..58477c4e 100644 --- a/src/compilerlib/pb_codegen_decode_yojson.ml +++ b/src/compilerlib/pb_codegen_decode_yojson.ml @@ -25,7 +25,7 @@ let field_pattern_match ~r_name ~rf_label field_type = | Ot.Bt_bool -> decode "bool" | Ot.Bt_bytes -> decode "bytes" in - ("json_value", exp) + "json_value", exp | Ot.Ft_unit -> "json_value", sp "Pbrt_yojson.unit json_value \"%s\" \"%s\"" r_name rf_label (* TODO Wrapper: add similar one for wrapper type (with different @@ -103,44 +103,42 @@ let gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type = let json_label = Pb_codegen_util.camel_case_of_label rf_label in F.linep sc "| (\"%s\", `Assoc assoc) ->" json_label; F.sub_scope sc (fun sc -> - let value_name, value_exp = field_pattern_match ~r_name ~rf_label value_type in - let key_name = "key" in - let key_exp = - match key_type with - | Ot.Bt_string -> "key" - | Ot.Bt_int -> "(Int.of_string key)" - | Ot.Bt_int32 -> "(Int32.of_string key)" - | Ot.Bt_int64 -> "(Int64.of_string key)" - | Ot.Bt_uint32 -> "(`unsigned (Int32.of_string key))" - | Ot.Bt_uint64 -> "(`unsigned (Int64.of_string key))" - | Ot.Bt_bool -> "(Bool.of_string key)" - | Ot.Bt_float -> - Printf.eprintf "float cannot be used as a map key type"; - exit 1 - | Ot.Bt_bytes -> - Printf.eprintf "bytes cannot be used as a map key type"; - exit 1 - in - F.line sc "let assoc ="; - F.sub_scope sc (fun sc -> - F.line sc "assoc"; - F.linep sc "|> List.map (fun (%s, %s) -> (%s, %s)) " - key_name - value_name - key_exp - value_exp; - F.line sc "|> List.to_seq"; - (* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there - is a repeated key we take the last value associated with it. *) - F.line sc "|> Hashtbl.of_seq"); - F.line sc "in"; - let assoc_exp = - match assoc_type with - | Ot.At_hashtable -> "assoc" - | Ot.At_list -> "assoc |> Hashtbl.to_seq |> List.of_seq" - in - F.linep sc "v.%s <- %s" rf_label assoc_exp); -;; + let value_name, value_exp = + field_pattern_match ~r_name ~rf_label value_type + in + let key_name = "key" in + let key_exp = + match key_type with + | Ot.Bt_string -> "key" + | Ot.Bt_int -> "(Int.of_string key)" + | Ot.Bt_int32 -> "(Int32.of_string key)" + | Ot.Bt_int64 -> "(Int64.of_string key)" + | Ot.Bt_uint32 -> "(`unsigned (Int32.of_string key))" + | Ot.Bt_uint64 -> "(`unsigned (Int64.of_string key))" + | Ot.Bt_bool -> "(Bool.of_string key)" + | Ot.Bt_float -> + Printf.eprintf "float cannot be used as a map key type"; + exit 1 + | Ot.Bt_bytes -> + Printf.eprintf "bytes cannot be used as a map key type"; + exit 1 + in + F.line sc "let assoc ="; + F.sub_scope sc (fun sc -> + F.line sc "assoc"; + F.linep sc "|> List.map (fun (%s, %s) -> (%s, %s)) " key_name + value_name key_exp value_exp; + F.line sc "|> List.to_seq"; + (* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there + is a repeated key we take the last value associated with it. *) + F.line sc "|> Hashtbl.of_seq"); + F.line sc "in"; + let assoc_exp = + match assoc_type with + | Ot.At_hashtable -> "assoc" + | Ot.At_list -> "assoc |> Hashtbl.to_seq |> List.of_seq" + in + F.linep sc "v.%s <- %s" rf_label assoc_exp) (* Generate decode function for a record *) let gen_record ?and_ { Ot.r_name; r_fields } sc = @@ -174,8 +172,10 @@ let gen_record ?and_ { Ot.r_name; r_fields } sc = | Ot.Rft_required _ -> Printf.eprintf "Only proto3 syntax supported in JSON encoding"; exit 1 - | Ot.Rft_associative (assoc_type, _, (key_type, _), (value_type, _)) -> - gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type) + | Ot.Rft_associative + (assoc_type, _, (key_type, _), (value_type, _)) -> + gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type + ~value_type) r_fields; (* Unknown fields are simply ignored *) diff --git a/src/compilerlib/pb_codegen_encode_binary.ml b/src/compilerlib/pb_codegen_encode_binary.ml index 3e61409a..4d6e8e81 100644 --- a/src/compilerlib/pb_codegen_encode_binary.ml +++ b/src/compilerlib/pb_codegen_encode_binary.ml @@ -155,7 +155,7 @@ let gen_rft_variant sc var_name { Ot.v_constructors; _ } = gen_encode_field_type sc ~with_key:true "x" vc_encoding_number vc_payload_kind false field_type)) v_constructors; - F.line sc "| None -> ()"; + F.line sc "| None -> ()"; F.line sc "end;" let gen_rft_associative sc var_name associative_field = diff --git a/src/compilerlib/pb_codegen_encode_yojson.ml b/src/compilerlib/pb_codegen_encode_yojson.ml index 25ecce40..4fc51d52 100644 --- a/src/compilerlib/pb_codegen_encode_yojson.ml +++ b/src/compilerlib/pb_codegen_encode_yojson.ml @@ -149,13 +149,8 @@ let gen_rft_variant sc rf_label { Ot.v_constructors; _ } = F.linep sc "in (* match v.%s *)" rf_label -let gen_rft_assoc - sc - ~rf_label - ~assoc_type - ~key_type - ~value_field:(value_type, value_pk) - = +let gen_rft_assoc sc ~rf_label ~assoc_type ~key_type + ~value_field:(value_type, value_pk) = let var_name = sp "v.%s" rf_label in let json_label = Pb_codegen_util.camel_case_of_label rf_label in let key_pat, key_exp = @@ -177,44 +172,41 @@ let gen_rft_assoc let write_assoc_field ~fn ~var_name = F.line sc "let assoc_field ="; F.sub_scope sc (fun sc -> - F.linep sc "%s" var_name; - (match assoc_type with - | Ot.At_list -> () - | Ot.At_hashtable -> - F.line sc "|> Hashtbl.to_seq |> List.of_seq"); - F.linep sc "|> List.map (fun (%s, value) -> %s, %s value)" key_pat key_exp fn); - F.line sc "in"; + F.linep sc "%s" var_name; + (match assoc_type with + | Ot.At_list -> () + | Ot.At_hashtable -> F.line sc "|> Hashtbl.to_seq |> List.of_seq"); + F.linep sc "|> List.map (fun (%s, value) -> %s, %s value)" key_pat + key_exp fn); + F.line sc "in" in F.line sc "let assoc ="; F.sub_scope sc (fun sc -> - (match value_type with - | Ot.Ft_unit -> unsupported json_label - | Ot.Ft_basic_type basic_type -> - let runtime_f, map_function = - runtime_function_for_basic_type json_label basic_type value_pk - in - (match map_function with + (match value_type with + | Ot.Ft_unit -> unsupported json_label + | Ot.Ft_basic_type basic_type -> + let runtime_f, map_function = + runtime_function_for_basic_type json_label basic_type value_pk + in + (match map_function with | None -> write_assoc_field ~fn:("Pbrt_yojson." ^ runtime_f) ~var_name | Some map_function -> let fn = - Printf.sprintf - "(fun value -> value |> %s |> Pbrt_yojson.%s)" - map_function - runtime_f + Printf.sprintf "(fun value -> value |> %s |> Pbrt_yojson.%s)" + map_function runtime_f in write_assoc_field ~fn ~var_name) - (* TODO Wrapper: add similar case for Ft_wrapper_type *) - (* User defined *) - | Ot.Ft_user_defined_type udt -> - let fn = - let function_prefix = "encode_json" in - Pb_codegen_util.function_name_of_user_defined ~function_prefix udt - in - write_assoc_field ~fn ~var_name; - | _ -> unsupported json_label); - F.linep sc "(\"%s\", `Assoc assoc_field) :: assoc " json_label); + (* TODO Wrapper: add similar case for Ft_wrapper_type *) + (* User defined *) + | Ot.Ft_user_defined_type udt -> + let fn = + let function_prefix = "encode_json" in + Pb_codegen_util.function_name_of_user_defined ~function_prefix udt + in + write_assoc_field ~fn ~var_name + | _ -> unsupported json_label); + F.linep sc "(\"%s\", `Assoc assoc_field) :: assoc " json_label); F.line sc "in" -;; let gen_record ?and_ { Ot.r_name; r_fields } sc = let rn = r_name in diff --git a/src/compilerlib/pb_format_util.ml b/src/compilerlib/pb_format_util.ml index 78381fff..0c2a6885 100644 --- a/src/compilerlib/pb_format_util.ml +++ b/src/compilerlib/pb_format_util.ml @@ -1,6 +1,5 @@ open Format - (* Not available in 4.03 *) let pp_print_option ?(none = fun _ () -> ()) pp_v ppf = function | None -> none ppf () diff --git a/src/dune b/src/dune index f6dc452c..cc26033e 100644 --- a/src/dune +++ b/src/dune @@ -1,3 +1,3 @@ - (env - (_ (flags :standard -warn-error -a+8 -w +a-4-40-41-42-44-48-70))) + (_ + (flags :standard -warn-error -a+8 -w +a-4-40-41-42-44-48-70))) diff --git a/src/examples/dune b/src/examples/dune index 24d338af..7f33cbb5 100644 --- a/src/examples/dune +++ b/src/examples/dune @@ -119,14 +119,5 @@ (action (with-stdout-to dune.inc.gen - (run - %{gen-dune} - build_server - calculator - example01 - example03 - example04 - example05 - file_server - orgchart - oneof)))) + (run %{gen-dune} build_server calculator example01 example03 example04 + example05 file_server orgchart oneof)))) diff --git a/src/ocaml-protoc/dune b/src/ocaml-protoc/dune index 7204b55e..7c12257f 100644 --- a/src/ocaml-protoc/dune +++ b/src/ocaml-protoc/dune @@ -16,5 +16,5 @@ (re_export pbrt))) (documentation - (package ocaml-protoc) - (mld_files index)) + (package ocaml-protoc) + (mld_files index)) diff --git a/src/runtime-services/dune b/src/runtime-services/dune index 77e192ed..44170aab 100644 --- a/src/runtime-services/dune +++ b/src/runtime-services/dune @@ -1,4 +1,3 @@ - (library (name pbrt_services) (public_name pbrt_services) diff --git a/src/runtime-yojson/dune b/src/runtime-yojson/dune index c7e629dc..26710039 100644 --- a/src/runtime-yojson/dune +++ b/src/runtime-yojson/dune @@ -1,5 +1,6 @@ - (library - (public_name pbrt_yojson) - (wrapped false) - (libraries (re_export yojson) base64)) + (public_name pbrt_yojson) + (wrapped false) + (libraries + (re_export yojson) + base64)) diff --git a/src/runtime/dune b/src/runtime/dune index e79ebbf9..dbb53caa 100644 --- a/src/runtime/dune +++ b/src/runtime/dune @@ -2,7 +2,10 @@ (name pbrt) (public_name pbrt) (synopsis "Runtime library for ocaml-protoc") - (foreign_stubs (language c) (flags :standard -std=c99 -O2) (names stubs)) + (foreign_stubs + (language c) + (flags :standard -std=c99 -O2) + (names stubs)) ; we need to increase -inline, so that the varint encoder/decoder can ; be remembered by the inliner. (ocamlopt_flags :standard -inline 100)) diff --git a/src/tests/benchmark/dune b/src/tests/benchmark/dune index b52ecb90..e37b4e70 100644 --- a/src/tests/benchmark/dune +++ b/src/tests/benchmark/dune @@ -6,6 +6,5 @@ (executable (name benchmark_single_ml) - (modules benchmark_single_ml ocaml_test_types ocaml_test_runner - benchmark) + (modules benchmark_single_ml ocaml_test_types ocaml_test_runner benchmark) (libraries pbrt unix)) diff --git a/src/tests/expectation/tests.ml b/src/tests/expectation/tests.ml index f0cec1ce..d2875fd6 100644 --- a/src/tests/expectation/tests.ml +++ b/src/tests/expectation/tests.ml @@ -225,7 +225,7 @@ let test_cases = rpc GetShelfWithSemicolon (GetShelfRequest) returns (GetShelfResponse) {}; } - |} + |}; ] let () = List.iter run test_cases diff --git a/src/tests/google_unittest/dune b/src/tests/google_unittest/dune index 17582bdc..7cd6c25a 100644 --- a/src/tests/google_unittest/dune +++ b/src/tests/google_unittest/dune @@ -1,16 +1,20 @@ (test - (name google_unittest) - (flags :standard -w -11) - (package ocaml-protoc) - (libraries pbrt)) + (name google_unittest) + (flags :standard -w -11) + (package ocaml-protoc) + (libraries pbrt)) (rule - (targets unittest.ml unittest.mli) - (deps (:file unittest.proto) unittest_import.proto) - (action (run ocaml-protoc --ml_out . -I . %{file}))) + (targets unittest.ml unittest.mli) + (deps + (:file unittest.proto) + unittest_import.proto) + (action + (run ocaml-protoc --ml_out . -I . %{file}))) (rule - (targets unittest_import.ml unittest_import.mli) - (deps (:file unittest_import.proto)) - (action (run ocaml-protoc --ml_out . -I . %{file}))) - + (targets unittest_import.ml unittest_import.mli) + (deps + (:file unittest_import.proto)) + (action + (run ocaml-protoc --ml_out . -I . %{file}))) diff --git a/src/tests/integration-tests/dune b/src/tests/integration-tests/dune index dee780fc..344669d2 100644 --- a/src/tests/integration-tests/dune +++ b/src/tests/integration-tests/dune @@ -8,9 +8,9 @@ (targets test01.ml test01.mli) (deps test01.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ./ -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ocaml_all_types_ppx "deriving show" --ml_out ./ ./ - test01.proto))) + (run ocaml-protoc -I ./ -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ocaml_all_types_ppx + "deriving show" --ml_out ./ ./ test01.proto))) (executable (name test01_ml) @@ -161,8 +161,8 @@ (targets test15.ml test15.mli) (deps test15.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test15.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test15.proto))) (executable (name test15_ml) @@ -173,8 +173,8 @@ (targets test16.ml test16.mli) (deps test16.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test16.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test16.proto))) (executable (name test16_ml) @@ -185,8 +185,8 @@ (targets test17.ml test17.mli) (deps test17.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test17.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test17.proto))) (executable (name test17_ml) @@ -197,8 +197,8 @@ (targets test18.ml test18.mli) (deps test18.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test18.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test18.proto))) (executable (name test18_ml) @@ -209,8 +209,8 @@ (targets test19.ml test19.mli) (deps test19.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test19.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test19.proto))) (executable (name test19_ml) @@ -221,8 +221,8 @@ (targets test20.ml test20.mli) (deps test20.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test20.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test20.proto))) (executable (name test20_ml) @@ -235,8 +235,8 @@ (targets test21.ml test21.mli) (deps test21.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} - --binary --pp --ml_out ./ ./ test21.proto))) + (run ocaml-protoc -I ../../include/ocaml-protoc -I + %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test21.proto))) (executable (name test21_ml) @@ -293,8 +293,8 @@ (targets test26.ml test26.mli) (deps test26.proto ../../include/ocaml-protoc/ocamloptions.proto) (action - (run ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ - test26.proto))) + (run ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ + ./ test26.proto))) (executable (name test26_ml) diff --git a/src/tests/unit-tests/dune b/src/tests/unit-tests/dune index 0a110bdf..0583504b 100644 --- a/src/tests/unit-tests/dune +++ b/src/tests/unit-tests/dune @@ -2,8 +2,7 @@ (package ocaml-protoc) (names graph_test format_play_ground lexer_comment ocaml_codegen_test parse_enum pbtt_compile_p2 test_typing verify_syntax_invariants - parse_message parse_field_options - parse_file_options parse_import pbtt_compile_p1 backend_ocaml_test - pbrt_array wrapper_encoding varint) + parse_message parse_field_options parse_file_options parse_import + pbtt_compile_p1 backend_ocaml_test pbrt_array wrapper_encoding varint) (libraries pbrt ocaml-protoc.compiler-lib) (flags :standard -open Ocaml_protoc_compiler_lib)) diff --git a/src/tests/yojson/dune b/src/tests/yojson/dune index 9b34a351..a0f41639 100644 --- a/src/tests/yojson/dune +++ b/src/tests/yojson/dune @@ -1,11 +1,12 @@ - (test - (name yojson_unittest) - (package ocaml-protoc) - (libraries pbrt pbrt_yojson)) + (name yojson_unittest) + (package ocaml-protoc) + (libraries pbrt pbrt_yojson)) (rule - (targets yojson_unittest.ml yojson_unittest.mli) - (deps (:file yojson_unittest.proto)) - (action (run %{project_root}/src/ocaml-protoc/ocaml_protoc.exe - %{file} --yojson --ml_out=.))) + (targets yojson_unittest.ml yojson_unittest.mli) + (deps + (:file yojson_unittest.proto)) + (action + (run %{project_root}/src/ocaml-protoc/ocaml_protoc.exe %{file} --yojson + --ml_out=.))) diff --git a/src/tests/yojson/yojson/dune b/src/tests/yojson/yojson/dune index 03f6d94a..aa2c92a2 100644 --- a/src/tests/yojson/yojson/dune +++ b/src/tests/yojson/yojson/dune @@ -1,5 +1,4 @@ - (test - (name unit_tests) - (package pbrt_yojson) - (libraries yojson pbrt_yojson)) + (name unit_tests) + (package pbrt_yojson) + (libraries yojson pbrt_yojson)) diff --git a/src/tests/yojson/yojson/unit_tests.ml b/src/tests/yojson/yojson/unit_tests.ml index 4a7aaae8..c5ef64f9 100644 --- a/src/tests/yojson/yojson/unit_tests.ml +++ b/src/tests/yojson/yojson/unit_tests.ml @@ -14,4 +14,3 @@ let () = assert (true = bool (`Bool true) "r" "f"); assert (false = bool (`Bool false) "r" "f"); () - From b7a1bd71d2a723737a57ac7c0ca1c6f985d4939f Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Mon, 22 Jan 2024 16:49:32 +0400 Subject: [PATCH 06/47] Expose one-of per-constructor options --- src/compilerlib/pb_codegen_backend.ml | 1 + src/compilerlib/pb_codegen_decode_binary.ml | 2 ++ src/compilerlib/pb_codegen_encode_binary.ml | 2 ++ src/compilerlib/pb_codegen_ocaml_type.ml | 1 + src/compilerlib/pb_codegen_ocaml_type_dump.ml | 3 ++- src/tests/expectation/option_processing.ml.expected | 8 ++++++++ src/tests/expectation/option_processing.proto | 5 +++-- 7 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/compilerlib/pb_codegen_backend.ml b/src/compilerlib/pb_codegen_backend.ml index 81a721e2..512fe4a6 100644 --- a/src/compilerlib/pb_codegen_backend.ml +++ b/src/compilerlib/pb_codegen_backend.ml @@ -328,6 +328,7 @@ let variant_of_oneof ?include_oneof_name ~outer_message_names ~unsigned_tag (match field_type with | Ft_unit -> Vct_nullary | _ -> Vct_non_nullary_constructor field_type); + vc_options = field.field_options; }) oneof_field.Tt.oneof_fields in diff --git a/src/compilerlib/pb_codegen_decode_binary.ml b/src/compilerlib/pb_codegen_decode_binary.ml index b7d994b1..1257e065 100644 --- a/src/compilerlib/pb_codegen_decode_binary.ml +++ b/src/compilerlib/pb_codegen_decode_binary.ml @@ -161,6 +161,7 @@ let gen_rft_variant sc r_name rf_label { Ot.v_constructors; _ } = vc_field_type; vc_encoding_number; vc_payload_kind = pk; + vc_options = _; } = variant_constructor in @@ -281,6 +282,7 @@ let gen_variant ?and_ { Ot.v_name; v_constructors } sc = vc_field_type; vc_encoding_number; vc_payload_kind = pk; + vc_options = _; } = variant_constructor in diff --git a/src/compilerlib/pb_codegen_encode_binary.ml b/src/compilerlib/pb_codegen_encode_binary.ml index 4d6e8e81..1c3d0944 100644 --- a/src/compilerlib/pb_codegen_encode_binary.ml +++ b/src/compilerlib/pb_codegen_encode_binary.ml @@ -139,6 +139,7 @@ let gen_rft_variant sc var_name { Ot.v_constructors; _ } = vc_field_type; vc_encoding_number; vc_payload_kind; + vc_options = _; } = constructor in @@ -236,6 +237,7 @@ let gen_variant ?and_ variant sc = vc_field_type; vc_encoding_number; vc_payload_kind; + vc_options = _; } = variant_constructor in diff --git a/src/compilerlib/pb_codegen_ocaml_type.ml b/src/compilerlib/pb_codegen_ocaml_type.ml index 69328d4b..94ce45f2 100644 --- a/src/compilerlib/pb_codegen_ocaml_type.ml +++ b/src/compilerlib/pb_codegen_ocaml_type.ml @@ -106,6 +106,7 @@ and variant_constructor = { vc_field_type: variant_constructor_type; vc_encoding_number: encoding_number; vc_payload_kind: payload_kind; + vc_options: Pb_option.set; } and variant_constructor_type = diff --git a/src/compilerlib/pb_codegen_ocaml_type_dump.ml b/src/compilerlib/pb_codegen_ocaml_type_dump.ml index e12afdab..69af6314 100644 --- a/src/compilerlib/pb_codegen_ocaml_type_dump.ml +++ b/src/compilerlib/pb_codegen_ocaml_type_dump.ml @@ -170,7 +170,8 @@ module PP = struct F.linep sc " Field Type: %s\n" (string_of_variant_constructor_type vc.vc_field_type); F.linep sc " Encoding Number: %d, Payload Kind: %s" vc.vc_encoding_number - (string_of_payload_kind vc.vc_payload_kind) + (string_of_payload_kind vc.vc_payload_kind); + F.linep sc " Options: %s" (string_of_options vc.vc_options) (* Helper function to convert variant_constructor_type to string *) and string_of_variant_constructor_type vct = diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index 3e1a3439..f73716f4 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -14,6 +14,7 @@ type person_location = { type person_id = | X of string | Y of int32 + | Z of float and person = { id : int64; @@ -96,10 +97,17 @@ and default_person Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_string Encoding Number: 6, Payload Kind: Pk_bytes + Options: {"validate.rules.string.prefix": Constant_string "foo"} Constructor: Y Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_int32 Encoding Number: 7, Payload Kind: Pk_varint (zigzag: false) + Options: {"validate.rules.int32.gt": Constant_int 0} + Constructor: Z + Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_float + + Encoding Number: 8, Payload Kind: Pk_bits32 + Options: {} Options: {} *) diff --git a/src/tests/expectation/option_processing.proto b/src/tests/expectation/option_processing.proto index 15f96445..2247bfec 100644 --- a/src/tests/expectation/option_processing.proto +++ b/src/tests/expectation/option_processing.proto @@ -35,7 +35,8 @@ message Person { oneof id { option (validate.required) = true; - string x = 6; - int32 y = 7; + string x = 6 [(validate.rules).string.prefix = "foo"]; + int32 y = 7 [(validate.rules).int32.gt = 0]; + float z = 8; } } From 52d9ee7426f8165e62338f8f57fafce65f65544f Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Mon, 26 Feb 2024 11:10:53 +0400 Subject: [PATCH 07/47] Stop special-casing option parsing in field_option --- src/compilerlib/pb_parsing_parser.mly | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/compilerlib/pb_parsing_parser.mly b/src/compilerlib/pb_parsing_parser.mly index f130effa..4d8d6730 100644 --- a/src/compilerlib/pb_parsing_parser.mly +++ b/src/compilerlib/pb_parsing_parser.mly @@ -359,9 +359,7 @@ field_option_list : } field_option : - | T_ident T_equal option_value { (snd $1, $3) } - | T_lparen T_ident T_rparen T_equal option_value { (snd $2, $5)} - | T_lparen T_ident T_rparen T_ident T_equal option_value { ((snd $2) ^ (snd $4), $6)} + | option_identifier T_equal option_value { ($1, $3) } option_identifier_item : | T_ident {snd $1} From 2df18e9ceb467032e425376dc9779e12adf10333 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Mon, 26 Feb 2024 21:17:22 +0400 Subject: [PATCH 08/47] Use adequate types to represent option names See https://protobuf.com/docs/language-spec#option-names --- src/compilerlib/pb_codegen_all.ml | 2 +- src/compilerlib/pb_codegen_backend.ml | 23 +++--- src/compilerlib/pb_codegen_ocaml_type_dump.ml | 35 ++------- src/compilerlib/pb_option.ml | 32 +++++++- src/compilerlib/pb_option.mli | 12 ++- src/compilerlib/pb_parsing_parser.mly | 6 +- src/compilerlib/pb_parsing_util.ml | 17 +++- src/compilerlib/pb_parsing_util.mli | 2 + src/compilerlib/pb_typing_util.mli | 10 ++- src/compilerlib/pb_typing_validation.ml | 2 +- src/ocaml-protoc/ocaml_protoc_cmdline.ml | 12 +-- .../expectation/option_processing.ml.expected | 77 ++++++++++++++----- src/tests/expectation/tests.expected | 30 ++++---- src/tests/unit-tests/parse_field_options.ml | 8 +- src/tests/unit-tests/parse_file_options.ml | 8 +- 15 files changed, 176 insertions(+), 100 deletions(-) diff --git a/src/compilerlib/pb_codegen_all.ml b/src/compilerlib/pb_codegen_all.ml index 0a0de529..5dc77dbf 100644 --- a/src/compilerlib/pb_codegen_all.ml +++ b/src/compilerlib/pb_codegen_all.ml @@ -40,7 +40,7 @@ let new_ocaml_mod ~proto_file_options ~proto_file_name () : ocaml_mod = let self = { ml = F.empty_scope (); mli = F.empty_scope () } in let print_ppx sc = - match Pb_option.get proto_file_options "ocaml_file_ppx" with + match Pb_option.get_ext proto_file_options "ocaml_file_ppx" with | None -> () | Some Pb_option.(Scalar_value (Constant_string s)) -> F.linep sc "[@@@%s]" s diff --git a/src/compilerlib/pb_codegen_backend.ml b/src/compilerlib/pb_codegen_backend.ml index 512fe4a6..9be3a985 100644 --- a/src/compilerlib/pb_codegen_backend.ml +++ b/src/compilerlib/pb_codegen_backend.ml @@ -195,7 +195,7 @@ let encoding_info_of_field_type ~all_types field_type : Ot.payload_kind = let encoding_of_field ~all_types (field : (Pb_field_type.resolved, 'a) Tt.field) = let packed = - match Typing_util.field_option field "packed" with + match Typing_util.field_option field [ Pb_option.Simple_name "packed" ] with | Some Pb_option.(Scalar_value (Constant_bool x)) -> x | Some _ -> E.invalid_packed_option (Typing_util.field_name field) | None -> false @@ -209,34 +209,34 @@ let encoding_of_field ~all_types (field : (Pb_field_type.resolved, 'a) Tt.field) let compile_field_type ~unsigned_tag ~(all_types : _ Tt.proto_type list) file_options field_options file_name field_type : Ot.field_type = let ocaml_type = - match Pb_option.get field_options "ocaml_type" with + match Pb_option.get_ext field_options "ocaml_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> `Int_t | _ -> `None in let int32_type = - match Pb_option.get file_options "int32_type" with + match Pb_option.get_ext file_options "int32_type" with | Some Pb_option.(Scalar_value (Pb_option.Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_int32) in let uint32_type = - match Pb_option.get file_options "int32_type" with + match Pb_option.get_ext file_options "int32_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_uint32) in let int64_type = - match Pb_option.get file_options "int64_type" with + match Pb_option.get_ext file_options "int64_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_int64) in let uint64_type = - match Pb_option.get file_options "int64_type" with + match Pb_option.get_ext file_options "int64_type" with | Some Pb_option.(Scalar_value (Constant_literal "int_t")) -> Ot.(Ft_basic_type Bt_int) | _ -> Ot.(Ft_basic_type Bt_uint64) @@ -289,13 +289,13 @@ let compile_field_type ~unsigned_tag ~(all_types : _ Tt.proto_type list) | `User_defined id, _ -> user_defined_type_of_id ~all_types ~file_name id let is_mutable ?field_name field_options = - match Pb_option.get field_options "ocaml_mutable" with + match Pb_option.get_ext field_options "ocaml_mutable" with | Some Pb_option.(Scalar_value (Constant_bool v)) -> v | Some _ -> Pb_exception.invalid_mutable_option ?field_name () | None -> false let ocaml_container field_options = - match Pb_option.get field_options "ocaml_container" with + match Pb_option.get_ext field_options "ocaml_container" with | None -> None | Some Pb_option.(Scalar_value (Constant_literal container_name)) -> Some container_name @@ -371,7 +371,7 @@ let process_all_types_ppx_extension file_name file_options match type_level_ppx_extension with | Some x -> Some x | None -> - Pb_option.get file_options "ocaml_all_types_ppx" + Pb_option.get_ext file_options "ocaml_all_types_ppx" |> string_of_string_option file_name let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) @@ -388,7 +388,8 @@ let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) let { Tt.message_names; _ } = scope in let type_level_ppx_extension = - Typing_util.message_option message "ocaml_type_ppx" + Typing_util.message_option message + [ Pb_option.Extension_name "ocaml_type_ppx" ] |> string_of_string_option message_name |> process_all_types_ppx_extension file_name file_options in @@ -633,7 +634,7 @@ let compile_enum file_options file_name scope enum = in let type_level_ppx_extension = - Typing_util.enum_option enum "ocaml_enum_ppx" + Typing_util.enum_option enum [ Pb_option.Extension_name "ocaml_enum_ppx" ] |> string_of_string_option enum_name |> process_all_types_ppx_extension file_name file_options in diff --git a/src/compilerlib/pb_codegen_ocaml_type_dump.ml b/src/compilerlib/pb_codegen_ocaml_type_dump.ml index 69af6314..6b454069 100644 --- a/src/compilerlib/pb_codegen_ocaml_type_dump.ml +++ b/src/compilerlib/pb_codegen_ocaml_type_dump.ml @@ -74,29 +74,6 @@ module PP = struct | Constant_literal s -> Printf.sprintf "Constant_literal %S" (String.escaped s) - (* Helper function to convert value to string *) - let rec string_of_value value = - match value with - | Pb_option.Scalar_value c -> string_of_constant c - | Message_literal ml -> string_of_message_literal ml - | List_literal ll -> string_of_list_literal ll - - (* Helper function to convert message_literal to string *) - and string_of_message_literal ml = - "{" - ^ String.concat ", " - (List.map - (fun (k, v) -> Printf.sprintf "%S: %s" k (string_of_value v)) - ml) - ^ "}" - - (* Helper function to convert list_literal to string *) - and string_of_list_literal ll = - "[" ^ String.concat ", " (List.map string_of_value ll) ^ "]" - - (* Function to convert options (message_literal) to string *) - let string_of_options options = string_of_message_literal options - (* Helper function to convert default_value to string *) let string_of_default_value dv = match dv with @@ -171,7 +148,8 @@ module PP = struct (string_of_variant_constructor_type vc.vc_field_type); F.linep sc " Encoding Number: %d, Payload Kind: %s" vc.vc_encoding_number (string_of_payload_kind vc.vc_payload_kind); - F.linep sc " Options: %s" (string_of_options vc.vc_options) + F.linep sc " Options: %s" + (Format.asprintf "%a" Pb_option.pp_set vc.vc_options) (* Helper function to convert variant_constructor_type to string *) and string_of_variant_constructor_type vct = @@ -189,7 +167,8 @@ module PP = struct and print_record_field sc record_field = F.linep sc "- Field: %s" record_field.rf_label; print_record_field_type sc record_field.rf_field_type; - F.linep sc " Field options: %s" (string_of_options record_field.rf_options) + F.linep sc " Field options: %s" + (Format.asprintf "%a" Pb_option.pp_set record_field.rf_options) (* Recursive function to print a const_variant *) let rec print_const_variant sc const_variant = @@ -201,7 +180,8 @@ module PP = struct F.linep sc " Constructor: %s" cvc.cvc_name; F.linep sc " Binary Value: %d, String Value: %s" cvc.cvc_binary_value cvc.cvc_string_value; - F.linep sc " Options: %s" (string_of_options cvc.cvc_options) + F.linep sc " Options: %s" + (Format.asprintf "%a" Pb_option.pp_set cvc.cvc_options) (* Recursive function to print the type_spec *) let print_type_spec sc type_spec = @@ -215,7 +195,8 @@ module PP = struct let print_type sc type_ = F.linep sc "Module Prefix: %s" type_.module_prefix; print_type_spec sc type_.spec; - F.linep sc "Options: %s" (string_of_options type_.type_options); + F.linep sc "Options: %s" + (Format.asprintf "%a" Pb_option.pp_set type_.type_options); match type_.type_level_ppx_extension with | Some ext -> F.linep sc "PPX Extension: %s" ext | None -> () diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index f4403a45..190a230a 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -5,6 +5,12 @@ type constant = | Constant_float of float | Constant_literal of string +type name_part = + | Simple_name of string + | Extension_name of string + +type option_name = name_part list + type message_literal = (string * value) list and list_literal = value list @@ -13,19 +19,35 @@ and value = | Message_literal of message_literal | List_literal of list_literal -type option_name = string type t = option_name * value type set = t list +let name_part_to_string = function + | Simple_name s -> s + | Extension_name s -> "(" ^ s ^ ")" + +let stringify_option_name (option_name : option_name) : string = + let str_list = List.map name_part_to_string option_name in + String.concat "." str_list + +let name_part_equal a b = + match a, b with + | Simple_name a, Simple_name b -> String.equal a b + | Extension_name a, Extension_name b -> String.equal a b + | _ -> false + +let option_name_equal a b = List.equal name_part_equal a b let empty = [] let add t option_name value = (option_name, value) :: t let merge t1 t2 = t2 @ t1 let get t option_name = - match List.assoc option_name t with - | c -> Some c + match List.find (fun (other, _) -> option_name_equal option_name other) t with + | _, c -> Some c | exception Not_found -> None +let get_ext t option_name = get t [ Extension_name option_name ] + let pp_constant ppf = function | Constant_string s -> Format.fprintf ppf "%S" s | Constant_bool b -> Format.fprintf ppf "%B" b @@ -56,7 +78,9 @@ and pp_message_field ppf (field, value) = Format.fprintf ppf "%S: %a" field pp_value value let pp_t ppf (name, value) = - Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" name pp_value value + Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" + (stringify_option_name name) + pp_value value let pp_set ppf set = Format.fprintf ppf "[@[%a@]]" diff --git a/src/compilerlib/pb_option.mli b/src/compilerlib/pb_option.mli index ee9c5afc..95390b09 100644 --- a/src/compilerlib/pb_option.mli +++ b/src/compilerlib/pb_option.mli @@ -18,7 +18,11 @@ and value = | Message_literal of message_literal | List_literal of list_literal -type option_name = string +type name_part = + | Simple_name of string + | Extension_name of string + +type option_name = name_part list (** Option identifier *) type t = option_name * value @@ -28,14 +32,16 @@ type set = t list Can be used for field/message or file options *) +val stringify_option_name : option_name -> string val empty : set -val add : set -> string -> value -> set +val add : set -> option_name -> value -> set val merge : set -> set -> set (** [merge s1 s2] adds all the options from [s2] to [s1]. This means than in case of duplicates [s2] options will override [s1] options. *) -val get : set -> string -> value option +val get : set -> option_name -> value option +val get_ext : set -> string -> value option val pp_constant : Format.formatter -> constant -> unit val pp_value : Format.formatter -> value -> unit val pp_message_literal : Format.formatter -> message_literal -> unit diff --git a/src/compilerlib/pb_parsing_parser.mly b/src/compilerlib/pb_parsing_parser.mly index 4d8d6730..326db322 100644 --- a/src/compilerlib/pb_parsing_parser.mly +++ b/src/compilerlib/pb_parsing_parser.mly @@ -362,12 +362,12 @@ field_option : | option_identifier T_equal option_value { ($1, $3) } option_identifier_item : - | T_ident {snd $1} - | T_lparen T_ident T_rparen {snd $2} + | T_ident {snd $1 |> Pb_parsing_util.option_name_of_ident} + | T_lparen T_ident T_rparen {snd $2 |> Pb_parsing_util.option_name_extension} option_identifier : | option_identifier_item {$1} - | option_identifier T_ident {$1 ^ (snd $2)} + | option_identifier_item option_identifier {$1 @ $2} option : | T_option option_identifier T_equal option_value semicolon { ($2, $4) } diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index 3ed8463e..a63a511c 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -128,6 +128,18 @@ let rpc ?(options = Pb_option.empty) ~req_stream ~req ~res_stream ~res rpc_name let option_map items = Pb_option.Message_literal items let option_list items = Pb_option.List_literal items + +let option_name_of_ident ident = + let ident = + if String.starts_with ~prefix:"." ident then + String.sub ident 1 (String.length ident - 1) + else + ident + in + ident |> String.split_on_char '.' + |> List.map (fun x -> Pb_option.Simple_name x) + +let option_name_extension ident = [ Pb_option.Extension_name ident ] let service ~content service_name = Pt.{ service_name; service_body = content } let import ?public file_name = @@ -275,7 +287,7 @@ let finalize_syntax3 proto = in messages. Optional is now allowed, but default values might not be. *) let verify_no_default_field_options field_name message_name field_options = - match Pb_option.get field_options "default" with + match Pb_option.get field_options [ Pb_option.Simple_name "default" ] with | None -> () | Some _ -> E.default_field_option_not_supported ~field_name ~message_name in @@ -316,7 +328,8 @@ let finalize_syntax3 proto = | `Bool -> let field_options = Pb_option.( - add field_options "packed" + add field_options + [ Pb_option.Simple_name "packed" ] (Scalar_value (Constant_bool true))) in { field with Pt.field_options } diff --git a/src/compilerlib/pb_parsing_util.mli b/src/compilerlib/pb_parsing_util.mli index f9bfdaa3..da1451e5 100644 --- a/src/compilerlib/pb_parsing_util.mli +++ b/src/compilerlib/pb_parsing_util.mli @@ -89,6 +89,8 @@ val rpc : val option_map : Pb_option.message_literal -> Pb_option.value val option_list : Pb_option.list_literal -> Pb_option.value +val option_name_of_ident : string -> Pb_option.option_name +val option_name_extension : string -> Pb_option.option_name val service_body_option : Pb_option.t -> Pt.service_body_content val service_body_rpc : Pt.rpc -> Pt.service_body_content val service : content:Pt.service_body_content list -> string -> Pt.service diff --git a/src/compilerlib/pb_typing_util.mli b/src/compilerlib/pb_typing_util.mli index 98724474..43d8ee26 100644 --- a/src/compilerlib/pb_typing_util.mli +++ b/src/compilerlib/pb_typing_util.mli @@ -50,7 +50,8 @@ val field_default : ('a, 'b) Tt.field -> Pb_option.constant option val field_options : ('a, 'b) Tt.field -> Pb_option.set -val field_option : ('a, 'b) Tt.field -> string -> Pb_option.value option +val field_option : + ('a, 'b) Tt.field -> Pb_option.option_name -> Pb_option.value option (** [field_option field option_name] returns the constant associated with [option_name]. If the fields options does not contain [option_name] [None] is returned. @@ -62,8 +63,11 @@ val type_of_id : 'a Tt.proto_type list -> int -> 'a Tt.proto_type *) val string_of_message : int -> Tt.type_scope -> 'a Tt.message -> string -val message_option : 'a Tt.message -> string -> Pb_option.value option -val enum_option : Tt.enum -> string -> Pb_option.value option + +val message_option : + 'a Tt.message -> Pb_option.option_name -> Pb_option.value option + +val enum_option : Tt.enum -> Pb_option.option_name -> Pb_option.value option (** {2 Accessor for Tt.type} *) diff --git a/src/compilerlib/pb_typing_validation.ml b/src/compilerlib/pb_typing_validation.ml index 1810b2c3..6f00ed31 100644 --- a/src/compilerlib/pb_typing_validation.ml +++ b/src/compilerlib/pb_typing_validation.ml @@ -37,7 +37,7 @@ let scope_of_package : string option -> Tt.type_scope = function | None -> Typing_util.empty_scope let get_default field_name field_options : Pb_option.constant option = - match Pb_option.get field_options "default" with + match Pb_option.get field_options [ Pb_option.Simple_name "default" ] with | Some (Pb_option.Scalar_value constant) -> Some constant | Some (Pb_option.Message_literal _) -> E.invalid_default_value ~field_name diff --git a/src/ocaml-protoc/ocaml_protoc_cmdline.ml b/src/ocaml-protoc/ocaml_protoc_cmdline.ml index 1f0a5e2a..5cc2ebaa 100644 --- a/src/ocaml-protoc/ocaml_protoc_cmdline.ml +++ b/src/ocaml-protoc/ocaml_protoc_cmdline.ml @@ -87,15 +87,17 @@ module File_options = struct let option_name, option_value = f x in Pb_option.add options option_name option_value in - Pb_option.empty + let open Pb_option in + empty |> map int32_type (fun s -> - "int32_type", Pb_option.(Scalar_value (Constant_literal s))) + [ Extension_name "int32_type" ], Scalar_value (Constant_literal s)) |> map int64_type (fun s -> - "int64_type", Pb_option.(Scalar_value (Constant_literal s))) + [ Extension_name "int64_type" ], Scalar_value (Constant_literal s)) |> map ocaml_file_ppx (fun s -> - "ocaml_file_ppx", Pb_option.(Scalar_value (Constant_string s))) + [ Extension_name "ocaml_file_ppx" ], Scalar_value (Constant_string s)) |> map ocaml_all_types_ppx (fun s -> - "ocaml_all_types_ppx", Pb_option.(Scalar_value (Constant_string s))) + ( [ Extension_name "ocaml_all_types_ppx" ], + Scalar_value (Constant_string s) )) end (** Command line argument for the ocaml-protoc *) diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index f73716f4..4a4cab46 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -63,17 +63,27 @@ and default_person Const Variant: payment_system Constructor: Cash Binary Value: 0, String Value: CASH - Options: {"label": Constant_string "Cash"} + Options: [{ + "(label)": "Cash" + }] Constructor: Credit_card Binary Value: 1, String Value: CREDIT_CARD - Options: {"label": Constant_string "Credit Card"} + Options: [{ + "(label)": "Credit Card" + }] Constructor: Debit_card Binary Value: 2, String Value: DEBIT_CARD - Options: {"label": Constant_string "Debit Card"} + Options: [{ + "(label)": "Debit Card" + }] Constructor: App Binary Value: 3, String Value: APP - Options: {"label": Constant_string "Mobile App"} - Options: {"label": Constant_string "Payment method"} + Options: [{ + "(label)": "Mobile App" + }] + Options: [{ + "(label)": "Payment method" + }] *) (* ----------------------------------------------------- *) @@ -82,11 +92,19 @@ and default_person Record: person_location - Field: lat Rft_nolabel (Field Type: Ft_basic_type: Bt_float, Encoding: 1, Payload Kind: Pk_bits64) - Field options: {"validate.rules.double": {"gte": Constant_int -90, "lte": Constant_int 90}} + Field options: [{ + "(validate.rules).double": {"gte": -90, + "lte": 90} + }] - Field: lng Rft_nolabel (Field Type: Ft_basic_type: Bt_float, Encoding: 2, Payload Kind: Pk_bits64) - Field options: {"validate.rules.double": {"gte": Constant_int -180, "lte": Constant_int 180}} - Options: {"validate.disabled": Constant_bool true} + Field options: [{ + "(validate.rules).double": {"gte": -180, + "lte": 180} + }] + Options: [{ + "(validate.disabled)": true + }] *) (* ----------------------------------------------------- *) @@ -97,18 +115,22 @@ and default_person Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_string Encoding Number: 6, Payload Kind: Pk_bytes - Options: {"validate.rules.string.prefix": Constant_string "foo"} + Options: [{ + "(validate.rules).string.prefix": "foo" + }] Constructor: Y Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_int32 Encoding Number: 7, Payload Kind: Pk_varint (zigzag: false) - Options: {"validate.rules.int32.gt": Constant_int 0} + Options: [{ + "(validate.rules).int32.gt": 0 + }] Constructor: Z Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_float Encoding Number: 8, Payload Kind: Pk_bits32 - Options: {} - Options: {} + Options: [] + Options: [] *) (* @@ -116,21 +138,38 @@ and default_person Record: person - Field: id Rft_nolabel (Field Type: Ft_basic_type: Bt_int64, Encoding: 1, Payload Kind: Pk_varint (zigzag: false)) - Field options: {"validate.rules.uint64.gt": Constant_int 999} + Field options: [{ + "(validate.rules).uint64.gt": 999 + }] - Field: email Rft_nolabel (Field Type: Ft_basic_type: Bt_string, Encoding: 2, Payload Kind: Pk_bytes) - Field options: {"validate.rules.string.email": Constant_bool true} + Field options: [{ + "(validate.rules).string.email": true + }] - Field: name Rft_nolabel (Field Type: Ft_basic_type: Bt_string, Encoding: 3, Payload Kind: Pk_bytes) - Field options: {"validate.rules.string": {"pattern": Constant_string "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", "max_bytes": Constant_int 256}} + Field options: [{ + "(validate.rules).string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256} + }] - Field: home Rft_optional (Field Type: Ft_user_defined_type: person_location, Encoding: 4, Payload Kind: Pk_bytes, Default Value: None) - Field options: {"validate.rules.message.required": Constant_bool true} + Field options: [{ + "(validate.rules).message.required": true + }] - Field: picture Rft_nolabel (Field Type: Ft_basic_type: Bt_bytes, Encoding: 5, Payload Kind: Pk_bytes) - Field options: {"validate.rules.bytes": {"not_in": [Constant_string "foo", Constant_string "bar", Constant_string "baz"]}} + Field options: [{ + "(validate.rules).bytes": {"not_in": ["foo", + "bar", + "baz"]} + }] - Field: id Rft_variant: person_id - Field options: {"validate.required": Constant_bool true} - Options: {"validate.disabled": Constant_bool true} + Field options: [{ + "(validate.required)": true + }] + Options: [{ + "(validate.disabled)": true + }] *) diff --git a/src/tests/expectation/tests.expected b/src/tests/expectation/tests.expected index a80793fd..47c8f61b 100644 --- a/src/tests/expectation/tests.expected +++ b/src/tests/expectation/tests.expected @@ -273,7 +273,7 @@ id = 7; message_name = "OptionMessage"; message_body = [{ - "my_option": true + "(my_option)": true }; { field_name = "id"; @@ -281,7 +281,7 @@ field_label = `Nolabel; field_type = Int32; field_options = [{ - "my_field_option": "value" + "(my_field_option)": "value" }]; }; { @@ -713,7 +713,7 @@ field_label = `Nolabel; field_type = Uint64; field_options = [{ - "validate.rules.uint64.gt": 999 + "(validate.rules).uint64.gt": 999 }]; }; { @@ -722,7 +722,7 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "validate.rules.string.email": true + "(validate.rules).string.email": true }]; }; { @@ -731,7 +731,7 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "validate.rules.string": { + "(validate.rules).string": { "pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", "max_bytes": 256} }]; @@ -746,7 +746,7 @@ from_root: false }; field_options = [{ - "validate.rules.message.required": true + "(validate.rules).message.required": true }]; }; { @@ -759,7 +759,7 @@ field_type = Double; field_options = [ { - "validate.rules.double": { + "(validate.rules).double": { "gte": -90, "lte": 90} }]; @@ -771,7 +771,7 @@ field_type = Double; field_options = [ { - "validate.rules.double": { + "(validate.rules).double": { "gte": -180, "lte": 180} }]; @@ -783,7 +783,7 @@ message_name = "Other"; message_body = [{oneof_name = "id"; oneof_body = [{ - "validate.required": true + "(validate.required)": true }; { field_name = "x"; @@ -792,7 +792,7 @@ field_type = String; field_options = [ { - "validate.rules.string.len": 5 + "(validate.rules).string.len": 5 }]; }; { @@ -822,7 +822,7 @@ field_label = `Nolabel; field_type = Uint32; field_options = [{ - "validate.rules.uint32": { + "(validate.rules).uint32": { "in": [1, 2, 3]} @@ -834,7 +834,7 @@ field_label = `Nolabel; field_type = Float; field_options = [{ - "validate.rules.float": { + "(validate.rules).float": { "not_in": [0, 0.990000]} }]; @@ -927,7 +927,7 @@ { service_name = "ShelfServiceV2"; service_body = [{ - "some.config": "service_shelf" + "(some.config)": "service_shelf" }; { rpc_name = "ListShelves"; @@ -996,10 +996,10 @@ { rpc_name = "GetShelf"; rpc_options = [{ - "const.config": "rpc_shelf" + "(const.config)": "rpc_shelf" }, { - "google.api.http": { + "(google.api.http)": { "post": "/v1/shelves/{shelf}", "body": "body"} }]; diff --git a/src/tests/unit-tests/parse_field_options.ml b/src/tests/unit-tests/parse_field_options.ml index b704a827..8cbc1c6e 100644 --- a/src/tests/unit-tests/parse_field_options.ml +++ b/src/tests/unit-tests/parse_field_options.ml @@ -1,7 +1,7 @@ let parse f s = f Pb_parsing_lexer.lexer (Lexing.from_string s) let has_option set option_name = - match Pb_option.get set option_name with + match Pb_option.get set [ Pb_option.Simple_name option_name ] with | None -> false | Some _ -> true @@ -9,7 +9,9 @@ module Pt = Pb_parsing_parse_tree let () = let test_default s = - Pb_option.get (parse Pb_parsing_parser.field_options_ s) "default" + Pb_option.get + (parse Pb_parsing_parser.field_options_ s) + [ Pb_option.Simple_name "default" ] |> function | Some (Pb_option.Scalar_value x) -> x | _ -> assert false @@ -46,6 +48,6 @@ let () = in assert ( Some Pb_option.(Scalar_value (Constant_literal "int")) - = Pb_option.get field_options "ocaml_type") + = Pb_option.get_ext field_options "ocaml_type") let () = print_endline "Parse Field Options ... Ok" diff --git a/src/tests/unit-tests/parse_file_options.ml b/src/tests/unit-tests/parse_file_options.ml index 7247aa6e..5f462b19 100644 --- a/src/tests/unit-tests/parse_file_options.ml +++ b/src/tests/unit-tests/parse_file_options.ml @@ -8,7 +8,9 @@ module Pt = Pb_parsing_parse_tree let () = let s = "option blah = 1;" in - let fo = "blah", Pb_option.(Scalar_value (Constant_int 1)) in + let fo = + [ Pb_option.Simple_name "blah" ], Pb_option.(Scalar_value (Constant_int 1)) + in assert (fo = parse s) let () = @@ -17,10 +19,10 @@ let () = let fo_parsed = proto.Pt.file_options in assert ( Some Pb_option.(Scalar_value (Constant_int 1)) - = Pb_option.get fo_parsed "blah"); + = Pb_option.get fo_parsed [ Pb_option.Simple_name "blah" ]); assert ( Some Pb_option.(Scalar_value (Constant_string "blah")) - = Pb_option.get fo_parsed "foo"); + = Pb_option.get fo_parsed [ Pb_option.Simple_name "foo" ]); () let () = print_endline "Parse File Options ... Ok" From efb389406ee61a1191d4b8ec6135ffb2cba53e1a Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Wed, 28 Feb 2024 13:58:58 +0400 Subject: [PATCH 09/47] Destructure option names to nested messages --- src/compilerlib/pb_codegen_backend.ml | 6 +- src/compilerlib/pb_option.ml | 75 +++++++++++++++---- src/compilerlib/pb_option.mli | 6 +- src/compilerlib/pb_parsing_parse_tree.ml | 6 ++ src/compilerlib/pb_parsing_parser.mly | 6 +- src/compilerlib/pb_parsing_util.ml | 36 +++++++-- src/compilerlib/pb_parsing_util.mli | 10 ++- src/compilerlib/pb_typing_validation.ml | 2 +- src/ocaml-protoc/ocaml_protoc_cmdline.ml | 8 +- .../expectation/option_processing.ml.expected | 28 +++---- src/tests/expectation/tests.expected | 46 +++++++----- src/tests/unit-tests/parse_field_options.ml | 4 +- src/tests/unit-tests/parse_file_options.ml | 6 +- 13 files changed, 164 insertions(+), 75 deletions(-) diff --git a/src/compilerlib/pb_codegen_backend.ml b/src/compilerlib/pb_codegen_backend.ml index 9be3a985..183f3463 100644 --- a/src/compilerlib/pb_codegen_backend.ml +++ b/src/compilerlib/pb_codegen_backend.ml @@ -195,7 +195,7 @@ let encoding_info_of_field_type ~all_types field_type : Ot.payload_kind = let encoding_of_field ~all_types (field : (Pb_field_type.resolved, 'a) Tt.field) = let packed = - match Typing_util.field_option field [ Pb_option.Simple_name "packed" ] with + match Typing_util.field_option field (Pb_option.Simple_name "packed") with | Some Pb_option.(Scalar_value (Constant_bool x)) -> x | Some _ -> E.invalid_packed_option (Typing_util.field_name field) | None -> false @@ -389,7 +389,7 @@ let compile_message ~(unsigned_tag : bool) (file_options : Pb_option.set) let type_level_ppx_extension = Typing_util.message_option message - [ Pb_option.Extension_name "ocaml_type_ppx" ] + (Pb_option.Extension_name "ocaml_type_ppx") |> string_of_string_option message_name |> process_all_types_ppx_extension file_name file_options in @@ -634,7 +634,7 @@ let compile_enum file_options file_name scope enum = in let type_level_ppx_extension = - Typing_util.enum_option enum [ Pb_option.Extension_name "ocaml_enum_ppx" ] + Typing_util.enum_option enum (Pb_option.Extension_name "ocaml_enum_ppx") |> string_of_string_option enum_name |> process_all_types_ppx_extension file_name file_options in diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index 190a230a..599b29b3 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -5,12 +5,10 @@ type constant = | Constant_float of float | Constant_literal of string -type name_part = +type option_name = | Simple_name of string | Extension_name of string -type option_name = name_part list - type message_literal = (string * value) list and list_literal = value list @@ -22,31 +20,82 @@ and value = type t = option_name * value type set = t list -let name_part_to_string = function +let stringify_option_name = function | Simple_name s -> s | Extension_name s -> "(" ^ s ^ ")" -let stringify_option_name (option_name : option_name) : string = - let str_list = List.map name_part_to_string option_name in - String.concat "." str_list - -let name_part_equal a b = +let option_name_equal a b = match a, b with | Simple_name a, Simple_name b -> String.equal a b | Extension_name a, Extension_name b -> String.equal a b | _ -> false -let option_name_equal a b = List.equal name_part_equal a b let empty = [] -let add t option_name value = (option_name, value) :: t -let merge t1 t2 = t2 @ t1 + +let destructure_option_name option_name value = + List.fold_right + (fun name_part acc -> + match name_part with + | Simple_name name -> Message_literal [ name, acc ] + | Extension_name name -> + failwith + (Printf.sprintf "Extension_name '%s' is not supported in option_name" + name)) + option_name value + +let rec merge_value v1 v2 = + match v1, v2 with + | Message_literal ml1, Message_literal ml2 -> + let rec merge_lists list1 list2 = + match list2 with + | [] -> list1 + | (field, value) :: rest -> + let updated_list, is_merged = + List.fold_left + (fun (acc, merged) (f, v) -> + if f = field then ( + match value, v with + | Message_literal _, Message_literal _ -> + acc @ [ f, merge_value value v ], true + | _ -> acc @ [ f, value ], merged + ) else + acc @ [ f, v ], merged) + ([], false) list1 + in + if is_merged then + merge_lists updated_list rest + else + merge_lists (updated_list @ [ field, value ]) rest + in + Message_literal (merge_lists ml1 ml2) + | _ -> v2 + +let add option_set option_name value = + match + List.partition + (fun ((name, _) : t) -> option_name_equal name option_name) + option_set + with + | [], _ -> (option_name, value) :: option_set + | [ (_, existing_value) ], remainder -> + let merged_value = merge_value existing_value value in + (option_name, merged_value) :: remainder + | _ -> + failwith + "This should not happen, partition should result in at most single item \ + in left component" + +let merge set1 set2 = + List.fold_left + (fun acc (option_name, value) -> add acc option_name value) + set1 set2 let get t option_name = match List.find (fun (other, _) -> option_name_equal option_name other) t with | _, c -> Some c | exception Not_found -> None -let get_ext t option_name = get t [ Extension_name option_name ] +let get_ext t option_name = get t (Extension_name option_name) let pp_constant ppf = function | Constant_string s -> Format.fprintf ppf "%S" s diff --git a/src/compilerlib/pb_option.mli b/src/compilerlib/pb_option.mli index 95390b09..7e13dc71 100644 --- a/src/compilerlib/pb_option.mli +++ b/src/compilerlib/pb_option.mli @@ -18,13 +18,11 @@ and value = | Message_literal of message_literal | List_literal of list_literal -type name_part = +(** Option identifier *) +type option_name = | Simple_name of string | Extension_name of string -type option_name = name_part list -(** Option identifier *) - type t = option_name * value type set = t list diff --git a/src/compilerlib/pb_parsing_parse_tree.ml b/src/compilerlib/pb_parsing_parse_tree.ml index 5ee3ebc5..e61911e2 100644 --- a/src/compilerlib/pb_parsing_parse_tree.ml +++ b/src/compilerlib/pb_parsing_parse_tree.ml @@ -25,6 +25,12 @@ (** Protobuf parse tree *) +type option_name_part = + | Simple_name of string + | Extension_name of string + +type option_name = option_name_part list + type message_field_label = [ `Optional | `Required diff --git a/src/compilerlib/pb_parsing_parser.mly b/src/compilerlib/pb_parsing_parser.mly index 326db322..1df2a9d7 100644 --- a/src/compilerlib/pb_parsing_parser.mly +++ b/src/compilerlib/pb_parsing_parser.mly @@ -240,7 +240,7 @@ rpc_options_list : } rpc_option : - | T_option option_identifier T_equal option_value semicolon { ($2, $4) } + | T_option option_identifier T_equal option_value semicolon { Pb_parsing_util.normalize_option $2 $4 } option_value : | constant { Pb_option.Scalar_value $1 } @@ -359,7 +359,7 @@ field_option_list : } field_option : - | option_identifier T_equal option_value { ($1, $3) } + | option_identifier T_equal option_value { Pb_parsing_util.normalize_option $1 $3 } option_identifier_item : | T_ident {snd $1 |> Pb_parsing_util.option_name_of_ident} @@ -370,7 +370,7 @@ option_identifier : | option_identifier_item option_identifier {$1 @ $2} option : - | T_option option_identifier T_equal option_value semicolon { ($2, $4) } + | T_option option_identifier T_equal option_value semicolon { Pb_parsing_util.normalize_option $2 $4} constant : | T_int { Pb_option.Constant_int $1 } diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index a63a511c..a37bd48b 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -136,10 +136,35 @@ let option_name_of_ident ident = else ident in - ident |> String.split_on_char '.' - |> List.map (fun x -> Pb_option.Simple_name x) + ident |> String.split_on_char '.' |> List.map (fun x -> Pt.Simple_name x) + +let option_name_extension ident = [ Pt.Extension_name ident ] + +let normalize_option_name option_name value = + List.fold_right + (fun name_part acc -> + match name_part with + | Pt.Simple_name name -> Pb_option.Message_literal [ name, acc ] + | Pt.Extension_name name -> + failwith + (Printf.sprintf + "normalize_option_name: Extension_name '%s' is not supported in \ + option_name" + name)) + option_name value + +let option_name_from_part = function + | Pt.Simple_name x -> Pb_option.Simple_name x + | Pt.Extension_name x -> Pb_option.Extension_name x + +let normalize_option option_name value = + match option_name with + | [] -> failwith "option_name can't be an empty list!" + | [ single_item ] -> option_name_from_part single_item, value + | top_level_item :: rest -> + let new_value = normalize_option_name rest value in + option_name_from_part top_level_item, new_value -let option_name_extension ident = [ Pb_option.Extension_name ident ] let service ~content service_name = Pt.{ service_name; service_body = content } let import ?public file_name = @@ -287,7 +312,7 @@ let finalize_syntax3 proto = in messages. Optional is now allowed, but default values might not be. *) let verify_no_default_field_options field_name message_name field_options = - match Pb_option.get field_options [ Pb_option.Simple_name "default" ] with + match Pb_option.get field_options (Pb_option.Simple_name "default") with | None -> () | Some _ -> E.default_field_option_not_supported ~field_name ~message_name in @@ -328,8 +353,7 @@ let finalize_syntax3 proto = | `Bool -> let field_options = Pb_option.( - add field_options - [ Pb_option.Simple_name "packed" ] + add field_options (Pb_option.Simple_name "packed") (Scalar_value (Constant_bool true))) in { field with Pt.field_options } diff --git a/src/compilerlib/pb_parsing_util.mli b/src/compilerlib/pb_parsing_util.mli index da1451e5..a907333e 100644 --- a/src/compilerlib/pb_parsing_util.mli +++ b/src/compilerlib/pb_parsing_util.mli @@ -89,8 +89,14 @@ val rpc : val option_map : Pb_option.message_literal -> Pb_option.value val option_list : Pb_option.list_literal -> Pb_option.value -val option_name_of_ident : string -> Pb_option.option_name -val option_name_extension : string -> Pb_option.option_name +val option_name_of_ident : string -> Pt.option_name +val option_name_extension : string -> Pt.option_name + +val normalize_option : + Pt.option_name_part list -> + Pb_option.value -> + Pb_option.option_name * Pb_option.value + val service_body_option : Pb_option.t -> Pt.service_body_content val service_body_rpc : Pt.rpc -> Pt.service_body_content val service : content:Pt.service_body_content list -> string -> Pt.service diff --git a/src/compilerlib/pb_typing_validation.ml b/src/compilerlib/pb_typing_validation.ml index 6f00ed31..1176469e 100644 --- a/src/compilerlib/pb_typing_validation.ml +++ b/src/compilerlib/pb_typing_validation.ml @@ -37,7 +37,7 @@ let scope_of_package : string option -> Tt.type_scope = function | None -> Typing_util.empty_scope let get_default field_name field_options : Pb_option.constant option = - match Pb_option.get field_options [ Pb_option.Simple_name "default" ] with + match Pb_option.get field_options (Pb_option.Simple_name "default") with | Some (Pb_option.Scalar_value constant) -> Some constant | Some (Pb_option.Message_literal _) -> E.invalid_default_value ~field_name diff --git a/src/ocaml-protoc/ocaml_protoc_cmdline.ml b/src/ocaml-protoc/ocaml_protoc_cmdline.ml index 5cc2ebaa..b1d8a48b 100644 --- a/src/ocaml-protoc/ocaml_protoc_cmdline.ml +++ b/src/ocaml-protoc/ocaml_protoc_cmdline.ml @@ -90,13 +90,13 @@ module File_options = struct let open Pb_option in empty |> map int32_type (fun s -> - [ Extension_name "int32_type" ], Scalar_value (Constant_literal s)) + Extension_name "int32_type", Scalar_value (Constant_literal s)) |> map int64_type (fun s -> - [ Extension_name "int64_type" ], Scalar_value (Constant_literal s)) + Extension_name "int64_type", Scalar_value (Constant_literal s)) |> map ocaml_file_ppx (fun s -> - [ Extension_name "ocaml_file_ppx" ], Scalar_value (Constant_string s)) + Extension_name "ocaml_file_ppx", Scalar_value (Constant_string s)) |> map ocaml_all_types_ppx (fun s -> - ( [ Extension_name "ocaml_all_types_ppx" ], + ( Extension_name "ocaml_all_types_ppx", Scalar_value (Constant_string s) )) end diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index 4a4cab46..1cb0d9c5 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -93,14 +93,14 @@ and default_person - Field: lat Rft_nolabel (Field Type: Ft_basic_type: Bt_float, Encoding: 1, Payload Kind: Pk_bits64) Field options: [{ - "(validate.rules).double": {"gte": -90, - "lte": 90} + "(validate.rules)": {"double": {"gte": -90, + "lte": 90}} }] - Field: lng Rft_nolabel (Field Type: Ft_basic_type: Bt_float, Encoding: 2, Payload Kind: Pk_bits64) Field options: [{ - "(validate.rules).double": {"gte": -180, - "lte": 180} + "(validate.rules)": {"double": {"gte": -180, + "lte": 180}} }] Options: [{ "(validate.disabled)": true @@ -116,14 +116,14 @@ and default_person Encoding Number: 6, Payload Kind: Pk_bytes Options: [{ - "(validate.rules).string.prefix": "foo" + "(validate.rules)": {"string": {"prefix": "foo"}} }] Constructor: Y Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_int32 Encoding Number: 7, Payload Kind: Pk_varint (zigzag: false) Options: [{ - "(validate.rules).int32.gt": 0 + "(validate.rules)": {"int32": {"gt": 0}} }] Constructor: Z Field Type: Vct_non_nullary_constructor: Ft_basic_type: Bt_float @@ -139,30 +139,30 @@ and default_person - Field: id Rft_nolabel (Field Type: Ft_basic_type: Bt_int64, Encoding: 1, Payload Kind: Pk_varint (zigzag: false)) Field options: [{ - "(validate.rules).uint64.gt": 999 + "(validate.rules)": {"uint64": {"gt": 999}} }] - Field: email Rft_nolabel (Field Type: Ft_basic_type: Bt_string, Encoding: 2, Payload Kind: Pk_bytes) Field options: [{ - "(validate.rules).string.email": true + "(validate.rules)": {"string": {"email": true}} }] - Field: name Rft_nolabel (Field Type: Ft_basic_type: Bt_string, Encoding: 3, Payload Kind: Pk_bytes) Field options: [{ - "(validate.rules).string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", - "max_bytes": 256} + "(validate.rules)": {"string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256}} }] - Field: home Rft_optional (Field Type: Ft_user_defined_type: person_location, Encoding: 4, Payload Kind: Pk_bytes, Default Value: None) Field options: [{ - "(validate.rules).message.required": true + "(validate.rules)": {"message": {"required": true}} }] - Field: picture Rft_nolabel (Field Type: Ft_basic_type: Bt_bytes, Encoding: 5, Payload Kind: Pk_bytes) Field options: [{ - "(validate.rules).bytes": {"not_in": ["foo", - "bar", - "baz"]} + "(validate.rules)": {"bytes": {"not_in": ["foo", + "bar", + "baz"]}} }] - Field: id Rft_variant: person_id diff --git a/src/tests/expectation/tests.expected b/src/tests/expectation/tests.expected index 47c8f61b..320b1a3f 100644 --- a/src/tests/expectation/tests.expected +++ b/src/tests/expectation/tests.expected @@ -713,7 +713,8 @@ field_label = `Nolabel; field_type = Uint64; field_options = [{ - "(validate.rules).uint64.gt": 999 + "(validate.rules)": { + "uint64": {"gt": 999}} }]; }; { @@ -722,7 +723,8 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "(validate.rules).string.email": true + "(validate.rules)": { + "string": {"email": true}} }]; }; { @@ -731,9 +733,9 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "(validate.rules).string": { - "pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", - "max_bytes": 256} + "(validate.rules)": { + "string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256}} }]; }; { @@ -746,7 +748,8 @@ from_root: false }; field_options = [{ - "(validate.rules).message.required": true + "(validate.rules)": { + "message": {"required": true}} }]; }; { @@ -759,9 +762,9 @@ field_type = Double; field_options = [ { - "(validate.rules).double": { - "gte": -90, - "lte": 90} + "(validate.rules)": { + "double": {"gte": -90, + "lte": 90}} }]; }; { @@ -771,9 +774,9 @@ field_type = Double; field_options = [ { - "(validate.rules).double": { - "gte": -180, - "lte": 180} + "(validate.rules)": { + "double": {"gte": -180, + "lte": 180}} }]; }]; }]; @@ -792,7 +795,8 @@ field_type = String; field_options = [ { - "(validate.rules).string.len": 5 + "(validate.rules)": { + "string": {"len": 5}} }]; }; { @@ -822,10 +826,11 @@ field_label = `Nolabel; field_type = Uint32; field_options = [{ - "(validate.rules).uint32": { - "in": [1, - 2, - 3]} + "(validate.rules)": { + "uint32": {"in": [ + 1, + 2, + 3]}} }]; }; { @@ -834,9 +839,10 @@ field_label = `Nolabel; field_type = Float; field_options = [{ - "(validate.rules).float": { - "not_in": [0, - 0.990000]} + "(validate.rules)": { + "float": {"not_in": [ + 0, + 0.990000]}} }]; }]; }]; diff --git a/src/tests/unit-tests/parse_field_options.ml b/src/tests/unit-tests/parse_field_options.ml index 8cbc1c6e..5a233968 100644 --- a/src/tests/unit-tests/parse_field_options.ml +++ b/src/tests/unit-tests/parse_field_options.ml @@ -1,7 +1,7 @@ let parse f s = f Pb_parsing_lexer.lexer (Lexing.from_string s) let has_option set option_name = - match Pb_option.get set [ Pb_option.Simple_name option_name ] with + match Pb_option.get set (Pb_option.Simple_name option_name) with | None -> false | Some _ -> true @@ -11,7 +11,7 @@ let () = let test_default s = Pb_option.get (parse Pb_parsing_parser.field_options_ s) - [ Pb_option.Simple_name "default" ] + (Pb_option.Simple_name "default") |> function | Some (Pb_option.Scalar_value x) -> x | _ -> assert false diff --git a/src/tests/unit-tests/parse_file_options.ml b/src/tests/unit-tests/parse_file_options.ml index 5f462b19..feb73050 100644 --- a/src/tests/unit-tests/parse_file_options.ml +++ b/src/tests/unit-tests/parse_file_options.ml @@ -9,7 +9,7 @@ module Pt = Pb_parsing_parse_tree let () = let s = "option blah = 1;" in let fo = - [ Pb_option.Simple_name "blah" ], Pb_option.(Scalar_value (Constant_int 1)) + Pb_option.Simple_name "blah", Pb_option.(Scalar_value (Constant_int 1)) in assert (fo = parse s) @@ -19,10 +19,10 @@ let () = let fo_parsed = proto.Pt.file_options in assert ( Some Pb_option.(Scalar_value (Constant_int 1)) - = Pb_option.get fo_parsed [ Pb_option.Simple_name "blah" ]); + = Pb_option.get fo_parsed (Pb_option.Simple_name "blah")); assert ( Some Pb_option.(Scalar_value (Constant_string "blah")) - = Pb_option.get fo_parsed [ Pb_option.Simple_name "foo" ]); + = Pb_option.get fo_parsed (Pb_option.Simple_name "foo")); () let () = print_endline "Parse File Options ... Ok" From b1002fe478eaf2828ce181ce28554aa2523dec5c Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Fri, 1 Mar 2024 11:35:51 +0400 Subject: [PATCH 10/47] WIP: Introduce Pb_raw_option --- src/compilerlib/dune | 6 +- src/compilerlib/pb_codegen_all.ml | 2 +- src/compilerlib/pb_codegen_all.mli | 2 +- src/compilerlib/pb_option.ml | 11 --- src/compilerlib/pb_parsing_parse_tree.ml | 40 ++++------ src/compilerlib/pb_parsing_parser.mly | 26 +++--- src/compilerlib/pb_parsing_util.ml | 80 ++++++++++--------- src/compilerlib/pb_parsing_util.mli | 30 +++---- src/compilerlib/pb_raw_option.ml | 47 +++++++++++ src/compilerlib/pb_raw_option.mli | 23 ++++++ src/compilerlib/pb_typing_validation.ml | 2 +- src/ocaml-protoc/ocaml_protoc_cmdline.ml | 14 ++-- src/ocaml-protoc/ocaml_protoc_compilation.ml | 2 +- src/ocaml-protoc/ocaml_protoc_generation.mli | 2 +- src/tests/expectation/option_processing.proto | 12 +++ src/tests/unit-tests/parse_field_options.ml | 10 +-- src/tests/unit-tests/parse_file_options.ml | 7 +- 17 files changed, 189 insertions(+), 127 deletions(-) create mode 100644 src/compilerlib/pb_raw_option.ml create mode 100644 src/compilerlib/pb_raw_option.mli diff --git a/src/compilerlib/dune b/src/compilerlib/dune index 7bab48c5..8a8acde4 100644 --- a/src/compilerlib/dune +++ b/src/compilerlib/dune @@ -14,8 +14,8 @@ pb_codegen_encode_yojson pb_codegen_formatting pb_codegen_ocaml_type_dump pb_codegen_ocaml_type pb_codegen_pp pb_codegen_plugin pb_codegen_types pb_codegen_services pb_codegen_util pb_exception pb_field_type pb_location - pb_logger pb_option pb_parsing pb_parsing_lexer pb_parsing_parser - pb_parsing_parse_tree pb_parsing_util pb_typing_graph pb_typing - pb_typing_recursion pb_typing_resolution pb_typing_type_tree + pb_logger pb_option pb_raw_option pb_parsing pb_parsing_lexer + pb_parsing_parser pb_parsing_parse_tree pb_parsing_util pb_typing_graph + pb_typing pb_typing_recursion pb_typing_resolution pb_typing_type_tree pb_typing_util pb_typing_validation pb_util pb_format_util) (libraries stdlib-shims)) diff --git a/src/compilerlib/pb_codegen_all.ml b/src/compilerlib/pb_codegen_all.ml index 5dc77dbf..13d6cb17 100644 --- a/src/compilerlib/pb_codegen_all.ml +++ b/src/compilerlib/pb_codegen_all.ml @@ -40,7 +40,7 @@ let new_ocaml_mod ~proto_file_options ~proto_file_name () : ocaml_mod = let self = { ml = F.empty_scope (); mli = F.empty_scope () } in let print_ppx sc = - match Pb_option.get_ext proto_file_options "ocaml_file_ppx" with + match Pb_raw_option.get_ext proto_file_options "ocaml_file_ppx" with | None -> () | Some Pb_option.(Scalar_value (Constant_string s)) -> F.linep sc "[@@@%s]" s diff --git a/src/compilerlib/pb_codegen_all.mli b/src/compilerlib/pb_codegen_all.mli index b693585e..5d7d1a4f 100644 --- a/src/compilerlib/pb_codegen_all.mli +++ b/src/compilerlib/pb_codegen_all.mli @@ -12,7 +12,7 @@ type ocaml_mod = { val codegen : Ot.proto -> generate_make:bool -> - proto_file_options:Pb_option.set -> + proto_file_options:Pb_raw_option.set -> proto_file_name:string -> services:bool -> Plugin.t list -> diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index 599b29b3..b3551ec5 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -32,17 +32,6 @@ let option_name_equal a b = let empty = [] -let destructure_option_name option_name value = - List.fold_right - (fun name_part acc -> - match name_part with - | Simple_name name -> Message_literal [ name, acc ] - | Extension_name name -> - failwith - (Printf.sprintf "Extension_name '%s' is not supported in option_name" - name)) - option_name value - let rec merge_value v1 v2 = match v1, v2 with | Message_literal ml1, Message_literal ml2 -> diff --git a/src/compilerlib/pb_parsing_parse_tree.ml b/src/compilerlib/pb_parsing_parse_tree.ml index e61911e2..023d3b6e 100644 --- a/src/compilerlib/pb_parsing_parse_tree.ml +++ b/src/compilerlib/pb_parsing_parse_tree.ml @@ -25,12 +25,6 @@ (** Protobuf parse tree *) -type option_name_part = - | Simple_name of string - | Extension_name of string - -type option_name = option_name_part list - type message_field_label = [ `Optional | `Required @@ -51,7 +45,7 @@ type 'a field = { field_number: int; field_label: 'a; field_type: Pb_field_type.unresolved_t; - field_options: Pb_option.set; + field_options: Pb_raw_option.set; } (** message field. @@ -69,12 +63,12 @@ type map_field = { map_number: int; map_key_type: Pb_field_type.map_key_type; map_value_type: Pb_field_type.unresolved_t; - map_options: Pb_option.set; + map_options: Pb_raw_option.set; } type oneof_body_content = | Oneof_field of oneof_field - | Oneof_option of Pb_option.t + | Oneof_option of Pb_raw_option.t type oneof = { oneof_name: string; @@ -85,12 +79,12 @@ type oneof = { type enum_value = { enum_value_name: string; enum_value_int: int; - enum_value_options: Pb_option.set; + enum_value_options: Pb_raw_option.set; } type enum_body_content = | Enum_value of enum_value - | Enum_option of Pb_option.t + | Enum_option of Pb_raw_option.t type enum = { enum_id: int; @@ -119,7 +113,7 @@ type message_body_content = | Message_enum of enum | Message_extension of extension_range list | Message_reserved of extension_range list - | Message_option of Pb_option.t + | Message_option of Pb_raw_option.t and message = { id: int; @@ -135,7 +129,7 @@ and message = { type rpc = { rpc_name: string; - rpc_options: Pb_option.set; + rpc_options: Pb_raw_option.set; rpc_req_stream: bool; rpc_req: Pb_field_type.unresolved_t; rpc_res_stream: bool; @@ -144,7 +138,7 @@ type rpc = { type service_body_content = | Service_rpc of rpc - | Service_option of Pb_option.t + | Service_option of Pb_raw_option.t type service = { service_name: string; @@ -166,7 +160,7 @@ type proto = { proto_file_name: string option; syntax: string option; imports: import list; - file_options: Pb_option.set; + file_options: Pb_raw_option.set; package: string option; messages: message list; services: service list; @@ -203,7 +197,7 @@ let pp_field pp_label ppf field = field_options = %a;@,\ }@]" field.field_name field.field_number pp_label field.field_label - Pb_field_type.pp_unresolved_t field.field_type Pb_option.pp_set + Pb_field_type.pp_unresolved_t field.field_type Pb_raw_option.pp_set field.field_options let pp_message_field ppf field = pp_field pp_message_field_label ppf field @@ -220,11 +214,11 @@ let pp_map_field ppf map_field = }@]" map_field.map_name map_field.map_number Pb_field_type.pp_map_key_type map_field.map_key_type Pb_field_type.pp_unresolved_t - map_field.map_value_type Pb_option.pp_set map_field.map_options + map_field.map_value_type Pb_raw_option.pp_set map_field.map_options let pp_oneof_body_content ppf = function | Oneof_field field -> pp_oneof_field ppf field - | Oneof_option option -> Pb_option.pp_t ppf option + | Oneof_option option -> Pb_raw_option.pp_t ppf option let pp_oneof ppf oneof = fprintf ppf "{@[%s = %S;@,%s = [@[%a@]];@,@]}" "oneof_name" @@ -241,7 +235,7 @@ let pp_enum_value ppf enum_value = let pp_enum_body_content ppf enum_body_content = match enum_body_content with | Enum_value enum_value -> pp_enum_value ppf enum_value - | Enum_option option -> Pb_option.pp_t ppf option + | Enum_option option -> Pb_raw_option.pp_t ppf option let pp_enum ppf enum = fprintf ppf @@ -284,7 +278,7 @@ let rec pp_message_body_content ppf msg_body_content = ~pp_sep:(fun ppf () -> fprintf ppf ";@,") pp_extension_range) res_ranges - | Message_option option -> Pb_option.pp_t ppf option + | Message_option option -> Pb_raw_option.pp_t ppf option and pp_message ppf message = fprintf ppf @@ -305,14 +299,14 @@ let pp_rpc ppf rpc = rpc_res_stream = %b;@,\ rpc_res = %a;@,\ }@]" - rpc.rpc_name Pb_option.pp_set rpc.rpc_options rpc.rpc_req_stream + rpc.rpc_name Pb_raw_option.pp_set rpc.rpc_options rpc.rpc_req_stream Pb_field_type.pp_unresolved_t rpc.rpc_req rpc.rpc_res_stream Pb_field_type.pp_unresolved_t rpc.rpc_res let rec pp_service_body_content ppf service_body_content = match service_body_content with | Service_rpc rpc -> pp_rpc ppf rpc - | Service_option option -> Pb_option.pp_t ppf option + | Service_option option -> Pb_raw_option.pp_t ppf option and pp_service ppf service = fprintf ppf "{@[@,service_name = %S;@,service_body = [@[%a@]];@,}@]" @@ -350,7 +344,7 @@ let pp_proto ppf proto = (pp_print_option ~none:pp_none pp_print_string) proto.syntax (pp_print_list ~pp_sep:(fun ppf () -> fprintf ppf ";@,") pp_import) - proto.imports Pb_option.pp_set proto.file_options + proto.imports Pb_raw_option.pp_set proto.file_options (pp_print_option ~none:pp_none pp_print_string) proto.package (pp_print_list ~pp_sep:(fun ppf () -> fprintf ppf ";@,") pp_message) diff --git a/src/compilerlib/pb_parsing_parser.mly b/src/compilerlib/pb_parsing_parser.mly index 1df2a9d7..0187e0a2 100644 --- a/src/compilerlib/pb_parsing_parser.mly +++ b/src/compilerlib/pb_parsing_parser.mly @@ -68,7 +68,7 @@ /*Entry points*/ %start field_options_ -%type field_options_ +%type field_options_ %start normal_field_ %type normal_field_ %start enum_value_ @@ -86,7 +86,7 @@ %start import_ %type import_ %start option_ -%type option_ +%type option_ %start extension_range_list_ %type extension_range_list_ %start extension_ @@ -129,7 +129,7 @@ proto: proto_content: | import {Pb_parsing_util.proto ~import:$1 ()} - | option {Pb_parsing_util.proto ~file_option:$1 ()} + | option { (let x : Pb_raw_option.t = $1 in Pb_parsing_util.proto ~file_option:x ())} | package_declaration {Pb_parsing_util.proto ~package:$1 ()} | message {Pb_parsing_util.proto ~message:$1 ()} | service {Pb_parsing_util.proto ~service:$1 ()} @@ -227,20 +227,20 @@ rpc : rpc_options : | T_lbrace rpc_options_list T_rbrace { $2 } | T_lbrace rpc_options_list T_rbrace semicolon { $2 } - | T_lbrace T_rbrace { Pb_option.empty } - | T_lbrace T_rbrace semicolon { Pb_option.empty }; + | T_lbrace T_rbrace { Pb_raw_option.empty } + | T_lbrace T_rbrace semicolon { Pb_raw_option.empty }; rpc_options_list : | rpc_option { let option_name, option_value = $1 in - Pb_option.add Pb_option.empty option_name option_value + Pb_raw_option.add Pb_raw_option.empty option_name option_value } | rpc_option rpc_options_list { - Pb_option.add $2 (fst $1) (snd $1) + Pb_raw_option.add $2 (fst $1) (snd $1) } rpc_option : - | T_option option_identifier T_equal option_value semicolon { Pb_parsing_util.normalize_option $2 $4 } + | T_option option_identifier T_equal option_value semicolon { ($2, $4) } option_value : | constant { Pb_option.Scalar_value $1 } @@ -347,19 +347,19 @@ label : field_options : | T_lbracket field_option_list T_rbracket { $2 } - | T_lbracket T_rbracket { Pb_option.empty }; + | T_lbracket T_rbracket { Pb_raw_option.empty }; field_option_list : | field_option { let option_name, option_value = $1 in - Pb_option.add Pb_option.empty option_name option_value + Pb_raw_option.add Pb_raw_option.empty option_name option_value } | field_option T_comma field_option_list { - Pb_option.add $3 (fst $1) (snd $1) + Pb_raw_option.add $3 (fst $1) (snd $1) } field_option : - | option_identifier T_equal option_value { Pb_parsing_util.normalize_option $1 $3 } + | option_identifier T_equal option_value { ($1, $3) } option_identifier_item : | T_ident {snd $1 |> Pb_parsing_util.option_name_of_ident} @@ -370,7 +370,7 @@ option_identifier : | option_identifier_item option_identifier {$1 @ $2} option : - | T_option option_identifier T_equal option_value semicolon { Pb_parsing_util.normalize_option $2 $4} + | T_option option_identifier T_equal option_value semicolon { (let foo: Pb_raw_option.t = ($2, $4) in foo) } constant : | T_int { Pb_option.Constant_int $1 } diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index a37bd48b..6741118b 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -26,7 +26,7 @@ module E = Pb_exception module Pt = Pb_parsing_parse_tree -let field ?(options = Pb_option.empty) ~label ~number ~type_ name = +let field ?(options = Pb_raw_option.empty) ~label ~number ~type_ name = { Pt.field_name = name; Pt.field_number = number; @@ -35,7 +35,7 @@ let field ?(options = Pb_option.empty) ~label ~number ~type_ name = Pt.field_options = options; } -let map_field ?options:(map_options = Pb_option.empty) ~number ~key_type +let map_field ?options:(map_options = Pb_raw_option.empty) ~number ~key_type ~value_type name = let map_key_type = Pb_field_type.parse key_type |> function @@ -54,7 +54,7 @@ let map_field ?options:(map_options = Pb_option.empty) ~number ~key_type Pt.map_options; } -let oneof_field ?(options = Pb_option.empty) ~number ~type_ name = +let oneof_field ?(options = Pb_raw_option.empty) ~number ~type_ name = Pt.Oneof_field { Pt.field_name = name; @@ -68,7 +68,7 @@ let oneof_option option_ = Pt.Oneof_option option_ let oneof ?(oneof_body = []) name = { Pt.oneof_name = name; Pt.oneof_body } let message_counter = ref 0 -let enum_value ~int_value ?(options = Pb_option.empty) name = +let enum_value ~int_value ?(options = Pb_raw_option.empty) name = Pt.( Enum_value { @@ -114,8 +114,8 @@ let message ~content message_name = let service_body_option option_ = Pt.Service_option option_ let service_body_rpc rpc = Pt.Service_rpc rpc -let rpc ?(options = Pb_option.empty) ~req_stream ~req ~res_stream ~res rpc_name - = +let rpc ?(options = Pb_raw_option.empty) ~req_stream ~req ~res_stream ~res + rpc_name = Pt. { rpc_name; @@ -136,34 +136,36 @@ let option_name_of_ident ident = else ident in - ident |> String.split_on_char '.' |> List.map (fun x -> Pt.Simple_name x) - -let option_name_extension ident = [ Pt.Extension_name ident ] - -let normalize_option_name option_name value = - List.fold_right - (fun name_part acc -> - match name_part with - | Pt.Simple_name name -> Pb_option.Message_literal [ name, acc ] - | Pt.Extension_name name -> - failwith - (Printf.sprintf - "normalize_option_name: Extension_name '%s' is not supported in \ - option_name" - name)) - option_name value - -let option_name_from_part = function - | Pt.Simple_name x -> Pb_option.Simple_name x - | Pt.Extension_name x -> Pb_option.Extension_name x - -let normalize_option option_name value = - match option_name with - | [] -> failwith "option_name can't be an empty list!" - | [ single_item ] -> option_name_from_part single_item, value - | top_level_item :: rest -> - let new_value = normalize_option_name rest value in - option_name_from_part top_level_item, new_value + ident |> String.split_on_char '.' + |> List.map (fun x -> Pb_raw_option.Simple_name x) + +let option_name_extension ident = [ Pb_raw_option.Extension_name ident ] + +(* let normalize_option_name option_name value = + List.fold_right + (fun name_part acc -> + match name_part with + | Pb_raw_option.Simple_name name -> + Pb_option.Message_literal [ name, acc ] + | Pb_raw_option.Extension_name name -> + failwith + (Printf.sprintf + "normalize_option_name: Extension_name '%s' is not supported in \ + option_name" + name)) + option_name value + + let option_name_from_part = function + | Pb_raw_option.Simple_name x -> Pb_option.Simple_name x + | Pb_raw_option.Extension_name x -> Pb_option.Extension_name x + + let normalize_option option_name value = + match option_name with + | [] -> failwith "option_name can't be an empty list!" + | [ single_item ] -> option_name_from_part single_item, value + | top_level_item :: rest -> + let new_value = normalize_option_name rest value in + option_name_from_part top_level_item, new_value *) let service ~content service_name = Pt.{ service_name; service_body = content } @@ -221,7 +223,7 @@ let proto ?syntax ?file_option ?package ?import ?message ?service ?enum ?proto package = None; messages = []; services = []; - file_options = Pb_option.empty; + file_options = Pb_raw_option.empty; enums = []; extends = []; } @@ -272,7 +274,7 @@ let proto ?syntax ?file_option ?package ?import ?message ?service ?enum ?proto match file_option with | None -> proto | Some i -> - let file_options = Pb_option.add file_options (fst i) (snd i) in + let file_options = Pb_raw_option.add file_options (fst i) (snd i) in Pt.{ proto with file_options } in @@ -312,7 +314,7 @@ let finalize_syntax3 proto = in messages. Optional is now allowed, but default values might not be. *) let verify_no_default_field_options field_name message_name field_options = - match Pb_option.get field_options (Pb_option.Simple_name "default") with + match Pb_raw_option.get field_options [ Simple_name "default" ] with | None -> () | Some _ -> E.default_field_option_not_supported ~field_name ~message_name in @@ -352,8 +354,8 @@ let finalize_syntax3 proto = | #Pb_field_type.builtin_type_floating_point | `Bool -> let field_options = - Pb_option.( - add field_options (Pb_option.Simple_name "packed") + Pb_raw_option.( + add field_options [ Simple_name "packed" ] (Scalar_value (Constant_bool true))) in { field with Pt.field_options } diff --git a/src/compilerlib/pb_parsing_util.mli b/src/compilerlib/pb_parsing_util.mli index a907333e..a99e49e3 100644 --- a/src/compilerlib/pb_parsing_util.mli +++ b/src/compilerlib/pb_parsing_util.mli @@ -33,7 +33,7 @@ module Pt = Pb_parsing_parse_tree (** {2 Creators } *) val field : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> label:Pt.message_field_label -> number:int -> type_:string -> @@ -41,7 +41,7 @@ val field : Pt.message_field val map_field : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> number:int -> key_type:string -> value_type:string -> @@ -49,22 +49,22 @@ val map_field : Pt.map_field val oneof_field : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> number:int -> type_:string -> string -> Pt.oneof_body_content -val oneof_option : Pb_option.t -> Pt.oneof_body_content +val oneof_option : Pb_raw_option.t -> Pt.oneof_body_content val oneof : ?oneof_body:Pt.oneof_body_content list -> string -> Pt.oneof val message_body_field : Pt.message_field -> Pt.message_body_content val message_body_map_field : Pt.map_field -> Pt.message_body_content val message_body_oneof_field : Pt.oneof -> Pt.message_body_content val enum_value : - int_value:int -> ?options:Pb_option.set -> string -> Pt.enum_body_content + int_value:int -> ?options:Pb_raw_option.set -> string -> Pt.enum_body_content -val enum_option : Pb_option.t -> Pt.enum_body_content +val enum_option : Pb_raw_option.t -> Pt.enum_body_content val enum : ?enum_body:Pt.enum_body_content list -> string -> Pt.enum val extension_range_single_number : int -> Pt.extension_range @@ -75,11 +75,11 @@ val message_body_sub : Pt.message -> Pt.message_body_content val message_body_enum : Pt.enum -> Pt.message_body_content val message_body_extension : Pt.extension_range list -> Pt.message_body_content val message_body_reserved : Pt.extension_range list -> Pt.message_body_content -val message_body_option : Pb_option.t -> Pt.message_body_content +val message_body_option : Pb_raw_option.t -> Pt.message_body_content val message : content:Pt.message_body_content list -> string -> Pt.message val rpc : - ?options:Pb_option.set -> + ?options:Pb_raw_option.set -> req_stream:bool -> req:string -> res_stream:bool -> @@ -89,15 +89,9 @@ val rpc : val option_map : Pb_option.message_literal -> Pb_option.value val option_list : Pb_option.list_literal -> Pb_option.value -val option_name_of_ident : string -> Pt.option_name -val option_name_extension : string -> Pt.option_name - -val normalize_option : - Pt.option_name_part list -> - Pb_option.value -> - Pb_option.option_name * Pb_option.value - -val service_body_option : Pb_option.t -> Pt.service_body_content +val option_name_of_ident : string -> Pb_raw_option.option_name +val option_name_extension : string -> Pb_raw_option.option_name +val service_body_option : Pb_raw_option.t -> Pt.service_body_content val service_body_rpc : Pt.rpc -> Pt.service_body_content val service : content:Pt.service_body_content list -> string -> Pt.service val import : ?public:unit -> string -> Pt.import @@ -105,7 +99,7 @@ val extend : string -> Pt.message_field list -> Pt.extend val proto : ?syntax:string -> - ?file_option:Pb_option.t -> + ?file_option:Pb_raw_option.t -> ?package:string -> ?import:Pt.import -> ?message:Pt.message -> diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml new file mode 100644 index 00000000..42a8a8ce --- /dev/null +++ b/src/compilerlib/pb_raw_option.ml @@ -0,0 +1,47 @@ +type name_part = Pb_option.option_name = + | Simple_name of string + | Extension_name of string + +type option_name = name_part list +type t = option_name * Pb_option.value +type set = t list + +let stringify_option_name name = + name + |> List.map (function + | Simple_name s -> s + | Extension_name s -> "(" ^ s ^ ")") + |> String.concat "." + +let option_name_part_equal a b = + match a, b with + | Simple_name a, Simple_name b -> String.equal a b + | Extension_name a, Extension_name b -> String.equal a b + | _ -> false + +let option_name_equal = List.equal option_name_part_equal +let empty = [] +let add option_set option_name value = (option_name, value) :: option_set + +let merge set1 set2 = + List.fold_left + (fun acc (option_name, value) -> add acc option_name value) + set1 set2 + +let get t option_name = + match List.find (fun (other, _) -> option_name_equal option_name other) t with + | _, c -> Some c + | exception Not_found -> None + +let get_ext t option_name = get t [ Extension_name option_name ] +let get_simple t option_name = get t [ Simple_name option_name ] + +let pp_t ppf (name, value) = + Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" + (stringify_option_name name) + Pb_option.pp_value value + +let pp_set ppf set = + Format.fprintf ppf "[@[%a@]]" + (Format.pp_print_list ~pp_sep:(fun ppf () -> Format.fprintf ppf ",@,") pp_t) + set diff --git a/src/compilerlib/pb_raw_option.mli b/src/compilerlib/pb_raw_option.mli new file mode 100644 index 00000000..cb7b957b --- /dev/null +++ b/src/compilerlib/pb_raw_option.mli @@ -0,0 +1,23 @@ +(** Protobuf File/Message/Field raw options (i.e. exactly as they parsed) *) + +type name_part = + | Simple_name of string + | Extension_name of string + +type option_name = name_part list +type t = option_name * Pb_option.value +type set = t list + +val stringify_option_name : option_name -> string +val empty : set +val add : set -> option_name -> Pb_option.value -> set + +val merge : set -> set -> set +(** [merge s1 s2] adds all the options from [s2] to [s1]. This means + than in case of duplicates [s2] options will override [s1] options. *) + +val get : set -> option_name -> Pb_option.value option +val get_ext : set -> string -> Pb_option.value option +val get_simple : set -> string -> Pb_option.value option +val pp_t : Format.formatter -> t -> unit +val pp_set : Format.formatter -> set -> unit diff --git a/src/compilerlib/pb_typing_validation.ml b/src/compilerlib/pb_typing_validation.ml index 1176469e..b8211935 100644 --- a/src/compilerlib/pb_typing_validation.ml +++ b/src/compilerlib/pb_typing_validation.ml @@ -37,7 +37,7 @@ let scope_of_package : string option -> Tt.type_scope = function | None -> Typing_util.empty_scope let get_default field_name field_options : Pb_option.constant option = - match Pb_option.get field_options (Pb_option.Simple_name "default") with + match Pb_raw_option.get_simple field_options "default" with | Some (Pb_option.Scalar_value constant) -> Some constant | Some (Pb_option.Message_literal _) -> E.invalid_default_value ~field_name diff --git a/src/ocaml-protoc/ocaml_protoc_cmdline.ml b/src/ocaml-protoc/ocaml_protoc_cmdline.ml index b1d8a48b..d33a0141 100644 --- a/src/ocaml-protoc/ocaml_protoc_cmdline.ml +++ b/src/ocaml-protoc/ocaml_protoc_cmdline.ml @@ -77,7 +77,7 @@ module File_options = struct (** Converts the command line values to Parse Tree file options *) - let to_file_options t : Pb_option.set = + let to_file_options t : Pb_raw_option.set = let { int32_type; int64_type; ocaml_file_ppx; ocaml_all_types_ppx } = t in let map x f options = @@ -85,18 +85,18 @@ module File_options = struct | None -> options | Some x -> let option_name, option_value = f x in - Pb_option.add options option_name option_value + Pb_raw_option.add options option_name option_value in - let open Pb_option in + let open Pb_raw_option in empty |> map int32_type (fun s -> - Extension_name "int32_type", Scalar_value (Constant_literal s)) + [ Extension_name "int32_type" ], Scalar_value (Constant_literal s)) |> map int64_type (fun s -> - Extension_name "int64_type", Scalar_value (Constant_literal s)) + [ Extension_name "int64_type" ], Scalar_value (Constant_literal s)) |> map ocaml_file_ppx (fun s -> - Extension_name "ocaml_file_ppx", Scalar_value (Constant_string s)) + [ Extension_name "ocaml_file_ppx" ], Scalar_value (Constant_string s)) |> map ocaml_all_types_ppx (fun s -> - ( Extension_name "ocaml_all_types_ppx", + ( [ Extension_name "ocaml_all_types_ppx" ], Scalar_value (Constant_string s) )) end diff --git a/src/ocaml-protoc/ocaml_protoc_compilation.ml b/src/ocaml-protoc/ocaml_protoc_compilation.ml index f6ab4eb4..3e8f0e84 100644 --- a/src/ocaml-protoc/ocaml_protoc_compilation.ml +++ b/src/ocaml-protoc/ocaml_protoc_compilation.ml @@ -76,7 +76,7 @@ let compile cmdline cmd_line_files_options : Ot.proto * _ = { proto with Pt.file_options = - Pb_option.merge proto.Pt.file_options cmd_line_files_options; + Pb_raw_option.merge proto.Pt.file_options cmd_line_files_options; }) protos in diff --git a/src/ocaml-protoc/ocaml_protoc_generation.mli b/src/ocaml-protoc/ocaml_protoc_generation.mli index 9a4295f0..d397f80f 100644 --- a/src/ocaml-protoc/ocaml_protoc_generation.mli +++ b/src/ocaml-protoc/ocaml_protoc_generation.mli @@ -4,4 +4,4 @@ module Ot = Pb_codegen_ocaml_type module Cmdline = Ocaml_protoc_cmdline.Cmdline val generate_code : - Ot.proto -> proto_file_options:Pb_option.set -> Cmdline.t -> unit + Ot.proto -> proto_file_options:Pb_raw_option.set -> Cmdline.t -> unit diff --git a/src/tests/expectation/option_processing.proto b/src/tests/expectation/option_processing.proto index 2247bfec..8aae5c13 100644 --- a/src/tests/expectation/option_processing.proto +++ b/src/tests/expectation/option_processing.proto @@ -40,3 +40,15 @@ message Person { float z = 8; } } + +message DestructuredOptions { + option (google.api.http).custom.kind = "FETCH"; + option (google.api.http).custom.path = "/foo/bar/baz/{id}"; + option (google.api.http).additional_bindings = { + get: "/foo/bar/baz/{id}" + }; + option (google.api.http).additional_bindings = { + post: "/foo/bar/baz/", + body: "*" + }; +} diff --git a/src/tests/unit-tests/parse_field_options.ml b/src/tests/unit-tests/parse_field_options.ml index 5a233968..b66436cd 100644 --- a/src/tests/unit-tests/parse_field_options.ml +++ b/src/tests/unit-tests/parse_field_options.ml @@ -1,7 +1,7 @@ let parse f s = f Pb_parsing_lexer.lexer (Lexing.from_string s) let has_option set option_name = - match Pb_option.get set (Pb_option.Simple_name option_name) with + match Pb_raw_option.get_simple set option_name with | None -> false | Some _ -> true @@ -9,9 +9,9 @@ module Pt = Pb_parsing_parse_tree let () = let test_default s = - Pb_option.get + Pb_raw_option.get_simple (parse Pb_parsing_parser.field_options_ s) - (Pb_option.Simple_name "default") + "default" |> function | Some (Pb_option.Scalar_value x) -> x | _ -> assert false @@ -34,7 +34,7 @@ let () = let () = let field_options = parse Pb_parsing_parser.field_options_ "[]" in - assert (field_options = Pb_option.empty) + assert (field_options = Pb_raw_option.empty) let () = let field_options = parse Pb_parsing_parser.field_options_ "[a=1,b=true]" in @@ -48,6 +48,6 @@ let () = in assert ( Some Pb_option.(Scalar_value (Constant_literal "int")) - = Pb_option.get_ext field_options "ocaml_type") + = Pb_raw_option.get_ext field_options "ocaml_type") let () = print_endline "Parse Field Options ... Ok" diff --git a/src/tests/unit-tests/parse_file_options.ml b/src/tests/unit-tests/parse_file_options.ml index feb73050..5a94680e 100644 --- a/src/tests/unit-tests/parse_file_options.ml +++ b/src/tests/unit-tests/parse_file_options.ml @@ -9,7 +9,8 @@ module Pt = Pb_parsing_parse_tree let () = let s = "option blah = 1;" in let fo = - Pb_option.Simple_name "blah", Pb_option.(Scalar_value (Constant_int 1)) + ( [ Pb_raw_option.Simple_name "blah" ], + Pb_option.(Scalar_value (Constant_int 1)) ) in assert (fo = parse s) @@ -19,10 +20,10 @@ let () = let fo_parsed = proto.Pt.file_options in assert ( Some Pb_option.(Scalar_value (Constant_int 1)) - = Pb_option.get fo_parsed (Pb_option.Simple_name "blah")); + = Pb_raw_option.get_simple fo_parsed "blah"); assert ( Some Pb_option.(Scalar_value (Constant_string "blah")) - = Pb_option.get fo_parsed (Pb_option.Simple_name "foo")); + = Pb_raw_option.get_simple fo_parsed "foo"); () let () = print_endline "Parse File Options ... Ok" From 8c3dbd54081f7ecb5a842f8aba50968b228f3010 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Sat, 2 Mar 2024 09:10:05 +0400 Subject: [PATCH 11/47] Proper compilation of options --- src/compilerlib/pb_raw_option.ml | 25 ++++ src/compilerlib/pb_raw_option.mli | 1 + src/compilerlib/pb_typing_validation.ml | 108 +++++++++++------- src/compilerlib/pb_typing_validation.mli | 1 - .../expectation/option_processing.ml.expected | 21 +++- src/tests/expectation/tests.expected | 46 ++++---- 6 files changed, 132 insertions(+), 70 deletions(-) diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml index 42a8a8ce..71bcd703 100644 --- a/src/compilerlib/pb_raw_option.ml +++ b/src/compilerlib/pb_raw_option.ml @@ -36,6 +36,31 @@ let get t option_name = let get_ext t option_name = get t [ Extension_name option_name ] let get_simple t option_name = get t [ Simple_name option_name ] +let assoc_option_name key alist = + try Some (List.find (fun (k, _) -> option_name_equal k key) alist |> snd) + with Not_found -> None + +let remove_assoc_option_name key alist = + List.filter (fun (k, _) -> not (option_name_equal k key)) alist + +let group_list_values (set : set) : set = + let rec aux grouped = function + | [] -> + List.map + (function + | name, [ value ] -> name, value + | name, values -> name, Pb_option.List_literal (List.rev values)) + grouped + | (name, value) :: xs -> + (match assoc_option_name name grouped with + | None -> aux ((name, [ value ]) :: grouped) xs + | Some prev_values -> + let grouped = remove_assoc_option_name name grouped in + aux ((name, value :: prev_values) :: grouped) xs) + in + + aux [] set + let pp_t ppf (name, value) = Format.fprintf ppf "{@;<1 2>%S: %a@;<1 2>}" (stringify_option_name name) diff --git a/src/compilerlib/pb_raw_option.mli b/src/compilerlib/pb_raw_option.mli index cb7b957b..83b55051 100644 --- a/src/compilerlib/pb_raw_option.mli +++ b/src/compilerlib/pb_raw_option.mli @@ -19,5 +19,6 @@ val merge : set -> set -> set val get : set -> option_name -> Pb_option.value option val get_ext : set -> string -> Pb_option.value option val get_simple : set -> string -> Pb_option.value option +val group_list_values : set -> set val pp_t : Format.formatter -> t -> unit val pp_set : Format.formatter -> set -> unit diff --git a/src/compilerlib/pb_typing_validation.ml b/src/compilerlib/pb_typing_validation.ml index b8211935..a556cf1c 100644 --- a/src/compilerlib/pb_typing_validation.ml +++ b/src/compilerlib/pb_typing_validation.ml @@ -28,6 +28,40 @@ module Pt = Pb_parsing_parse_tree module Tt = Pb_typing_type_tree module Typing_util = Pb_typing_util +let normalize_option_name option_name value = + List.fold_right + (fun name_part acc -> + match name_part with + | Pb_raw_option.Simple_name name -> + Pb_option.Message_literal [ name, acc ] + | Pb_raw_option.Extension_name name -> + failwith + (Printf.sprintf + "normalize_option_name: Extension_name '%s' is not supported in \ + option_name" + name)) + option_name value + +let option_name_from_part = function + | Pb_raw_option.Simple_name x -> Pb_option.Simple_name x + | Pb_raw_option.Extension_name x -> Pb_option.Extension_name x + +let normalize_option option_name value = + match option_name with + | [] -> failwith "option_name can't be an empty list!" + | [ single_item ] -> option_name_from_part single_item, value + | top_level_item :: rest -> + let new_value = normalize_option_name rest value in + option_name_from_part top_level_item, new_value + +let compile_options option_set = + let option_set = Pb_raw_option.group_list_values option_set in + List.fold_left + (fun set (option_name, value) -> + let option_name, value = normalize_option option_name value in + Pb_option.add set option_name value) + Pb_option.empty option_set + let scope_of_package : string option -> Tt.type_scope = function | Some s -> { @@ -51,6 +85,7 @@ let compile_field_p1 field_parsed : _ Tt.field = let { Pt.field_type; Pt.field_options; Pt.field_name; _ } = field_parsed in let field_default = get_default field_name field_options in + let field_options = compile_options field_options in { Tt.field_parsed; Tt.field_type; Tt.field_default; Tt.field_options } let compile_map_p1 map_parsed : _ Tt.map_field = @@ -63,7 +98,7 @@ let compile_map_p1 map_parsed : _ Tt.map_field = } = map_parsed in - + let map_options = compile_options map_options in Tt.{ map_name; map_number; map_key_type; map_value_type; map_options } let compile_oneof_p1 oneof_parsed : _ Tt.oneof = @@ -74,6 +109,17 @@ let compile_oneof_p1 oneof_parsed : _ Tt.oneof = Tt.oneof_options = Pb_option.empty; } in + let oneof_options = + oneof_parsed.Pt.oneof_body + |> Pb_util.List.filter_map (function + | Pt.Oneof_option o -> Some o + | _ -> None) + |> List.fold_left + (fun oneof_options (name, value) -> + Pb_raw_option.add oneof_options name value) + Pb_raw_option.empty + |> compile_options + in let oneof = List.fold_left (fun acc -> function @@ -82,15 +128,11 @@ let compile_oneof_p1 oneof_parsed : _ Tt.oneof = acc with Tt.oneof_fields = compile_field_p1 f :: acc.Tt.oneof_fields; } - | Pt.Oneof_option (name, value) -> - { - acc with - Tt.oneof_options = Pb_option.add acc.Tt.oneof_options name value; - }) + | _ -> acc) init oneof_parsed.Pt.oneof_body in (* now reverse the fields so they're back in the original order *) - { oneof with Tt.oneof_fields = List.rev oneof.oneof_fields } + { oneof with Tt.oneof_fields = List.rev oneof.oneof_fields; Tt.oneof_options } let not_found f : bool = try @@ -111,8 +153,7 @@ let make_proto_type ~file_name ~file_options ~id ~scope ~spec : _ Tt.proto_type { Tt.id; Tt.scope; Tt.file_name; Tt.file_options; Tt.spec } (** compile a [Pbpt] enum to a [Pbtt] type *) -let compile_enum_p1 ?(parent_options = Pb_option.empty) file_name file_options - scope parsed_enum = +let compile_enum_p1 file_name file_options scope parsed_enum = let { Pt.enum_id; enum_name; enum_body } = parsed_enum in let enum_values = @@ -120,6 +161,7 @@ let compile_enum_p1 ?(parent_options = Pb_option.empty) file_name file_options (function | Pt.Enum_value { Pt.enum_value_name; enum_value_int; enum_value_options } -> + let enum_value_options = compile_options enum_value_options in Some Tt.{ enum_value_name; enum_value_int; enum_value_options } | _ -> None) enum_body @@ -132,25 +174,19 @@ let compile_enum_p1 ?(parent_options = Pb_option.empty) file_name file_options | _ -> None) |> List.fold_left (fun enum_options (name, value) -> - Pb_option.add enum_options name value) - Pb_option.empty + Pb_raw_option.add enum_options name value) + Pb_raw_option.empty + |> compile_options in - let spec = - Tt.Enum - { - Tt.enum_name; - Tt.enum_values; - Tt.enum_options = Pb_option.merge parent_options enum_options; - } - in + let spec = Tt.Enum { Tt.enum_name; Tt.enum_values; Tt.enum_options } in make_proto_type ~file_name ~file_options ~id:enum_id ~scope ~spec (** compile a [Pbpt] message a list of [Pbtt] types (ie messages can defined more than one type). *) -let rec validate_message ?(parent_options = Pb_option.empty) file_name - file_options message_scope parsed_message : _ Tt.proto_type list = +let rec validate_message file_name file_options message_scope parsed_message : + _ Tt.proto_type list = let { Pt.id; Pt.message_name; Pt.message_body } = parsed_message in let { Tt.message_names; _ } = message_scope in @@ -166,17 +202,12 @@ let rec validate_message ?(parent_options = Pb_option.empty) file_name type ('a, 'b, 'd) t = { message_body: 'a list; extensions: 'b list; - options: Pb_option.set; + options: Pb_raw_option.set; all_types: 'd list; } - let e0 parent_options = - { - message_body = []; - extensions = []; - options = parent_options; - all_types = []; - } + let e0 = + { message_body = []; extensions = []; options = []; all_types = [] } end in let acc = List.fold_left @@ -194,28 +225,23 @@ let rec validate_message ?(parent_options = Pb_option.empty) file_name let field = Tt.Message_oneof_field (compile_oneof_p1 o) in { acc with Acc.message_body = field :: message_body } | Pt.Message_sub m -> - let parent_options = options in let all_sub_types = - validate_message ~parent_options file_name file_options sub_scope m + validate_message file_name file_options sub_scope m in { acc with Acc.all_types = all_types @ all_sub_types } | Pt.Message_enum parsed_enum -> - let parent_options = options in let enum = - compile_enum_p1 ~parent_options file_name file_options sub_scope - parsed_enum + compile_enum_p1 file_name file_options sub_scope parsed_enum in { acc with Acc.all_types = all_types @ [ enum ] } | Pt.Message_extension extension_ranges -> { acc with Acc.extensions = extensions @ extension_ranges } | Pt.Message_reserved _ -> acc (* TODO add support for checking reserved fields *) - | Pt.Message_option message_option -> - let options = - Pb_option.add options (fst message_option) (snd message_option) - in + | Pt.Message_option (name, value) -> + let options = Pb_raw_option.add options name value in { acc with Acc.options }) - (Acc.e0 parent_options) message_body + Acc.e0 message_body in let message_body = List.rev acc.Acc.message_body in @@ -264,7 +290,7 @@ let rec validate_message ?(parent_options = Pb_option.empty) file_name Tt.Message { Tt.extensions = acc.Acc.extensions; - message_options = acc.Acc.options; + message_options = acc.Acc.options |> compile_options; message_name; message_body; } @@ -299,6 +325,7 @@ let validate_service (scope : Tt.type_scope) ~file_name (service : Pt.service) : | `User_defined ty -> ty | _ -> E.invalid_rpc_res_type ~service_name ~rpc_name () in + let rpc_options = compile_options rpc_options in let rpc = { Tt.rpc_name; @@ -334,6 +361,7 @@ let validate (proto : Pt.proto) : _ Tt.proto = let file_name = Pb_util.Option.default "" proto_file_name in let scope = scope_of_package package in + let file_options = compile_options file_options in let pbtt_msgs = List.fold_right diff --git a/src/compilerlib/pb_typing_validation.mli b/src/compilerlib/pb_typing_validation.mli index 796a104e..9199073a 100644 --- a/src/compilerlib/pb_typing_validation.mli +++ b/src/compilerlib/pb_typing_validation.mli @@ -44,7 +44,6 @@ val validate : Pt.proto -> Pb_field_type.unresolved Tt.proto (** {2 Testing Only} *) val validate_message : - ?parent_options:Pb_option.set -> string -> Pb_option.set -> (* file options *) diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index 1cb0d9c5..4a7ffac5 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -25,6 +25,8 @@ and person = { id : person_id option; } +type destructured_options = unit + let rec default_payment_system () = (Cash:payment_system) let rec default_person_location @@ -53,6 +55,8 @@ and default_person id; } +let rec default_destructured_options = () + [@@@ocaml.warning "-27-30-39"] (** {2 Dump of internal representation for generated OCaml types} *) @@ -102,9 +106,7 @@ and default_person "(validate.rules)": {"double": {"gte": -180, "lte": 180}} }] - Options: [{ - "(validate.disabled)": true - }] + Options: [] *) (* ----------------------------------------------------- *) @@ -173,3 +175,16 @@ and default_person "(validate.disabled)": true }] *) + +(* ----------------------------------------------------- *) +(* + Module Prefix: Option_processing + Empty Record: destructured_options + Options: [{ + "(google.api.http)": {"custom": {"path": "/foo/bar/baz/{id}", + "kind": "FETCH"}, + "additional_bindings": [{"post": "/foo/bar/baz/", + "body": "*"}, + {"get": "/foo/bar/baz/{id}"}]} + }] +*) diff --git a/src/tests/expectation/tests.expected b/src/tests/expectation/tests.expected index 320b1a3f..47c8f61b 100644 --- a/src/tests/expectation/tests.expected +++ b/src/tests/expectation/tests.expected @@ -713,8 +713,7 @@ field_label = `Nolabel; field_type = Uint64; field_options = [{ - "(validate.rules)": { - "uint64": {"gt": 999}} + "(validate.rules).uint64.gt": 999 }]; }; { @@ -723,8 +722,7 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "(validate.rules)": { - "string": {"email": true}} + "(validate.rules).string.email": true }]; }; { @@ -733,9 +731,9 @@ field_label = `Nolabel; field_type = String; field_options = [{ - "(validate.rules)": { - "string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", - "max_bytes": 256}} + "(validate.rules).string": { + "pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256} }]; }; { @@ -748,8 +746,7 @@ from_root: false }; field_options = [{ - "(validate.rules)": { - "message": {"required": true}} + "(validate.rules).message.required": true }]; }; { @@ -762,9 +759,9 @@ field_type = Double; field_options = [ { - "(validate.rules)": { - "double": {"gte": -90, - "lte": 90}} + "(validate.rules).double": { + "gte": -90, + "lte": 90} }]; }; { @@ -774,9 +771,9 @@ field_type = Double; field_options = [ { - "(validate.rules)": { - "double": {"gte": -180, - "lte": 180}} + "(validate.rules).double": { + "gte": -180, + "lte": 180} }]; }]; }]; @@ -795,8 +792,7 @@ field_type = String; field_options = [ { - "(validate.rules)": { - "string": {"len": 5}} + "(validate.rules).string.len": 5 }]; }; { @@ -826,11 +822,10 @@ field_label = `Nolabel; field_type = Uint32; field_options = [{ - "(validate.rules)": { - "uint32": {"in": [ - 1, - 2, - 3]}} + "(validate.rules).uint32": { + "in": [1, + 2, + 3]} }]; }; { @@ -839,10 +834,9 @@ field_label = `Nolabel; field_type = Float; field_options = [{ - "(validate.rules)": { - "float": {"not_in": [ - 0, - 0.990000]}} + "(validate.rules).float": { + "not_in": [0, + 0.990000]} }]; }]; }]; From ba200df1a20389f26d4c5e4a7565a91d786dccd3 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Sat, 2 Mar 2024 09:15:40 +0400 Subject: [PATCH 12/47] Remove `merge` from Pb_option It's unsound to merge two sets of (compiled) Pb_options --- src/compilerlib/pb_option.ml | 5 ----- src/compilerlib/pb_option.mli | 4 ---- 2 files changed, 9 deletions(-) diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index b3551ec5..08350a5c 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -74,11 +74,6 @@ let add option_set option_name value = "This should not happen, partition should result in at most single item \ in left component" -let merge set1 set2 = - List.fold_left - (fun acc (option_name, value) -> add acc option_name value) - set1 set2 - let get t option_name = match List.find (fun (other, _) -> option_name_equal option_name other) t with | _, c -> Some c diff --git a/src/compilerlib/pb_option.mli b/src/compilerlib/pb_option.mli index 7e13dc71..248a249d 100644 --- a/src/compilerlib/pb_option.mli +++ b/src/compilerlib/pb_option.mli @@ -34,10 +34,6 @@ val stringify_option_name : option_name -> string val empty : set val add : set -> option_name -> value -> set -val merge : set -> set -> set -(** [merge s1 s2] adds all the options from [s2] to [s1]. This means - than in case of duplicates [s2] options will override [s1] options. *) - val get : set -> option_name -> value option val get_ext : set -> string -> value option val pp_constant : Format.formatter -> constant -> unit From 2e42b6ac79fa10eceed6e586e4d89a6f3716cf87 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Sat, 2 Mar 2024 09:18:31 +0400 Subject: [PATCH 13/47] Make Pb_raw_option.merge actually override options --- src/compilerlib/pb_raw_option.ml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml index 71bcd703..0b7afe72 100644 --- a/src/compilerlib/pb_raw_option.ml +++ b/src/compilerlib/pb_raw_option.ml @@ -23,11 +23,6 @@ let option_name_equal = List.equal option_name_part_equal let empty = [] let add option_set option_name value = (option_name, value) :: option_set -let merge set1 set2 = - List.fold_left - (fun acc (option_name, value) -> add acc option_name value) - set1 set2 - let get t option_name = match List.find (fun (other, _) -> option_name_equal option_name other) t with | _, c -> Some c @@ -43,6 +38,13 @@ let assoc_option_name key alist = let remove_assoc_option_name key alist = List.filter (fun (k, _) -> not (option_name_equal k key)) alist +let merge set1 set2 = + List.fold_left + (fun acc (option_name, value) -> + let acc = remove_assoc_option_name option_name acc in + add acc option_name value) + set1 set2 + let group_list_values (set : set) : set = let rec aux grouped = function | [] -> From f6df3fde8bb03f3dba195884d9acacbc85a0be71 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Sat, 2 Mar 2024 10:18:14 +0400 Subject: [PATCH 14/47] Add documentation --- src/compilerlib/pb_option.ml | 27 +++++++- src/compilerlib/pb_option.mli | 87 +++++++++++++++++++++++-- src/compilerlib/pb_parsing_util.ml | 27 -------- src/compilerlib/pb_raw_option.ml | 25 +++++++ src/compilerlib/pb_raw_option.mli | 84 ++++++++++++++++++++++++ src/compilerlib/pb_typing_validation.ml | 20 +++++- 6 files changed, 236 insertions(+), 34 deletions(-) diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index 08350a5c..2c90fb9b 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -1,3 +1,28 @@ +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + type constant = | Constant_string of string | Constant_bool of bool @@ -57,7 +82,7 @@ let rec merge_value v1 v2 = merge_lists (updated_list @ [ field, value ]) rest in Message_literal (merge_lists ml1 ml2) - | _ -> v2 + | _ -> v2 (* FIXME: This overrides an existing value, which is not allowed *) let add option_set option_name value = match diff --git a/src/compilerlib/pb_option.mli b/src/compilerlib/pb_option.mli index 248a249d..1df2d0b9 100644 --- a/src/compilerlib/pb_option.mli +++ b/src/compilerlib/pb_option.mli @@ -1,4 +1,73 @@ -(** Protobuf File/Message/Field options *) +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + +(** Protobuf File/Message/Field options + +This module represents "compiled" option set, which is high level +representation, as opposed to low-level representation in Pb_raw_option module. + +For the following "raw" set of options: + +{[ + option (google.api.http).custom.kind = "FETCH"; + option (google.api.http).custom.path = "/foo/bar/baz/{id}"; + option (google.api.http).additional_bindings = { + get: "/foo/bar/baz/{id}" + }; + option (google.api.http).additional_bindings = { + post: "/foo/bar/baz/" + body: "*" + }; +]} + +The "compiled" representation will have only one option [(google.api.http)], +which is a message: + +{[ + option (google.api.http) = { + custom: { + kind: "FETCH" + path: "/foo/bar/baz/{id}" + } + additional_bindings: [ + { + get: "/foo/bar/baz/{id}" + }, + { + post: "/foo/bar/baz/" + body: "*" + } + ] + }; +]} + +Option normalization is happening in [Pb_typing_validation.normalize_option], +destructured field assigments are normalized back to nested messages. See +[Pb_typing_validation.compile_option] to see the full process of option +compilation. +*) (** Protobuf constant @@ -18,7 +87,7 @@ and value = | Message_literal of message_literal | List_literal of list_literal -(** Option identifier *) +(** Top level option name *) type option_name = | Simple_name of string | Extension_name of string @@ -26,16 +95,24 @@ type option_name = type t = option_name * value type set = t list -(** Collection of options - - Can be used for field/message or file options *) +(** Compiled collection of options *) val stringify_option_name : option_name -> string val empty : set + val add : set -> option_name -> value -> set +(** [add set name value] adds option [(name, value)] into the [set]. Option name +and value are expected to be normalized (see +[Pb_typing_validation.normalize_option]). [add] is merging nested message +literals within option value with the ones that were previously added to the +[set]. *) val get : set -> option_name -> value option + val get_ext : set -> string -> value option +(** [get_ext set name] is a helper that retrieves [Extension_name name] option +from [set] *) + val pp_constant : Format.formatter -> constant -> unit val pp_value : Format.formatter -> value -> unit val pp_message_literal : Format.formatter -> message_literal -> unit diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index 6741118b..a2c52ba5 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -140,33 +140,6 @@ let option_name_of_ident ident = |> List.map (fun x -> Pb_raw_option.Simple_name x) let option_name_extension ident = [ Pb_raw_option.Extension_name ident ] - -(* let normalize_option_name option_name value = - List.fold_right - (fun name_part acc -> - match name_part with - | Pb_raw_option.Simple_name name -> - Pb_option.Message_literal [ name, acc ] - | Pb_raw_option.Extension_name name -> - failwith - (Printf.sprintf - "normalize_option_name: Extension_name '%s' is not supported in \ - option_name" - name)) - option_name value - - let option_name_from_part = function - | Pb_raw_option.Simple_name x -> Pb_option.Simple_name x - | Pb_raw_option.Extension_name x -> Pb_option.Extension_name x - - let normalize_option option_name value = - match option_name with - | [] -> failwith "option_name can't be an empty list!" - | [ single_item ] -> option_name_from_part single_item, value - | top_level_item :: rest -> - let new_value = normalize_option_name rest value in - option_name_from_part top_level_item, new_value *) - let service ~content service_name = Pt.{ service_name; service_body = content } let import ?public file_name = diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml index 0b7afe72..866d95ab 100644 --- a/src/compilerlib/pb_raw_option.ml +++ b/src/compilerlib/pb_raw_option.ml @@ -1,3 +1,28 @@ +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + type name_part = Pb_option.option_name = | Simple_name of string | Extension_name of string diff --git a/src/compilerlib/pb_raw_option.mli b/src/compilerlib/pb_raw_option.mli index 83b55051..7d7d8ef8 100644 --- a/src/compilerlib/pb_raw_option.mli +++ b/src/compilerlib/pb_raw_option.mli @@ -1,5 +1,57 @@ +(* + The MIT License (MIT) + + Copyright (c) 2016 Maxime Ransan + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*) + (** Protobuf File/Message/Field raw options (i.e. exactly as they parsed) *) +(* +Option names in Protobuf are complicated. See their syntax definition: + + +OptionName = ( SimpleName | ExtensionName ) [ dot OptionName ] . + +SimpleName = identifier . +ExtensionName = l_paren TypeName r_paren + + + +Example of option names are below: + +deprecated +json_name +(foo.bar) +abc.def.xyz +(foo).bar.(.baz.bob) + + +This module is low-level, it tracks list of options as they were parsed, option +name is a list of parts according to syntax specification. Option can be present +multiple times, which means it's a destructured list (see [group_list_values]). + +Good read on Protobuf options: https://github.com/bufbuild/protobuf-language-spec/blob/main/language-spec.md#options +*) + type name_part = | Simple_name of string | Extension_name of string @@ -19,6 +71,38 @@ val merge : set -> set -> set val get : set -> option_name -> Pb_option.value option val get_ext : set -> string -> Pb_option.value option val get_simple : set -> string -> Pb_option.value option + val group_list_values : set -> set +(** [group_list_values set] groups options with the same name into Pb_option.List_literal + +The following set of options: + +{[ + option (google.api.http).additional_bindings = { + get: "/foo/bar/baz/{id}" + }; + option (google.api.http).additional_bindings = { + post: "/foo/bar/baz/" + body: "*" + }; +]} + +Is equivalent to the below non-destructured version: + +{[ + option (google.api.http) = { + additional_bindings: [ + { + get: "/foo/bar/baz/{id}" + }, + { + post: "/foo/bar/baz/" + body: "*" + } + ] + }; +]} +*) + val pp_t : Format.formatter -> t -> unit val pp_set : Format.formatter -> set -> unit diff --git a/src/compilerlib/pb_typing_validation.ml b/src/compilerlib/pb_typing_validation.ml index a556cf1c..7aa45bf5 100644 --- a/src/compilerlib/pb_typing_validation.ml +++ b/src/compilerlib/pb_typing_validation.ml @@ -28,6 +28,7 @@ module Pt = Pb_parsing_parse_tree module Tt = Pb_typing_type_tree module Typing_util = Pb_typing_util +(** Re-construct nested messages out of field path *) let normalize_option_name option_name value = List.fold_right (fun name_part acc -> @@ -35,6 +36,8 @@ let normalize_option_name option_name value = | Pb_raw_option.Simple_name name -> Pb_option.Message_literal [ name, acc ] | Pb_raw_option.Extension_name name -> + (* TODO: Consider supporting Extension_name in option names, as in + (foo).bar.(.baz.bob) *) failwith (Printf.sprintf "normalize_option_name: Extension_name '%s' is not supported in \ @@ -49,16 +52,27 @@ let option_name_from_part = function let normalize_option option_name value = match option_name with | [] -> failwith "option_name can't be an empty list!" - | [ single_item ] -> option_name_from_part single_item, value + | [ single_item ] -> + (* Only one top level component in option name - nothing fancy is required + in this case *) + option_name_from_part single_item, value | top_level_item :: rest -> + (* Top level option is a message, and we need to reconstruct nested messages + inside the value, and leave only top level name component as actual option + name *) let new_value = normalize_option_name rest value in option_name_from_part top_level_item, new_value +(** [compile_options set] is compiling raw options into Pb_option.set *) let compile_options option_set = + (* Handle destructured lists *) let option_set = Pb_raw_option.group_list_values option_set in List.fold_left (fun set (option_name, value) -> + (* Normalize option names into nested messages within values *) let option_name, value = normalize_option option_name value in + (* Pb_option.add is smart to merge nested messages, reconstructing the + final message values *) Pb_option.add set option_name value) Pb_option.empty option_set @@ -109,6 +123,8 @@ let compile_oneof_p1 oneof_parsed : _ Tt.oneof = Tt.oneof_options = Pb_option.empty; } in + (* Compile one-of options separately, as compilation requires to see all raw + options at once *) let oneof_options = oneof_parsed.Pt.oneof_body |> Pb_util.List.filter_map (function @@ -167,6 +183,8 @@ let compile_enum_p1 file_name file_options scope parsed_enum = enum_body in + (* Compile enum options separately, as compilation requires to see all raw + options at once *) let enum_options = enum_body |> Pb_util.List.filter_map (function From 733f4c92c615fcb26c1b164982c44e2b2c373337 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Sat, 2 Mar 2024 10:43:16 +0400 Subject: [PATCH 15/47] Even moar documentation --- src/compilerlib/pb_option.ml | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/compilerlib/pb_option.ml b/src/compilerlib/pb_option.ml index 2c90fb9b..554d4966 100644 --- a/src/compilerlib/pb_option.ml +++ b/src/compilerlib/pb_option.ml @@ -60,6 +60,11 @@ let empty = [] let rec merge_value v1 v2 = match v1, v2 with | Message_literal ml1, Message_literal ml2 -> + (* In this case, both the existing and new values are messages. + Iterate through the fields of the new value. + For each field, check if a field with the same name exists in the existing value. + If it does and both field values are messages, merge them recursively. + If it does not, add the new field to the existing message. *) let rec merge_lists list1 list2 = match list2 with | [] -> list1 @@ -67,22 +72,33 @@ let rec merge_value v1 v2 = let updated_list, is_merged = List.fold_left (fun (acc, merged) (f, v) -> - if f = field then ( + if String.equal f field then ( match value, v with | Message_literal _, Message_literal _ -> - acc @ [ f, merge_value value v ], true + ( acc @ [ f, merge_value value v ], + true (* recursively merges two message literals *) ) | _ -> acc @ [ f, value ], merged ) else acc @ [ f, v ], merged) ([], false) list1 in if is_merged then + (* If the current field of list2 was found in list1 and the two + values merged, continue with the rest of list2. The current field of + list2 is not added to updated_list as its value has already been + included during the merge. *) merge_lists updated_list rest else + (* If the current field of list2 was not found in list1, add it to + updated_list. *) merge_lists (updated_list @ [ field, value ]) rest in Message_literal (merge_lists ml1 ml2) - | _ -> v2 (* FIXME: This overrides an existing value, which is not allowed *) + | _ -> + (* FIXME: This overrides the scalar value of an existing option with the + scalar value of a new option, which is not allowed as per Protocol Buffer + Language Specification. *) + v2 let add option_set option_name value = match @@ -90,11 +106,17 @@ let add option_set option_name value = (fun ((name, _) : t) -> option_name_equal name option_name) option_set with - | [], _ -> (option_name, value) :: option_set + | [], _ -> + (* If the option does not currently exist in the set, add it *) + (option_name, value) :: option_set | [ (_, existing_value) ], remainder -> + (* If the option already exists in the set, merge it's value with the new value *) let merged_value = merge_value existing_value value in (option_name, merged_value) :: remainder | _ -> + (* This is a sanity check. As we use an equality function, List.partition should + * always partition the list into two lists where the first list has at most one element. + * Hence, the condition that results in a call to failwith should never be satisfied. *) failwith "This should not happen, partition should result in at most single item \ in left component" From 86dd22c1e3856281043785c4a282dcc4263e9c50 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Fri, 8 Mar 2024 08:52:19 +0400 Subject: [PATCH 16/47] Support OCaml 4.08 (missing List.equal) --- src/compilerlib/pb_raw_option.ml | 2 +- src/compilerlib/pb_util.ml | 6 ++++++ src/compilerlib/pb_util.mli | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml index 866d95ab..cc7c2f4e 100644 --- a/src/compilerlib/pb_raw_option.ml +++ b/src/compilerlib/pb_raw_option.ml @@ -44,7 +44,7 @@ let option_name_part_equal a b = | Extension_name a, Extension_name b -> String.equal a b | _ -> false -let option_name_equal = List.equal option_name_part_equal +let option_name_equal = Pb_util.List.equal option_name_part_equal let empty = [] let add option_set option_name value = (option_name, value) :: option_set diff --git a/src/compilerlib/pb_util.ml b/src/compilerlib/pb_util.ml index 2163d46b..6b273dff 100644 --- a/src/compilerlib/pb_util.ml +++ b/src/compilerlib/pb_util.ml @@ -136,6 +136,12 @@ module List = struct (match f x with | Some _ as r -> r | None -> find_map f tl) + + let rec equal eq l1 l2 = + match l1, l2 with + | [], [] -> true + | [], _ :: _ | _ :: _, [] -> false + | a1 :: l1, a2 :: l2 -> eq a1 a2 && equal eq l1 l2 end module Int_map = Map.Make (struct diff --git a/src/compilerlib/pb_util.mli b/src/compilerlib/pb_util.mli index 4320c7a7..55426f89 100644 --- a/src/compilerlib/pb_util.mli +++ b/src/compilerlib/pb_util.mli @@ -84,6 +84,18 @@ module List : sig val find_opt : ('a -> bool) -> 'a list -> 'a option val find_map : ('a -> 'b option) -> 'a list -> 'b option + + val equal : ('a -> 'a -> bool) -> 'a list -> 'a list -> bool + (** [equal eq [a1; ...; an] [b1; ..; bm]] holds when + the two input lists have the same length, and for each + pair of elements [ai], [bi] at the same position we have + [eq ai bi]. + + Note: the [eq] function may be called even if the + lists have different length. If you know your equality + function is costly, you may want to check {!compare_lengths} + first. +*) end module Str_map : Map.S with type key = string From 5f3beb00761116e5e545cb5b08a826dc960c17c7 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Fri, 8 Mar 2024 09:00:54 +0400 Subject: [PATCH 17/47] String.starts_with... --- src/compilerlib/pb_parsing_util.ml | 2 +- src/compilerlib/pb_util.ml | 16 ++++++++++++++++ src/compilerlib/pb_util.mli | 9 +++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index a2c52ba5..19e96036 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -131,7 +131,7 @@ let option_list items = Pb_option.List_literal items let option_name_of_ident ident = let ident = - if String.starts_with ~prefix:"." ident then + if Pb_util.String.starts_with ~prefix:"." ident then String.sub ident 1 (String.length ident - 1) else ident diff --git a/src/compilerlib/pb_util.ml b/src/compilerlib/pb_util.ml index 6b273dff..dbe15c86 100644 --- a/src/compilerlib/pb_util.ml +++ b/src/compilerlib/pb_util.ml @@ -47,6 +47,22 @@ let string_fold_lefti f e0 s = in loop e0 0 +module String = struct + include String + + let starts_with ~prefix s = + let len_s = length s and len_pre = length prefix in + let rec aux i = + if i = len_pre then + true + else if unsafe_get s i <> unsafe_get prefix i then + false + else + aux (i + 1) + in + len_s >= len_pre && aux 0 +end + module Option = struct let default x = function | Some y -> y diff --git a/src/compilerlib/pb_util.mli b/src/compilerlib/pb_util.mli index 55426f89..5dc120ba 100644 --- a/src/compilerlib/pb_util.mli +++ b/src/compilerlib/pb_util.mli @@ -42,6 +42,14 @@ val string_fold_lefti : ('a -> int -> char -> 'a) -> 'a -> string -> 'a val indentation_prefix : int -> string (** [indentation_prefix level] returns a string of [2 * level] spaces *) +module String : sig + val starts_with : + prefix:(* comment thwarts tools/sync_stdlib_docs *) string -> string -> bool + (** [starts_with ][~prefix s] is [true] if and only if [s] starts with + [prefix]. + *) +end + module Option : sig val default : 'a -> 'a option -> 'a (** [option_default x o] returns [x] is [o] is [None] otherwise [y] @@ -93,6 +101,7 @@ module List : sig Note: the [eq] function may be called even if the lists have different length. If you know your equality + function is costly, you may want to check {!compare_lengths} first. *) From 0b2a40058367d9a2bf8e8e16699ca147e9566def Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Fri, 7 Jun 2024 08:54:37 +0400 Subject: [PATCH 18/47] Attempt to repro bug with tests --- src/compilerlib/pb_typing_validation.mli | 2 + src/tests/expectation/dune | 10 ++- .../test_option_compilation.expected | 82 +++++++++++++++++++ .../expectation/test_option_compilation.ml | 74 +++++++++++++++++ ....expected => test_option_parsing.expected} | 0 .../{tests.ml => test_option_parsing.ml} | 0 6 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 src/tests/expectation/test_option_compilation.expected create mode 100644 src/tests/expectation/test_option_compilation.ml rename src/tests/expectation/{tests.expected => test_option_parsing.expected} (100%) rename src/tests/expectation/{tests.ml => test_option_parsing.ml} (100%) diff --git a/src/compilerlib/pb_typing_validation.mli b/src/compilerlib/pb_typing_validation.mli index 9199073a..17a1d20c 100644 --- a/src/compilerlib/pb_typing_validation.mli +++ b/src/compilerlib/pb_typing_validation.mli @@ -50,3 +50,5 @@ val validate_message : Tt.type_scope -> Pt.message -> Pb_field_type.unresolved Tt.proto_type list + +val compile_options : Pb_raw_option.set -> Pb_option.set diff --git a/src/tests/expectation/dune b/src/tests/expectation/dune index bbcc4c9f..0912187d 100644 --- a/src/tests/expectation/dune +++ b/src/tests/expectation/dune @@ -1,5 +1,13 @@ (test - (name tests) + (name test_option_parsing) + (modules Test_option_parsing) + (libraries pbrt ocaml-protoc.compiler-lib) + (package ocaml-protoc) + (flags :standard -open Ocaml_protoc_compiler_lib)) + +(test + (name test_option_compilation) + (modules Test_option_compilation) (libraries pbrt ocaml-protoc.compiler-lib) (package ocaml-protoc) (flags :standard -open Ocaml_protoc_compiler_lib)) diff --git a/src/tests/expectation/test_option_compilation.expected b/src/tests/expectation/test_option_compilation.expected new file mode 100644 index 00000000..b9667e20 --- /dev/null +++ b/src/tests/expectation/test_option_compilation.expected @@ -0,0 +1,82 @@ +====================== ====================== + + message M { + option packed = true; + } + +===================== ====================== +======================= ======================= +-- message options -- +RAW: +[{ + "packed": true + }] + +COMPILED: +[{ + "packed": true + }] +====================== ======================= + + +====================== ====================== + + message PackedField { + repeated float inner = 1 [packed=true]; + } + +===================== ====================== +======================= ======================= +-- field options -- +RAW: +[{ + "packed": true + }] + +COMPILED: +[{ + "packed": true + }] + +-- message options -- +RAW: +[] + +COMPILED: +[] +====================== ======================= + + +====================== ====================== + + syntax = "proto3"; + message PackedField { + repeated float inner = 1 [packed=true]; + } + +===================== ====================== +======================= ======================= +-- field options -- +RAW: +[{ + "packed": true + }, + { + "packed": true + }] + +COMPILED: +[{ + "packed": [true, + true] + }] + +-- message options -- +RAW: +[] + +COMPILED: +[] +====================== ======================= + + diff --git a/src/tests/expectation/test_option_compilation.ml b/src/tests/expectation/test_option_compilation.ml new file mode 100644 index 00000000..8ea69c3a --- /dev/null +++ b/src/tests/expectation/test_option_compilation.ml @@ -0,0 +1,74 @@ +module E = Pb_exception +module Pt = Pb_parsing_parse_tree + +let pp_compiled ppf options = + Format.fprintf ppf "RAW:@.%a@.@.COMPILED:@.%a" Pb_raw_option.pp_set options + Pb_option.pp_set + (Pb_typing_validation.compile_options options) + +let run proto = + let maybe_protos = + try + Pb_parsing.parse_file + (fun f -> + match f with + | "test.proto" -> f, proto + | _ -> f, "") + "test.proto" + |> Result.ok + with e -> Error e + in + let pp_maybe_protos ppf = function + | Ok [ (proto : Pt.proto) ] -> + (match proto.messages with + | [ message ] -> + let raw_options = + message.message_body + |> List.filter_map (function + | Pt.Message_option opt -> Some opt + | Pt.Message_field field -> + Format.fprintf ppf "-- field options --@.%a@.@." pp_compiled + field.field_options; + None + | _ -> None) + |> List.fold_left + (fun oneof_options (name, value) -> + Pb_raw_option.add oneof_options name value) + Pb_raw_option.empty + in + Format.fprintf ppf "-- message options --@.%a" pp_compiled raw_options + | _ -> Format.fprintf ppf "[!] Only one message is expected") + | Ok _ -> Format.fprintf ppf "[!] Only one proto is expected" + | Error exn -> Format.fprintf ppf "[!] EXN: %s" (Printexc.to_string exn) + in + let ppf = Format.std_formatter in + Format.set_margin 149; + Format.fprintf ppf + "====================== \ + ======================@.%a@.===================== \ + ======================@.======================= \ + =======================@.%a@.====================== =======================@.@.@." + Format.pp_print_string proto pp_maybe_protos maybe_protos + +let test_cases = + [ + {| + message M { + option packed = true; + } + |}; + {| + message PackedField { + repeated float inner = 1 [packed=true]; + } + |}; + {| + syntax = "proto3"; + message PackedField { + repeated float inner = 1 [packed=true]; + } + |}; + ] + +let () = List.iter run test_cases diff --git a/src/tests/expectation/tests.expected b/src/tests/expectation/test_option_parsing.expected similarity index 100% rename from src/tests/expectation/tests.expected rename to src/tests/expectation/test_option_parsing.expected diff --git a/src/tests/expectation/tests.ml b/src/tests/expectation/test_option_parsing.ml similarity index 100% rename from src/tests/expectation/tests.ml rename to src/tests/expectation/test_option_parsing.ml From 9bf7fb0fe7069de51d5d367350cd6d892b039e25 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Fri, 7 Jun 2024 09:41:45 +0400 Subject: [PATCH 19/47] Fix duplicate packed options bug --- src/compilerlib/pb_parsing_util.ml | 2 +- src/compilerlib/pb_raw_option.ml | 9 +++++++++ src/compilerlib/pb_raw_option.mli | 1 + src/tests/expectation/test_option_compilation.expected | 6 +----- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/compilerlib/pb_parsing_util.ml b/src/compilerlib/pb_parsing_util.ml index 19e96036..c91f63af 100644 --- a/src/compilerlib/pb_parsing_util.ml +++ b/src/compilerlib/pb_parsing_util.ml @@ -328,7 +328,7 @@ let finalize_syntax3 proto = | `Bool -> let field_options = Pb_raw_option.( - add field_options [ Simple_name "packed" ] + add_or_replace field_options [ Simple_name "packed" ] (Scalar_value (Constant_bool true))) in { field with Pt.field_options } diff --git a/src/compilerlib/pb_raw_option.ml b/src/compilerlib/pb_raw_option.ml index cc7c2f4e..30ec47fb 100644 --- a/src/compilerlib/pb_raw_option.ml +++ b/src/compilerlib/pb_raw_option.ml @@ -48,6 +48,15 @@ let option_name_equal = Pb_util.List.equal option_name_part_equal let empty = [] let add option_set option_name value = (option_name, value) :: option_set +let add_or_replace option_set option_name value = + let option_set = + List.filter + (fun (option_name', _) -> + not (option_name_equal option_name' option_name)) + option_set + in + add option_set option_name value + let get t option_name = match List.find (fun (other, _) -> option_name_equal option_name other) t with | _, c -> Some c diff --git a/src/compilerlib/pb_raw_option.mli b/src/compilerlib/pb_raw_option.mli index 7d7d8ef8..5b1cfadd 100644 --- a/src/compilerlib/pb_raw_option.mli +++ b/src/compilerlib/pb_raw_option.mli @@ -63,6 +63,7 @@ type set = t list val stringify_option_name : option_name -> string val empty : set val add : set -> option_name -> Pb_option.value -> set +val add_or_replace : set -> option_name -> Pb_option.value -> set val merge : set -> set -> set (** [merge s1 s2] adds all the options from [s2] to [s1]. This means diff --git a/src/tests/expectation/test_option_compilation.expected b/src/tests/expectation/test_option_compilation.expected index b9667e20..ce8305cb 100644 --- a/src/tests/expectation/test_option_compilation.expected +++ b/src/tests/expectation/test_option_compilation.expected @@ -59,16 +59,12 @@ COMPILED: -- field options -- RAW: [{ - "packed": true - }, - { "packed": true }] COMPILED: [{ - "packed": [true, - true] + "packed": true }] -- message options -- From 7255b2f10045c78d43aca28f7332b91720348bc7 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 7 Feb 2024 13:07:58 -0500 Subject: [PATCH 20/47] silence warning 44 in generated code --- src/compilerlib/pb_codegen_all.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compilerlib/pb_codegen_all.ml b/src/compilerlib/pb_codegen_all.ml index 13d6cb17..7a822768 100644 --- a/src/compilerlib/pb_codegen_all.ml +++ b/src/compilerlib/pb_codegen_all.ml @@ -48,7 +48,7 @@ let new_ocaml_mod ~proto_file_options ~proto_file_name () : ocaml_mod = in (* write preludes *) - F.line self.ml "[@@@ocaml.warning \"-27-30-39\"]"; + F.line self.ml "[@@@ocaml.warning \"-27-30-39-44\"]"; F.empty_line self.ml; print_ppx self.ml; F.empty_line self.mli; From 7be41a6e0bc3ddf2f15ace0aff22e65738dead4d Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 7 Feb 2024 14:02:17 -0500 Subject: [PATCH 21/47] update tests --- src/examples/build_server.ml.expected | 2 +- src/examples/calculator.ml.expected | 2 +- src/examples/example01.ml.expected | 2 +- src/examples/example03.ml.expected | 2 +- src/examples/example04.ml.expected | 2 +- src/examples/example05.ml.expected | 2 +- src/examples/file_server.ml.expected | 2 +- src/examples/orgchart.ml.expected | 2 +- src/tests/expectation/option_processing.ml.expected | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/examples/build_server.ml.expected b/src/examples/build_server.ml.expected index ef537783..44dd2584 100644 --- a/src/examples/build_server.ml.expected +++ b/src/examples/build_server.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type file_path = { path : string; diff --git a/src/examples/calculator.ml.expected b/src/examples/calculator.ml.expected index aa1ff3e7..92c79a29 100644 --- a/src/examples/calculator.ml.expected +++ b/src/examples/calculator.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type div_by_zero = unit diff --git a/src/examples/example01.ml.expected b/src/examples/example01.ml.expected index a5a8177d..15e076fc 100644 --- a/src/examples/example01.ml.expected +++ b/src/examples/example01.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type person = { name : string; diff --git a/src/examples/example03.ml.expected b/src/examples/example03.ml.expected index 5b8cc697..0644837f 100644 --- a/src/examples/example03.ml.expected +++ b/src/examples/example03.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type string_some_none = unit diff --git a/src/examples/example04.ml.expected b/src/examples/example04.ml.expected index ee2b3158..7effa1dd 100644 --- a/src/examples/example04.ml.expected +++ b/src/examples/example04.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type int_list_nil = unit diff --git a/src/examples/example05.ml.expected b/src/examples/example05.ml.expected index d9d52b7d..1db8fcfa 100644 --- a/src/examples/example05.ml.expected +++ b/src/examples/example05.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type person = { name : string; diff --git a/src/examples/file_server.ml.expected b/src/examples/file_server.ml.expected index 324b4cca..0294aec9 100644 --- a/src/examples/file_server.ml.expected +++ b/src/examples/file_server.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type file_chunk = { path : string; diff --git a/src/examples/orgchart.ml.expected b/src/examples/orgchart.ml.expected index bb9379b4..f6933126 100644 --- a/src/examples/orgchart.ml.expected +++ b/src/examples/orgchart.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type person = { name : string; diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index 4a7ffac5..72bc09b8 100644 --- a/src/tests/expectation/option_processing.ml.expected +++ b/src/tests/expectation/option_processing.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type payment_system = | Cash From f7497f7f2c53ceb9a194b649138d454dde2ee2ab Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 13 Feb 2024 12:49:28 -0500 Subject: [PATCH 22/47] test: add bytecode-only tests --- src/tests/unit-tests/bytecode/dune | 7 +++ src/tests/unit-tests/bytecode/pbrt_array.ml | 55 ++++++++++++++++++ src/tests/unit-tests/bytecode/varint.ml | 57 +++++++++++++++++++ .../unit-tests/bytecode/wrapper_encoding.ml | 44 ++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 src/tests/unit-tests/bytecode/dune create mode 100644 src/tests/unit-tests/bytecode/pbrt_array.ml create mode 100644 src/tests/unit-tests/bytecode/varint.ml create mode 100644 src/tests/unit-tests/bytecode/wrapper_encoding.ml diff --git a/src/tests/unit-tests/bytecode/dune b/src/tests/unit-tests/bytecode/dune new file mode 100644 index 00000000..f3d85915 --- /dev/null +++ b/src/tests/unit-tests/bytecode/dune @@ -0,0 +1,7 @@ + +(tests + (package ocaml-protoc) + (names varint wrapper_encoding pbrt_array) + (libraries pbrt ocaml-protoc.compiler-lib) + (modes byte) + (flags :standard -open Ocaml_protoc_compiler_lib)) diff --git a/src/tests/unit-tests/bytecode/pbrt_array.ml b/src/tests/unit-tests/bytecode/pbrt_array.ml new file mode 100644 index 00000000..c30749a7 --- /dev/null +++ b/src/tests/unit-tests/bytecode/pbrt_array.ml @@ -0,0 +1,55 @@ +let insert_n n : int Pbrt.Repeated_field.t = + let a = Pbrt.Repeated_field.make 0 in + let rec loop = function + | i when i = n -> () + | i -> + Pbrt.Repeated_field.add i a; + loop (i + 1) + in + loop 0; + a + +let () = + (* Small array *) + let a = insert_n 3 in + assert ([| 0; 1; 2 |] = Pbrt.Repeated_field.to_array a) + +let test_n n : unit = + let a = insert_n n in + let a = Pbrt.Repeated_field.to_array a in + Array.iteri (fun i j -> assert (i = j)) a + +let () = + (* Larger Repeated_field *) + for i = 0 to 11_000 do + test_n i + done + +let test_n n : unit = + let a = insert_n n in + let a = Pbrt.Repeated_field.map_to_array (fun x -> -x) a in + Array.iteri (fun i j -> assert (i = -j)) a + +let () = + (* Larger Repeated_field *) + for i = 0 to 5_000 do + test_n i + done + +let () = + (* Pbrt.Repeated_field.fold_left *) + let a = insert_n 3 in + let l = Pbrt.Repeated_field.fold_left (fun acc e -> e :: acc) [] a in + assert ([ 2; 1; 0 ] = l) + +let test_n n : unit = + let a = insert_n n in + let l = Pbrt.Repeated_field.map_to_list (fun x -> -x) a in + List.iteri (fun i j -> assert (i = -j)) l + +let () = + for i = 0 to 1_000 do + test_n i + done + +let () = assert (0 = Pbrt.Repeated_field.length @@ Pbrt.Repeated_field.make 100) diff --git a/src/tests/unit-tests/bytecode/varint.ml b/src/tests/unit-tests/bytecode/varint.ml new file mode 100644 index 00000000..c29495da --- /dev/null +++ b/src/tests/unit-tests/bytecode/varint.ml @@ -0,0 +1,57 @@ +(* see: + https://developers.google.com/protocol-buffers/docs/encoding#varints +*) + +module D = Pbrt.Decoder +module E = Pbrt.Encoder + +let decvarint (s : string) : int64 = + let dec = D.of_string s in + D.int64_as_varint dec + +let encvarint (i : int64) : string = + let enc = E.create () in + E.int64_as_varint i enc; + E.to_string enc + +let str_to_l s = + let l = ref [] in + String.iter (fun x -> l := x :: !l) s; + List.rev !l + +let str_to_il s = str_to_l s |> List.map Char.code + +let () = + let s = encvarint 12L in + assert (str_to_il s = [ 12 ]); + assert (decvarint s = 12L) + +let () = + let s = encvarint 0L in + assert (str_to_il s = [ 0 ]); + assert (decvarint s = 0L) + +let () = + let s = encvarint 127L in + assert (str_to_il s = [ 127 ]); + assert (decvarint s = 127L) + +let () = + let s = encvarint 128L in + assert (str_to_il s = [ 128; 1 ]); + assert (decvarint s = 128L) + +let () = + let s = encvarint 300L in + assert (str_to_il s = [ 0b1010_1100; 0b0000_0010 ]); + assert (decvarint s = 300L) + +let () = + let s = encvarint 150L in + assert (str_to_il s = [ 0x96; 1 ]); + assert (decvarint s = 150L) + +let () = + let s = encvarint 178282982111149L in + assert (str_to_il s = [ 173; 239; 197; 238; 219; 196; 40 ]); + assert (decvarint s = 178282982111149L) diff --git a/src/tests/unit-tests/bytecode/wrapper_encoding.ml b/src/tests/unit-tests/bytecode/wrapper_encoding.ml new file mode 100644 index 00000000..ceb37de2 --- /dev/null +++ b/src/tests/unit-tests/bytecode/wrapper_encoding.ml @@ -0,0 +1,44 @@ +(* unit tests for the wrapper specific encoding *) + +let spf = Printf.sprintf + +let do_test pp encode decode v = + let e = Pbrt.Encoder.create () in + encode (Some v) e; + let b = Pbrt.Encoder.to_bytes e in + (* Printf.printf "encoded: %S for %s\n" (Bytes.unsafe_to_string b) (pp v); *) + let d = Pbrt.Decoder.of_bytes b in + match decode d with + | Some x when x = v -> () + | Some y -> + Printf.eprintf "expected %s, got %s\n%!" (pp v) (pp y); + assert false + | _ -> assert false + +let round32 v = + let open Int32 in + v |> bits_of_float |> float_of_bits + +let pp_bytes b = spf "%S" (Bytes.unsafe_to_string b) + +let () = + let open Pbrt in + do_test (spf "%f") Encoder.wrapper_double_value Decoder.wrapper_double_value + 1.23; + do_test (spf "%f") Encoder.wrapper_float_value Decoder.wrapper_float_value + (round32 1.23); + do_test (spf "%LdL") Encoder.wrapper_int64_value Decoder.wrapper_int64_value + 123L; + do_test (spf "%ldl") Encoder.wrapper_int32_value Decoder.wrapper_int32_value + 123l; + do_test (spf "%b") Encoder.wrapper_bool_value Decoder.wrapper_bool_value true; + do_test (spf "%b") Encoder.wrapper_bool_value Decoder.wrapper_bool_value false; + do_test (spf "%S") Encoder.wrapper_string_value Decoder.wrapper_string_value + ""; + do_test (spf "%S") Encoder.wrapper_string_value Decoder.wrapper_string_value + "abc"; + do_test pp_bytes Encoder.wrapper_bytes_value Decoder.wrapper_bytes_value + (Bytes.of_string ""); + do_test pp_bytes Encoder.wrapper_bytes_value Decoder.wrapper_bytes_value + (Bytes.of_string "abc"); + () From f4a4caa876e2e93dfb4543c44db71b7ef163df9e Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 13 Feb 2024 12:49:37 -0500 Subject: [PATCH 23/47] fix segfault in pbrt in bytecode --- src/runtime/stubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stubs.c b/src/runtime/stubs.c index eceaf382..739cab64 100644 --- a/src/runtime/stubs.c +++ b/src/runtime/stubs.c @@ -65,7 +65,7 @@ CAMLprim value caml_pbrt_varint_byte(value _str, value _idx, value _i) { CAMLparam3(_str, _idx, _i); char *str = Bytes_val(_str); int idx = Int_val(_idx); - int64_t i = Int64_val(_idx); + int64_t i = Int64_val(_i); pbrt_varint(str + idx, i); CAMLreturn(Val_unit); } From 0589de90ef574497bf57ab883985d21663b95d7d Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Wed, 17 Jan 2024 12:10:08 +0400 Subject: [PATCH 24/47] Add oneof example --- src/examples/oneof.ml.expected | 2 +- src/tests/unit-tests/bytecode/dune | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/examples/oneof.ml.expected b/src/examples/oneof.ml.expected index ec600fde..d31295b4 100644 --- a/src/examples/oneof.ml.expected +++ b/src/examples/oneof.ml.expected @@ -1,4 +1,4 @@ -[@@@ocaml.warning "-27-30-39"] +[@@@ocaml.warning "-27-30-39-44"] type patch_copy = { start : int64; diff --git a/src/tests/unit-tests/bytecode/dune b/src/tests/unit-tests/bytecode/dune index f3d85915..bcb68433 100644 --- a/src/tests/unit-tests/bytecode/dune +++ b/src/tests/unit-tests/bytecode/dune @@ -1,4 +1,3 @@ - (tests (package ocaml-protoc) (names varint wrapper_encoding pbrt_array) From 083ca2dac965558851ecc73c41df5d0062973569 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 22 Mar 2024 09:38:01 -0400 Subject: [PATCH 25/47] test: fix integration tests --- src/tests/integration-tests/test01_ml.ml | 6 ++-- src/tests/integration-tests/test07_ml.ml | 24 +++++++++++++-- src/tests/integration-tests/test08_ml.ml | 38 +++++++++++++++++++----- src/tests/integration-tests/test11_ml.ml | 4 +-- src/tests/integration-tests/test13_ml.ml | 13 ++++++-- 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/tests/integration-tests/test01_ml.ml b/src/tests/integration-tests/test01_ml.ml index 4fc73a7f..92436c1e 100644 --- a/src/tests/integration-tests/test01_ml.ml +++ b/src/tests/integration-tests/test01_ml.ml @@ -9,7 +9,7 @@ let decode_ref_data () = last_name = "Doe"; date_of_birth = 19820429l; tel_number = None; - employment = Employed_by "Google"; + employment = Some (Employed_by "Google"); marital_status = None; gender = Some Male; }; @@ -19,7 +19,7 @@ let decode_ref_data () = last_name = "Dupont"; date_of_birth = 19820306l; tel_number = Some { area_code = 917l; number = 1111111l }; - employment = Employed_by "INRIA"; + employment = Some (Employed_by "INRIA"); marital_status = None; gender = Some Female; }; @@ -52,7 +52,7 @@ let () = last_name = "Ransan"; date_of_birth = 19820429l; tel_number = None; - employment = Self_employed 0l; + employment = None; marital_status = None; gender = None; } diff --git a/src/tests/integration-tests/test07_ml.ml b/src/tests/integration-tests/test07_ml.ml index ebd845df..65e13c63 100644 --- a/src/tests/integration-tests/test07_ml.ml +++ b/src/tests/integration-tests/test07_ml.ml @@ -3,8 +3,28 @@ module T = Test07 let decode_ref_data () = { T.value = 1l; - T.left = T.Node { T.value = 2l; T.left = T.Empty 0l; T.right = T.Empty 0l }; - T.right = T.Node { T.value = 3l; T.left = T.Empty 0l; T.right = T.Empty 0l }; + T.left = + { + t = + Some + (T.Node + { + T.value = 2l; + T.left = { t = Some (T.Empty 0l) }; + T.right = { t = Some (T.Empty 0l) }; + }); + }; + T.right = + { + t = + Some + (T.Node + { + T.value = 3l; + T.left = { t = Some (T.Empty 0l) }; + T.right = { t = Some (T.Empty 0l) }; + }); + }; } let () = diff --git a/src/tests/integration-tests/test08_ml.ml b/src/tests/integration-tests/test08_ml.ml index c4b4f19c..dd8025e2 100644 --- a/src/tests/integration-tests/test08_ml.ml +++ b/src/tests/integration-tests/test08_ml.ml @@ -1,12 +1,36 @@ module T = Test08 -let decode_ref_data () = - T.Node - { - T.value = 1l; - T.left = T.Node { T.value = 2l; T.left = T.Empty 0l; right = T.Empty 0l }; - T.right = T.Node { T.value = 3l; T.left = T.Empty 0l; right = T.Empty 0l }; - } +let decode_ref_data () : T.tree = + { + t = + Some + (T.Node + { + T.value = 1l; + T.left = + { + t = + Some + (T.Node + { + T.value = 2l; + T.left = { t = Some (T.Empty 0l) }; + right = { t = Some (T.Empty 0l) }; + }); + }; + T.right = + { + t = + Some + (T.Node + { + T.value = 3l; + T.left = { t = Some (T.Empty 0l) }; + right = { t = Some (T.Empty 0l) }; + }); + }; + }); + } let () = let mode = Test_util.parse_args () in diff --git a/src/tests/integration-tests/test11_ml.ml b/src/tests/integration-tests/test11_ml.ml index 1ea47ee6..74a3c8e7 100644 --- a/src/tests/integration-tests/test11_ml.ml +++ b/src/tests/integration-tests/test11_ml.ml @@ -12,7 +12,7 @@ let create_ref_data n = T.last_name = "Doe"; T.date_of_birth = Int32.of_int n; T.tel_number = None; - T.employment = T.Employed_by "Google"; + T.employment = Some (T.Employed_by "Google"); T.marital_status = None; }; T.p2 = @@ -21,7 +21,7 @@ let create_ref_data n = T.last_name = "Dupont"; T.date_of_birth = 19820306l; T.tel_number = Some { T.area_code = 917l; T.number = 1111111l }; - T.employment = T.Employed_by "INRIA"; + T.employment = Some (T.Employed_by "INRIA"); T.marital_status = None; }; T.contact_numbers = diff --git a/src/tests/integration-tests/test13_ml.ml b/src/tests/integration-tests/test13_ml.ml index 12bb5c3f..f8cade3e 100644 --- a/src/tests/integration-tests/test13_ml.ml +++ b/src/tests/integration-tests/test13_ml.ml @@ -3,8 +3,17 @@ module T = Test13 let decode_pb_ref_data () = T. { - p2 = { empty = (); sub = Sub_empty }; - p1 = { l = [ Empty; Int 1l; Empty; Int 2l ] }; + p2 = { empty = (); sub = Some Sub_empty }; + p1 = + { + l = + [ + { t = Some Empty }; + { t = Some (Int 1l) }; + { t = Some Empty }; + { t = Some (Int 2l) }; + ]; + }; } let mode = Test_util.parse_args () From 83462a3909ebaedea79e06fe285d68c8531dc54d Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 31 Mar 2024 23:34:02 -0400 Subject: [PATCH 26/47] fix tests --- src/tests/integration-tests/test14_ml.ml | 4 ++-- src/tests/integration-tests/test17_ml.ml | 2 +- src/tests/integration-tests/test18_ml.ml | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tests/integration-tests/test14_ml.ml b/src/tests/integration-tests/test14_ml.ml index 4e2e7b6b..d16ee5b5 100644 --- a/src/tests/integration-tests/test14_ml.ml +++ b/src/tests/integration-tests/test14_ml.ml @@ -4,10 +4,10 @@ let decode_pb_ref_data () = T. { da = { aa = [ 1l; 2l; 3l; 4l ] }; - db = Ba { aa = [ 1l; 2l; 3l; 4l ] }; + db = { sub = Some (Ba { aa = [ 1l; 2l; 3l; 4l ] }) }; dc = { - sub = Ca { aa = [ 1l; 2l; 3l; 4l ] }; + sub = Some (Ca { aa = [ 1l; 2l; 3l; 4l ] }); cc = Some { aa = [ 1l; 2l; 3l; 4l ] }; }; } diff --git a/src/tests/integration-tests/test17_ml.ml b/src/tests/integration-tests/test17_ml.ml index 77c1b8ab..2b5eebbf 100644 --- a/src/tests/integration-tests/test17_ml.ml +++ b/src/tests/integration-tests/test17_ml.ml @@ -1,7 +1,7 @@ module T = Test17 let decode_pb_ref_data () = - T.{ m1 = { i1 = 1; i2 = 2 }; m2 = 1; m3 = 1; o = M4 4 } + T.{ m1 = { i1 = 1; i2 = 2 }; m2 = 1; m3 = 1; o = Some (M4 4) } let mode = Test_util.parse_args () diff --git a/src/tests/integration-tests/test18_ml.ml b/src/tests/integration-tests/test18_ml.ml index 4f806eaa..7c4ff41b 100644 --- a/src/tests/integration-tests/test18_ml.ml +++ b/src/tests/integration-tests/test18_ml.ml @@ -9,7 +9,8 @@ let decode_pb_ref_data () = int_to_message_value = [ 1l, { mv_field = "one" }; 2l, { mv_field = "two" } ]; int_to_enum_value = [ 1l, Ev_1; 2l, Ev_2 ]; - int_to_oneof_value = [ 1l, Ov_field1 "one"; 2l, Ov_field2 2l ]; + int_to_oneof_value = + [ 1l, { t = Some (Ov_field1 "one") }; 2l, { t = Some (Ov_field2 2l) } ]; } let mode = Test_util.parse_args () From 92082fc70399b50efb9b970f538ef21cbb353a99 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 31 Mar 2024 23:43:34 -0400 Subject: [PATCH 27/47] fix tests --- src/tests/integration-tests/test20.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/integration-tests/test20.proto b/src/tests/integration-tests/test20.proto index 7fc6b241..25ce0a62 100644 --- a/src/tests/integration-tests/test20.proto +++ b/src/tests/integration-tests/test20.proto @@ -12,6 +12,7 @@ message M { option (ocaml_type_ppx) = "deriving show"; required int32 f1 = 1; message Sub { + option (ocaml_type_ppx) = "deriving show"; required int32 sub_f1 = 1; } required Sub f2 = 2; From 694d2d257dfdd9100ed04c9a96a9704ebcf84e3c Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 31 Mar 2024 23:48:10 -0400 Subject: [PATCH 28/47] fix tests --- src/tests/integration-tests/test22_ml.ml | 6 +++--- src/tests/integration-tests/test24_ml.ml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/integration-tests/test22_ml.ml b/src/tests/integration-tests/test22_ml.ml index 1910647d..4e9ff801 100644 --- a/src/tests/integration-tests/test22_ml.ml +++ b/src/tests/integration-tests/test22_ml.ml @@ -10,7 +10,7 @@ let decode_pb_ref_data () = last_name = "Doe"; date_of_birth = 19820429l; tel_number = None; - employment = Employed_by "Google"; + employment = Some (Employed_by "Google"); marital_status = Single; gender = Male; }; @@ -21,7 +21,7 @@ let decode_pb_ref_data () = last_name = "Dupont"; date_of_birth = 19820306l; tel_number = Some { area_code = 917l; number = 1111111l }; - employment = Employed_by "INRIA"; + employment = Some (Employed_by "INRIA"); marital_status = Married; gender = Female; }; @@ -52,7 +52,7 @@ let () = last_name = ""; date_of_birth = 0l; tel_number = None; - employment = Self_employed 0l; + employment = None; marital_status = Single; gender = Male; } diff --git a/src/tests/integration-tests/test24_ml.ml b/src/tests/integration-tests/test24_ml.ml index 2e739a5d..236faad8 100644 --- a/src/tests/integration-tests/test24_ml.ml +++ b/src/tests/integration-tests/test24_ml.ml @@ -1,6 +1,6 @@ module T = Test24 -let decode_pb_ref_data () : T.a = T.Value "value" +let decode_pb_ref_data () : T.a = T.{ x = Some (Value "value") } let () = let mode = Test_util.parse_args () in From 0aecfaf0989b2ab3db31f270d3237bd454420d59 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 31 Mar 2024 23:51:37 -0400 Subject: [PATCH 29/47] dune --- src/dune | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dune b/src/dune index cc26033e..4dd477ec 100644 --- a/src/dune +++ b/src/dune @@ -1,3 +1,5 @@ (env (_ (flags :standard -warn-error -a+8 -w +a-4-40-41-42-44-48-70))) + +(data_only_dirs runtime-bs) From 4d512dbf835fc812c8c9dfb842aae61d5b4656c3 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 1 Apr 2024 00:03:53 -0400 Subject: [PATCH 30/47] stronger CI --- .github/workflows/main.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 773324e0..9503ddcb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,23 @@ jobs: - run: opam install -t . --deps-only - run: opam exec -- dune build @install - run: opam exec -- dune runtest - #- run: opam exec -- make integration + + - run: sudo apt install protobuf-compiler libprotobuf-dev + - run: opam exec -- make integration + + format: + name: format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + #with: + # submodules: true + - uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: 5.1 + allow-prerelease-opam: true + dune-cache: true + #- run: sudo apt install protobuf-compiler libprotobuf-dev - run: opam install ocamlformat.0.24.1 - run: opam exec -- dune build @fmt --auto-promote - run: git diff -q From 3a33f0c2bbc04f1ecadf423fc908c195baa93324 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 1 Apr 2024 00:39:28 -0400 Subject: [PATCH 31/47] attempt fix --- .github/workflows/main.yml | 2 +- Makefile.test | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9503ddcb..174fb9eb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ jobs: - run: opam exec -- dune runtest - run: sudo apt install protobuf-compiler libprotobuf-dev - - run: opam exec -- make integration + - run: opam exec -- make integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/x86_64-linux-gnu/ format: name: format diff --git a/Makefile.test b/Makefile.test index 08fb9b32..b2d0c6a0 100644 --- a/Makefile.test +++ b/Makefile.test @@ -45,9 +45,9 @@ $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc: $(OCAMLOPTIONS_HINC)/ocamloptions.proto %_cpp.tsk: %_cpp.cpp %.pb.cc $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(OCAMLOPTIONS_HINC) -I $(PB_HINC) \ - -L $(PB_LINC) -l protobuf \ + -L $(PB_LINC) \ $? \ - -o $@ + -o $@ -l protobuf $(INTEGRATION_TESTS_DIR)/test10_cpp.tsk: \ $(INTEGRATION_TESTS_DIR)/test10_cpp.cpp \ From 19146a46389fcacea42a27d47530336429a5bcc3 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 1 Apr 2024 00:45:11 -0400 Subject: [PATCH 32/47] CI --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 174fb9eb..a37ed7a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,6 +35,8 @@ jobs: - run: opam exec -- dune build @install - run: opam exec -- dune runtest + # integration tests + - run: opam install ppx_deriving -y - run: sudo apt install protobuf-compiler libprotobuf-dev - run: opam exec -- make integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/x86_64-linux-gnu/ From 8bf43917eae0f7dbc66330511432205b23fb01bb Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 1 Apr 2024 00:48:44 -0400 Subject: [PATCH 33/47] CI: enable submodules --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a37ed7a8..a7dd6ebe 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,8 +21,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - #with: - # submodules: true + with: + submodules: true - uses: ocaml/setup-ocaml@v2 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} From 36cbcac67967683766330e45b642df1af4f12b63 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 1 Apr 2024 22:53:15 -0400 Subject: [PATCH 34/47] wip --- Makefile.test | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Makefile.test b/Makefile.test index b2d0c6a0..875c91ad 100644 --- a/Makefile.test +++ b/Makefile.test @@ -32,20 +32,23 @@ tests: # location of where the Google protoc compiler is installed PB_INSTALL ?= /usr/ -PB_HINC = $(PB_INSTALL)/include -PB_LINC = $(PB_INSTALL)/lib +PB_HINC ?= $(PB_INSTALL)/include +PB_LINC ?= $(PB_INSTALL)/lib PROTOC = $(PB_INSTALL)/bin/protoc +PB_HINC_I = $(addprefix -I, $(PB_HINC)) +PB_LINC_L = $(addprefix -L, $(PB_LINC)) + export LD_LIBRARY_PATH=$(PB_LINC) $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc: $(OCAMLOPTIONS_HINC)/ocamloptions.proto cd $(OCAMLOPTIONS_HINC) && \ - $(PROTOC) --cpp_out ./ -I ./ -I $(abspath $(PB_HINC)) ocamloptions.proto + $(PROTOC) --cpp_out ./ -I ./ $(PB_HINC_I) ocamloptions.proto %_cpp.tsk: %_cpp.cpp %.pb.cc $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ - -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(OCAMLOPTIONS_HINC) -I $(PB_HINC) \ - -L $(PB_LINC) \ + -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(OCAMLOPTIONS_HINC) $(PB_HINC_L) \ + $(PB_LINC_L) \ $? \ -o $@ -l protobuf @@ -54,8 +57,8 @@ $(INTEGRATION_TESTS_DIR)/test10_cpp.tsk: \ $(INTEGRATION_TESTS_DIR)/test10.pb.cc \ $(INTEGRATION_TESTS_DIR)/test09.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ - -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(PB_HINC) \ - -L $(PB_LINC) -l protobuf \ + -I ./ -I $(INTEGRATION_TESTS_DIR) $(PB_HINC_I) \ + $(PB_LINC_L) -l protobuf \ $? \ -o $@ @@ -64,7 +67,7 @@ $(INTEGRATION_TESTS_DIR)/test10_cpp.tsk: \ %.pb.cc: %.proto $(PROTOC) \ --cpp_out $(INTEGRATION_TESTS_DIR) \ - -I $(PB_HINC) -I $(OCAMLOPTIONS_HINC) -I $(INTEGRATION_TESTS_DIR) \ + $(PB_HINC_I) -I $(OCAMLOPTIONS_HINC) -I $(INTEGRATION_TESTS_DIR) \ $< From 3e262ed8055acc2cdfaaa64805afed5f514a36f6 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 5 Jun 2024 11:53:44 -0400 Subject: [PATCH 35/47] fix tests --- src/tests/benchmark/ocaml_test_runner.ml | 20 +++++++++++--------- src/tests/integration-tests/test27_ml.ml | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tests/benchmark/ocaml_test_runner.ml b/src/tests/benchmark/ocaml_test_runner.ml index 4a316ba6..53c8c1f3 100644 --- a/src/tests/benchmark/ocaml_test_runner.ml +++ b/src/tests/benchmark/ocaml_test_runner.ml @@ -27,8 +27,9 @@ end module Make (T : T_sig) : Runner_sig = struct let run { Benchmark.type_; file_name; test_id } = - match type_ with - | Benchmark.Encode difficulty -> + match type_.t with + | None -> failwith "missing benchmark" + | Some (Encode difficulty) -> let t0 = Unix.gettimeofday () in let encoder = Pbrt.Encoder.create () in @@ -53,8 +54,8 @@ module Make (T : T_sig) : Runner_sig = struct } in - Benchmark.{ difficulty_size; test_id; data = Encode encode_data } - | Benchmark.Decode -> + Benchmark.{ difficulty_size; test_id; data = Some (Encode encode_data) } + | Some Decode -> let t0 = Unix.gettimeofday () in let ic = open_in file_name in let len = in_channel_length ic in @@ -69,11 +70,12 @@ module Make (T : T_sig) : Runner_sig = struct difficulty_size = T.difficulty_size v; test_id; data = - Decode - { - Benchmark.from_file_time = t1 -. t0; - Benchmark.decode_time = t2 -. t1; - }; + Some + (Decode + { + Benchmark.from_file_time = t1 -. t0; + Benchmark.decode_time = t2 -. t1; + }); } end (* Make *) diff --git a/src/tests/integration-tests/test27_ml.ml b/src/tests/integration-tests/test27_ml.ml index 6b437160..d5c14ce5 100644 --- a/src/tests/integration-tests/test27_ml.ml +++ b/src/tests/integration-tests/test27_ml.ml @@ -5,7 +5,7 @@ let test_data () = { enum1 = Value_with_option; unit_ = Some { unit_field = 1l }; - one_of_is_keyword = Some (One_of_is_keyword_field 1l); + one_of_is_keyword = Some { message = Some (One_of_is_keyword_field 1l) }; } let () = From 45a3e214ccf2ea7c0367d5ec1b735ca43fbee65a Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 5 Jun 2024 11:56:43 -0400 Subject: [PATCH 36/47] fix test --- src/tests/benchmark/benchmark_single_ml.ml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tests/benchmark/benchmark_single_ml.ml b/src/tests/benchmark/benchmark_single_ml.ml index 6a52e2de..36658596 100644 --- a/src/tests/benchmark/benchmark_single_ml.ml +++ b/src/tests/benchmark/benchmark_single_ml.ml @@ -45,8 +45,12 @@ let make_test_requests ~number_of_sample test_ids = let file_name = Printf.sprintf "test_%s_%i.data" (string_of_test_id test_id) difficulty in - let encode = Bench_t.{ type_ = Encode difficulty; file_name; test_id } in - let decode = Bench_t.{ type_ = Decode; file_name; test_id } in + let encode = + Bench_t.{ type_ = { t = Some (Encode difficulty) }; file_name; test_id } + in + let decode = + Bench_t.{ type_ = { t = Some Decode }; file_name; test_id } + in let init_cases, test_cases = acc in let test_cases = Util.append_n test_cases encode number_of_sample in @@ -150,10 +154,10 @@ let print_compare_type ~metric responses test_ids = (fun data -> let open Bench_t in match data, metric with - | Encode { encode_time; _ }, `Encode_time -> + | Some (Encode { encode_time; _ }), `Encode_time -> sum := !sum +. encode_time; incr counter - | Decode { decode_time; _ }, `Decode_time -> + | Some (Decode { decode_time; _ }), `Decode_time -> sum := !sum +. decode_time; incr counter | _ -> ()) From 49067364eb5be0555f36fa33bc859df4bc0d7039 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 11:53:25 -0400 Subject: [PATCH 37/47] fix build --- src/tests/yojson/dune | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/yojson/dune b/src/tests/yojson/dune index a0f41639..e471505c 100644 --- a/src/tests/yojson/dune +++ b/src/tests/yojson/dune @@ -6,7 +6,7 @@ (rule (targets yojson_unittest.ml yojson_unittest.mli) (deps + (:protoc %{project_root}/src/ocaml-protoc/ocaml_protoc.exe) (:file yojson_unittest.proto)) (action - (run %{project_root}/src/ocaml-protoc/ocaml_protoc.exe %{file} --yojson - --ml_out=.))) + (run %{protoc} %{file} --yojson --ml_out=.))) From b1cf44879e45c00065414a88e1c6a4929b0bf187 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 11:56:13 -0400 Subject: [PATCH 38/47] format --- src/tests/yojson/dune | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/yojson/dune b/src/tests/yojson/dune index e471505c..420abbc4 100644 --- a/src/tests/yojson/dune +++ b/src/tests/yojson/dune @@ -6,7 +6,7 @@ (rule (targets yojson_unittest.ml yojson_unittest.mli) (deps - (:protoc %{project_root}/src/ocaml-protoc/ocaml_protoc.exe) + (:protoc %{project_root}/src/ocaml-protoc/ocaml_protoc.exe) (:file yojson_unittest.proto)) (action (run %{protoc} %{file} --yojson --ml_out=.))) From f0460126c0c2de0228b286c1b7e9bb32d3cf2bcd Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 13:21:59 -0400 Subject: [PATCH 39/47] vendor google .proto files for CI --- .../google/protobuf/any.proto | 162 +++ .../google/protobuf/api.proto | 207 +++ .../google/protobuf/cpp_features.proto | 30 + .../google/protobuf/descriptor.proto | 1218 +++++++++++++++++ .../google/protobuf/duration.proto | 115 ++ .../google/protobuf/empty.proto | 51 + .../google/protobuf/field_mask.proto | 245 ++++ .../google/protobuf/source_context.proto | 48 + .../google/protobuf/struct.proto | 95 ++ .../google/protobuf/timestamp.proto | 144 ++ .../google/protobuf/type.proto | 193 +++ .../google/protobuf/wrappers.proto | 123 ++ 12 files changed, 2631 insertions(+) create mode 100644 src/tests/integration-tests/google/protobuf/any.proto create mode 100644 src/tests/integration-tests/google/protobuf/api.proto create mode 100644 src/tests/integration-tests/google/protobuf/cpp_features.proto create mode 100644 src/tests/integration-tests/google/protobuf/descriptor.proto create mode 100644 src/tests/integration-tests/google/protobuf/duration.proto create mode 100644 src/tests/integration-tests/google/protobuf/empty.proto create mode 100644 src/tests/integration-tests/google/protobuf/field_mask.proto create mode 100644 src/tests/integration-tests/google/protobuf/source_context.proto create mode 100644 src/tests/integration-tests/google/protobuf/struct.proto create mode 100644 src/tests/integration-tests/google/protobuf/timestamp.proto create mode 100644 src/tests/integration-tests/google/protobuf/type.proto create mode 100644 src/tests/integration-tests/google/protobuf/wrappers.proto diff --git a/src/tests/integration-tests/google/protobuf/any.proto b/src/tests/integration-tests/google/protobuf/any.proto new file mode 100644 index 00000000..eff44e50 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/any.proto @@ -0,0 +1,162 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/known/anypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/src/tests/integration-tests/google/protobuf/api.proto b/src/tests/integration-tests/google/protobuf/api.proto new file mode 100644 index 00000000..42223516 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/api.proto @@ -0,0 +1,207 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/source_context.proto"; +import "google/protobuf/type.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "ApiProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/apipb"; + +// Api is a light-weight descriptor for an API Interface. +// +// Interfaces are also described as "protocol buffer services" in some contexts, +// such as by the "service" keyword in a .proto file, but they are different +// from API Services, which represent a concrete implementation of an interface +// as opposed to simply a description of methods and bindings. They are also +// sometimes simply referred to as "APIs" in other contexts, such as the name of +// this message itself. See https://cloud.google.com/apis/design/glossary for +// detailed terminology. +message Api { + // The fully qualified name of this interface, including package name + // followed by the interface's simple name. + string name = 1; + + // The methods of this interface, in unspecified order. + repeated Method methods = 2; + + // Any metadata attached to the interface. + repeated Option options = 3; + + // A version string for this interface. If specified, must have the form + // `major-version.minor-version`, as in `1.10`. If the minor version is + // omitted, it defaults to zero. If the entire version field is empty, the + // major version is derived from the package name, as outlined below. If the + // field is not empty, the version in the package name will be verified to be + // consistent with what is provided here. + // + // The versioning schema uses [semantic + // versioning](http://semver.org) where the major version number + // indicates a breaking change and the minor version an additive, + // non-breaking change. Both version numbers are signals to users + // what to expect from different versions, and should be carefully + // chosen based on the product plan. + // + // The major version is also reflected in the package name of the + // interface, which must end in `v`, as in + // `google.feature.v1`. For major versions 0 and 1, the suffix can + // be omitted. Zero major versions must only be used for + // experimental, non-GA interfaces. + // + string version = 4; + + // Source context for the protocol buffer service represented by this + // message. + SourceContext source_context = 5; + + // Included interfaces. See [Mixin][]. + repeated Mixin mixins = 6; + + // The source syntax of the service. + Syntax syntax = 7; +} + +// Method represents a method of an API interface. +message Method { + // The simple name of this method. + string name = 1; + + // A URL of the input message type. + string request_type_url = 2; + + // If true, the request is streamed. + bool request_streaming = 3; + + // The URL of the output message type. + string response_type_url = 4; + + // If true, the response is streamed. + bool response_streaming = 5; + + // Any metadata attached to the method. + repeated Option options = 6; + + // The source syntax of this method. + Syntax syntax = 7; +} + +// Declares an API Interface to be included in this interface. The including +// interface must redeclare all the methods from the included interface, but +// documentation and options are inherited as follows: +// +// - If after comment and whitespace stripping, the documentation +// string of the redeclared method is empty, it will be inherited +// from the original method. +// +// - Each annotation belonging to the service config (http, +// visibility) which is not set in the redeclared method will be +// inherited. +// +// - If an http annotation is inherited, the path pattern will be +// modified as follows. Any version prefix will be replaced by the +// version of the including interface plus the [root][] path if +// specified. +// +// Example of a simple mixin: +// +// package google.acl.v1; +// service AccessControl { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v1/{resource=**}:getAcl"; +// } +// } +// +// package google.storage.v2; +// service Storage { +// rpc GetAcl(GetAclRequest) returns (Acl); +// +// // Get a data record. +// rpc GetData(GetDataRequest) returns (Data) { +// option (google.api.http).get = "/v2/{resource=**}"; +// } +// } +// +// Example of a mixin configuration: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// +// The mixin construct implies that all methods in `AccessControl` are +// also declared with same name and request/response types in +// `Storage`. A documentation generator or annotation processor will +// see the effective `Storage.GetAcl` method after inherting +// documentation and annotations as follows: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/{resource=**}:getAcl"; +// } +// ... +// } +// +// Note how the version in the path pattern changed from `v1` to `v2`. +// +// If the `root` field in the mixin is specified, it should be a +// relative path under which inherited HTTP paths are placed. Example: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// root: acls +// +// This implies the following inherited HTTP annotation: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; +// } +// ... +// } +message Mixin { + // The fully qualified name of the interface which is included. + string name = 1; + + // If non-empty specifies a path under which inherited HTTP paths + // are rooted. + string root = 2; +} diff --git a/src/tests/integration-tests/google/protobuf/cpp_features.proto b/src/tests/integration-tests/google/protobuf/cpp_features.proto new file mode 100644 index 00000000..2ba40e55 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/cpp_features.proto @@ -0,0 +1,30 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.FeatureSet { + optional CppFeatures cpp = 1000; +} + +message CppFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "true" }, + edition_defaults = { edition: EDITION_PROTO3, value: "false" } + ]; +} diff --git a/src/tests/integration-tests/google/protobuf/descriptor.proto b/src/tests/integration-tests/google/protobuf/descriptor.proto new file mode 100644 index 00000000..47486435 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/descriptor.proto @@ -0,0 +1,1218 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + +syntax = "proto2"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// The full set of known editions. +enum Edition { + // A placeholder for an unknown edition value. + EDITION_UNKNOWN = 0; + + // Legacy syntax "editions". These pre-date editions, but behave much like + // distinct editions. These can't be used to specify the edition of proto + // files, but feature definitions must supply proto2/proto3 defaults for + // backwards compatibility. + EDITION_PROTO2 = 998; + EDITION_PROTO3 = 999; + + // Editions that have been released. The specific values are arbitrary and + // should not be depended on, but they will always be time-ordered for easy + // comparison. + EDITION_2023 = 1000; + + // Placeholder editions for testing feature resolution. These should not be + // used or relyed on outside of tests. + EDITION_1_TEST_ONLY = 1; + EDITION_2_TEST_ONLY = 2; + EDITION_99997_TEST_ONLY = 99997; + EDITION_99998_TEST_ONLY = 99998; + EDITION_99999_TEST_ONLY = 99999; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2", "proto3", and "editions". + // + // If `edition` is present, this value must be "editions". + optional string syntax = 12; + + // The edition of the proto file. + optional Edition edition = 14; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + message Declaration { + // The extension number declared within the extension range. + optional int32 number = 1; + + // The fully-qualified name of the extension field. There must be a leading + // dot in front of the full name. + optional string full_name = 2; + + // The fully-qualified type name of the extension field. Unlike + // Metadata.type, Declaration.type must have a leading dot for messages + // and enums. + optional string type = 3; + + // If true, indicates that the number is reserved in the extension range, + // and any extension field with the number will fail to compile. Set this + // when a declared extension field is deleted. + optional bool reserved = 5; + + // If true, indicates that the extension must be defined as repeated. + // Otherwise the extension must be defined as optional. + optional bool repeated = 6; + + reserved 4; // removed is_repeated + } + + // For external users: DO NOT USE. We are in the process of open sourcing + // extension declaration and executing internal cleanups before it can be + // used externally. + repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The verification state of the extension range. + enum VerificationState { + // All the extensions of the range must be declared. + DECLARATION = 0; + UNVERIFIED = 1; + } + + // The verification state of the range. + // TODO: flip the default to DECLARATION once all empty ranges + // are marked as UNVERIFIED. + optional VerificationState verification = 3 [default = UNVERIFIED]; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported after google.protobuf. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. In Editions, the group wire format + // can be enabled via the `message_encoding` feature. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + } + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REPEATED = 3; + // The required label is only allowed in google.protobuf. In proto3 and Editions + // it's explicitly prohibited. In Editions, the `field_presence` feature + // can be used to get this behavior. + LABEL_REQUIRED = 2; + } + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must be belong to a oneof to + // signal to old proto3 clients that presence is tracked for this field. This + // oneof is known as a "synthetic" oneof, and this field must be its sole + // member (each proto3 optional field gets its own synthetic oneof). Synthetic + // oneofs exist in the descriptor only, and do not generate any API. Synthetic + // oneofs must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default = false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default = false]; +} + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + // Controls the name of the wrapper Java class generated for the .proto file. + // That class will always contain the .proto file's getDescriptor() method as + // well as any top-level extensions defined in the .proto file. + // If java_multiple_files is disabled, then all the other classes from the + // .proto file will be nested inside the single wrapper outer class. + optional string java_outer_classname = 8; + + // If enabled, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the wrapper class + // named by java_outer_classname. However, the wrapper class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default = false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + optional bool java_string_check_utf8 = 27 [default = false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default = SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + optional bool php_generic_services = 42 [default = false]; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default = false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default = true]; + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be + // used for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default = false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default = false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default = false]; + + reserved 4, 5, 6; + + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + // + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementations still need to work as + // if the field is a repeated message field. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // + // This should only be used as a temporary measure against broken builds due + // to the change in behavior for JSON field name conflicts. + // + // TODO This is legacy behavior we plan to remove once downstream + // teams have had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 12; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is only implemented to support use of + // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of + // type "bytes" in the open source release -- sorry, we'll try to include + // other types in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + // The option [ctype=CORD] may be applied to a non-repeated field of type + // "bytes". It indicates that in C++, the data should be stored in a Cord + // instead of a string. For very large strings, this may reduce memory + // fragmentation. It may also allow better performance when parsing from a + // Cord, or when parsing with aliasing enabled, as the parsed Cord may then + // alias the original buffer. + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. This option is prohibited in + // Editions, but the `repeated_field_encoding` feature can be used to control + // the behavior. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + // + // As of May 2022, lazy verifies the contents of the byte stream during + // parsing. An invalid byte stream will cause the overall parsing to fail. + optional bool lazy = 5 [default = false]; + + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default = false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default = false]; + + // Indicate that the field value should not be printed out when using debug + // formats, e.g. when the field contains sensitive credentials. + optional bool debug_redact = 16 [default = false]; + + // If set to RETENTION_SOURCE, the option will be omitted from the binary. + // Note: as of January 2023, support for this is in progress and does not yet + // have an effect (b/264593489). + enum OptionRetention { + RETENTION_UNKNOWN = 0; + RETENTION_RUNTIME = 1; + RETENTION_SOURCE = 2; + } + + optional OptionRetention retention = 17; + + // This indicates the types of entities that the field may apply to when used + // as an option. If it is unset, then the field may be freely used as an + // option on any kind of entity. Note: as of January 2023, support for this is + // in progress and does not yet have an effect (b/264593489). + enum OptionTargetType { + TARGET_TYPE_UNKNOWN = 0; + TARGET_TYPE_FILE = 1; + TARGET_TYPE_EXTENSION_RANGE = 2; + TARGET_TYPE_MESSAGE = 3; + TARGET_TYPE_FIELD = 4; + TARGET_TYPE_ONEOF = 5; + TARGET_TYPE_ENUM = 6; + TARGET_TYPE_ENUM_ENTRY = 7; + TARGET_TYPE_SERVICE = 8; + TARGET_TYPE_METHOD = 9; + } + + repeated OptionTargetType targets = 19; + + message EditionDefault { + optional Edition edition = 3; + optional string value = 2; // Textproto value. + } + repeated EditionDefault edition_defaults = 20; + + // Any features defined in the specific edition. + optional FeatureSet features = 21; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype + reserved 18; // reserve target, target_obsolete_do_not_use +} + +message OneofOptions { + // Any features defined in the specific edition. + optional FeatureSet features = 1; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default = false]; + + reserved 5; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // TODO Remove this legacy behavior once downstream teams have + // had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 7; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default = false]; + + // Any features defined in the specific edition. + optional FeatureSet features = 2; + + // Indicate that fields annotated with this enum value should not be printed + // out when using debug formats, e.g. when the field contains sensitive + // credentials. + optional bool debug_redact = 3 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Any features defined in the specific edition. + optional FeatureSet features = 34; + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default = false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = 34 + [default = IDEMPOTENCY_UNKNOWN]; + + // Any features defined in the specific edition. + optional FeatureSet features = 35; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Features + +// TODO Enums in C++ gencode (and potentially other languages) are +// not well scoped. This means that each of the feature enums below can clash +// with each other. The short names we've chosen maximize call-site +// readability, but leave us very open to this scenario. A future feature will +// be designed and implemented to handle this, hopefully before we ever hit a +// conflict here. +message FeatureSet { + enum FieldPresence { + FIELD_PRESENCE_UNKNOWN = 0; + EXPLICIT = 1; + IMPLICIT = 2; + LEGACY_REQUIRED = 3; + } + optional FieldPresence field_presence = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "EXPLICIT" }, + edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" }, + edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" } + ]; + + enum EnumType { + ENUM_TYPE_UNKNOWN = 0; + OPEN = 1; + CLOSED = 2; + } + optional EnumType enum_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "CLOSED" }, + edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" } + ]; + + enum RepeatedFieldEncoding { + REPEATED_FIELD_ENCODING_UNKNOWN = 0; + PACKED = 1; + EXPANDED = 2; + } + optional RepeatedFieldEncoding repeated_field_encoding = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "EXPANDED" }, + edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" } + ]; + + enum Utf8Validation { + UTF8_VALIDATION_UNKNOWN = 0; + NONE = 1; + VERIFY = 2; + } + optional Utf8Validation utf8_validation = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "NONE" }, + edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" } + ]; + + enum MessageEncoding { + MESSAGE_ENCODING_UNKNOWN = 0; + LENGTH_PREFIXED = 1; + DELIMITED = 2; + } + optional MessageEncoding message_encoding = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "LENGTH_PREFIXED" } + ]; + + enum JsonFormat { + JSON_FORMAT_UNKNOWN = 0; + ALLOW = 1; + LEGACY_BEST_EFFORT = 2; + } + optional JsonFormat json_format = 6 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + edition_defaults = { edition: EDITION_PROTO2, value: "LEGACY_BEST_EFFORT" }, + edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" } + ]; + + reserved 999; + + extensions 1000; // for Protobuf C++ + extensions 1001; // for Protobuf Java + + extensions 9995 to 9999; // For internal testing +} + +// A compiled specification for the defaults of a set of features. These +// messages are generated from FeatureSet extensions and can be used to seed +// feature resolution. The resolution with this object becomes a simple search +// for the closest matching edition, followed by proto merges. +message FeatureSetDefaults { + // A map from every known edition with a unique set of defaults to its + // defaults. Not all editions may be contained here. For a given edition, + // the defaults at the closest matching edition ordered at or before it should + // be used. This field must be in strict ascending order by edition. + message FeatureSetEditionDefault { + optional Edition edition = 3; + optional FeatureSet features = 2; + } + repeated FeatureSetEditionDefault defaults = 1; + + // The minimum supported edition (inclusive) when this was constructed. + // Editions before this will not have defaults. + optional Edition minimum_edition = 4; + + // The maximum known edition (inclusive) when this was constructed. Editions + // after this will not have reliable defaults. + optional Edition maximum_edition = 5; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition occurs. + // For example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed = true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed = true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to moo. + // // + // // Another line attached to moo. + // optional double moo = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to moo or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed = true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified object. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + + // Represents the identified object's effect on the element in the original + // .proto file. + enum Semantic { + // There is no effect or the effect is indescribable. + NONE = 0; + // The element is set or otherwise mutated. + SET = 1; + // An alias to the element is returned. + ALIAS = 2; + } + optional Semantic semantic = 5; + } +} diff --git a/src/tests/integration-tests/google/protobuf/duration.proto b/src/tests/integration-tests/google/protobuf/duration.proto new file mode 100644 index 00000000..41f40c22 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/duration.proto @@ -0,0 +1,115 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/durationpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (duration.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +message Duration { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/src/tests/integration-tests/google/protobuf/empty.proto b/src/tests/integration-tests/google/protobuf/empty.proto new file mode 100644 index 00000000..b87c89dc --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/empty.proto @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/known/emptypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +message Empty {} diff --git a/src/tests/integration-tests/google/protobuf/field_mask.proto b/src/tests/integration-tests/google/protobuf/field_mask.proto new file mode 100644 index 00000000..b28334b9 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/field_mask.proto @@ -0,0 +1,245 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "FieldMaskProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; +option cc_enable_arenas = true; + +// `FieldMask` represents a set of symbolic field paths, for example: +// +// paths: "f.a" +// paths: "f.b.d" +// +// Here `f` represents a field in some root message, `a` and `b` +// fields in the message found in `f`, and `d` a field found in the +// message in `f.b`. +// +// Field masks are used to specify a subset of fields that should be +// returned by a get operation or modified by an update operation. +// Field masks also have a custom JSON encoding (see below). +// +// # Field Masks in Projections +// +// When used in the context of a projection, a response message or +// sub-message is filtered by the API to only contain those fields as +// specified in the mask. For example, if the mask in the previous +// example is applied to a response message as follows: +// +// f { +// a : 22 +// b { +// d : 1 +// x : 2 +// } +// y : 13 +// } +// z: 8 +// +// The result will not contain specific values for fields x,y and z +// (their value will be set to the default, and omitted in proto text +// output): +// +// +// f { +// a : 22 +// b { +// d : 1 +// } +// } +// +// A repeated field is not allowed except at the last position of a +// paths string. +// +// If a FieldMask object is not present in a get operation, the +// operation applies to all fields (as if a FieldMask of all fields +// had been specified). +// +// Note that a field mask does not necessarily apply to the +// top-level response message. In case of a REST get operation, the +// field mask applies directly to the response, but in case of a REST +// list operation, the mask instead applies to each individual message +// in the returned resource list. In case of a REST custom method, +// other definitions may be used. Where the mask applies will be +// clearly documented together with its declaration in the API. In +// any case, the effect on the returned resource/resources is required +// behavior for APIs. +// +// # Field Masks in Update Operations +// +// A field mask in update operations specifies which fields of the +// targeted resource are going to be updated. The API is required +// to only change the values of the fields as specified in the mask +// and leave the others untouched. If a resource is passed in to +// describe the updated values, the API ignores the values of all +// fields not covered by the mask. +// +// If a repeated field is specified for an update operation, new values will +// be appended to the existing repeated field in the target resource. Note that +// a repeated field is only allowed in the last position of a `paths` string. +// +// If a sub-message is specified in the last position of the field mask for an +// update operation, then new value will be merged into the existing sub-message +// in the target resource. +// +// For example, given the target message: +// +// f { +// b { +// d: 1 +// x: 2 +// } +// c: [1] +// } +// +// And an update message: +// +// f { +// b { +// d: 10 +// } +// c: [2] +// } +// +// then if the field mask is: +// +// paths: ["f.b", "f.c"] +// +// then the result will be: +// +// f { +// b { +// d: 10 +// x: 2 +// } +// c: [1, 2] +// } +// +// An implementation may provide options to override this default behavior for +// repeated and message fields. +// +// In order to reset a field's value to the default, the field must +// be in the mask and set to the default value in the provided resource. +// Hence, in order to reset all fields of a resource, provide a default +// instance of the resource and set all fields in the mask, or do +// not provide a mask as described below. +// +// If a field mask is not present on update, the operation applies to +// all fields (as if a field mask of all fields has been specified). +// Note that in the presence of schema evolution, this may mean that +// fields the client does not know and has therefore not filled into +// the request will be reset to their default. If this is unwanted +// behavior, a specific service may require a client to always specify +// a field mask, producing an error if not. +// +// As with get operations, the location of the resource which +// describes the updated values in the request message depends on the +// operation kind. In any case, the effect of the field mask is +// required to be honored by the API. +// +// ## Considerations for HTTP REST +// +// The HTTP kind of an update operation which uses a field mask must +// be set to PATCH instead of PUT in order to satisfy HTTP semantics +// (PUT must only be used for full updates). +// +// # JSON Encoding of Field Masks +// +// In JSON, a field mask is encoded as a single string where paths are +// separated by a comma. Fields name in each path are converted +// to/from lower-camel naming conventions. +// +// As an example, consider the following message declarations: +// +// message Profile { +// User user = 1; +// Photo photo = 2; +// } +// message User { +// string display_name = 1; +// string address = 2; +// } +// +// In proto a field mask for `Profile` may look as such: +// +// mask { +// paths: "user.display_name" +// paths: "photo" +// } +// +// In JSON, the same mask is represented as below: +// +// { +// mask: "user.displayName,photo" +// } +// +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. +// +// ## Field Mask Verification +// +// The implementation of any API method which has a FieldMask type field in the +// request should verify the included field paths, and return an +// `INVALID_ARGUMENT` error if any path is unmappable. +message FieldMask { + // The set of field mask paths. + repeated string paths = 1; +} diff --git a/src/tests/integration-tests/google/protobuf/source_context.proto b/src/tests/integration-tests/google/protobuf/source_context.proto new file mode 100644 index 00000000..135f50fe --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/source_context.proto @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "SourceContextProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; + +// `SourceContext` represents information about the source of a +// protobuf element, like the file in which it is defined. +message SourceContext { + // The path-qualified name of the .proto file that contained the associated + // protobuf element. For example: `"google/protobuf/source_context.proto"`. + string file_name = 1; +} diff --git a/src/tests/integration-tests/google/protobuf/struct.proto b/src/tests/integration-tests/google/protobuf/struct.proto new file mode 100644 index 00000000..1bf0c1ad --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/struct.proto @@ -0,0 +1,95 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/structpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "StructProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// `Struct` represents a structured data value, consisting of fields +// which map to dynamically typed values. In some languages, `Struct` +// might be supported by a native representation. For example, in +// scripting languages like JS a struct is represented as an +// object. The details of that representation are described together +// with the proto support for the language. +// +// The JSON representation for `Struct` is JSON object. +message Struct { + // Unordered map of dynamically typed values. + map fields = 1; +} + +// `Value` represents a dynamically typed value which can be either +// null, a number, a string, a boolean, a recursive struct value, or a +// list of values. A producer of value is expected to set one of these +// variants. Absence of any variant indicates an error. +// +// The JSON representation for `Value` is JSON value. +message Value { + // The kind of value. + oneof kind { + // Represents a null value. + NullValue null_value = 1; + // Represents a double value. + double number_value = 2; + // Represents a string value. + string string_value = 3; + // Represents a boolean value. + bool bool_value = 4; + // Represents a structured value. + Struct struct_value = 5; + // Represents a repeated `Value`. + ListValue list_value = 6; + } +} + +// `NullValue` is a singleton enumeration to represent the null value for the +// `Value` type union. +// +// The JSON representation for `NullValue` is JSON `null`. +enum NullValue { + // Null value. + NULL_VALUE = 0; +} + +// `ListValue` is a wrapper around a repeated field of values. +// +// The JSON representation for `ListValue` is JSON array. +message ListValue { + // Repeated field of dynamically typed values. + repeated Value values = 1; +} diff --git a/src/tests/integration-tests/google/protobuf/timestamp.proto b/src/tests/integration-tests/google/protobuf/timestamp.proto new file mode 100644 index 00000000..fd0bc07d --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/timestamp.proto @@ -0,0 +1,144 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/timestamppb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// Example 5: Compute Timestamp from Java `Instant.now()`. +// +// Instant now = Instant.now(); +// +// Timestamp timestamp = +// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) +// .setNanos(now.getNano()).build(); +// +// Example 6: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required. A proto3 JSON serializer should always use UTC (as indicated by +// "Z") when printing the Timestamp type and a proto3 JSON parser should be +// able to accept both UTC and other timezones (as indicated by an offset). +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() +// ) to obtain a formatter capable of generating timestamps in this format. +// +message Timestamp { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/src/tests/integration-tests/google/protobuf/type.proto b/src/tests/integration-tests/google/protobuf/type.proto new file mode 100644 index 00000000..48cb11e7 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/type.proto @@ -0,0 +1,193 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/any.proto"; +import "google/protobuf/source_context.proto"; + +option cc_enable_arenas = true; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TypeProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/typepb"; + +// A protocol buffer message type. +message Type { + // The fully qualified message name. + string name = 1; + // The list of fields. + repeated Field fields = 2; + // The list of types appearing in `oneof` definitions in this type. + repeated string oneofs = 3; + // The protocol buffer options. + repeated Option options = 4; + // The source context. + SourceContext source_context = 5; + // The source syntax. + Syntax syntax = 6; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 7; +} + +// A single field of a message type. +message Field { + // Basic field types. + enum Kind { + // Field type unknown. + TYPE_UNKNOWN = 0; + // Field type double. + TYPE_DOUBLE = 1; + // Field type float. + TYPE_FLOAT = 2; + // Field type int64. + TYPE_INT64 = 3; + // Field type uint64. + TYPE_UINT64 = 4; + // Field type int32. + TYPE_INT32 = 5; + // Field type fixed64. + TYPE_FIXED64 = 6; + // Field type fixed32. + TYPE_FIXED32 = 7; + // Field type bool. + TYPE_BOOL = 8; + // Field type string. + TYPE_STRING = 9; + // Field type group. Proto2 syntax only, and deprecated. + TYPE_GROUP = 10; + // Field type message. + TYPE_MESSAGE = 11; + // Field type bytes. + TYPE_BYTES = 12; + // Field type uint32. + TYPE_UINT32 = 13; + // Field type enum. + TYPE_ENUM = 14; + // Field type sfixed32. + TYPE_SFIXED32 = 15; + // Field type sfixed64. + TYPE_SFIXED64 = 16; + // Field type sint32. + TYPE_SINT32 = 17; + // Field type sint64. + TYPE_SINT64 = 18; + } + + // Whether a field is optional, required, or repeated. + enum Cardinality { + // For fields with unknown cardinality. + CARDINALITY_UNKNOWN = 0; + // For optional fields. + CARDINALITY_OPTIONAL = 1; + // For required fields. Proto2 syntax only. + CARDINALITY_REQUIRED = 2; + // For repeated fields. + CARDINALITY_REPEATED = 3; + } + + // The field type. + Kind kind = 1; + // The field cardinality. + Cardinality cardinality = 2; + // The field number. + int32 number = 3; + // The field name. + string name = 4; + // The field type URL, without the scheme, for message or enumeration + // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. + string type_url = 6; + // The index of the field type in `Type.oneofs`, for message or enumeration + // types. The first type has index 1; zero means the type is not in the list. + int32 oneof_index = 7; + // Whether to use alternative packed wire representation. + bool packed = 8; + // The protocol buffer options. + repeated Option options = 9; + // The field JSON name. + string json_name = 10; + // The string value of the default value of this field. Proto2 syntax only. + string default_value = 11; +} + +// Enum type definition. +message Enum { + // Enum type name. + string name = 1; + // Enum value definitions. + repeated EnumValue enumvalue = 2; + // Protocol buffer options. + repeated Option options = 3; + // The source context. + SourceContext source_context = 4; + // The source syntax. + Syntax syntax = 5; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 6; +} + +// Enum value definition. +message EnumValue { + // Enum value name. + string name = 1; + // Enum value number. + int32 number = 2; + // Protocol buffer options. + repeated Option options = 3; +} + +// A protocol buffer option, which can be attached to a message, field, +// enumeration, etc. +message Option { + // The option's name. For protobuf built-in options (options defined in + // descriptor.proto), this is the short name. For example, `"map_entry"`. + // For custom options, it should be the fully-qualified name. For example, + // `"google.api.http"`. + string name = 1; + // The option's value packed in an Any message. If the value is a primitive, + // the corresponding wrapper type defined in google/protobuf/wrappers.proto + // should be used. If the value is an enum, it should be stored as an int32 + // value using the google.protobuf.Int32Value type. + Any value = 2; +} + +// The syntax in which a protocol buffer element is defined. +enum Syntax { + // Syntax `proto2`. + SYNTAX_PROTO2 = 0; + // Syntax `proto3`. + SYNTAX_PROTO3 = 1; + // Syntax `editions`. + SYNTAX_EDITIONS = 2; +} diff --git a/src/tests/integration-tests/google/protobuf/wrappers.proto b/src/tests/integration-tests/google/protobuf/wrappers.proto new file mode 100644 index 00000000..1959fa55 --- /dev/null +++ b/src/tests/integration-tests/google/protobuf/wrappers.proto @@ -0,0 +1,123 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Wrappers for primitive (non-message) types. These types are useful +// for embedding primitives in the `google.protobuf.Any` type and for places +// where we need to distinguish between the absence of a primitive +// typed field and its default value. +// +// These wrappers have no meaningful use within repeated fields as they lack +// the ability to detect presence on individual elements. +// These wrappers have no meaningful use within a map or a oneof since +// individual entries of a map or fields of a oneof can already detect presence. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "WrappersProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. +message DoubleValue { + // The double value. + double value = 1; +} + +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. +message FloatValue { + // The float value. + float value = 1; +} + +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. +message Int64Value { + // The int64 value. + int64 value = 1; +} + +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. +message UInt64Value { + // The uint64 value. + uint64 value = 1; +} + +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. +message Int32Value { + // The int32 value. + int32 value = 1; +} + +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. +message UInt32Value { + // The uint32 value. + uint32 value = 1; +} + +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. +message BoolValue { + // The bool value. + bool value = 1; +} + +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. +message StringValue { + // The string value. + string value = 1; +} + +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. +message BytesValue { + // The bytes value. + bytes value = 1; +} From 2bb3600524a6206e3d278693dc4a361750aa38d2 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 13:34:58 -0400 Subject: [PATCH 40/47] deps --- src/tests/integration-tests/dune | 58 +++++++++++++++++--------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/tests/integration-tests/dune b/src/tests/integration-tests/dune index 344669d2..9ff19aa9 100644 --- a/src/tests/integration-tests/dune +++ b/src/tests/integration-tests/dune @@ -6,7 +6,7 @@ (rule (targets test01.ml test01.mli) - (deps test01.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test01.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ./ -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ocaml_all_types_ppx @@ -21,7 +21,7 @@ (rule (targets test02.ml test02.mli) - (deps test02.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test02.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test02.proto))) @@ -32,7 +32,7 @@ (rule (targets test04.ml test04.mli) - (deps test04.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test04.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test04.proto))) @@ -43,7 +43,7 @@ (rule (targets test05.ml test05.mli) - (deps test05.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test05.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test05.proto))) @@ -54,7 +54,7 @@ (rule (targets test06.ml test06.mli) - (deps test06.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test06.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test06.proto))) @@ -65,7 +65,7 @@ (rule (targets test07.ml test07.mli) - (deps test07.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test07.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test07.proto))) @@ -76,7 +76,7 @@ (rule (targets test08.ml test08.mli) - (deps test08.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test08.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test08.proto))) @@ -87,7 +87,7 @@ (rule (targets test09.ml test09.mli) - (deps test09.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test09.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test09.proto))) @@ -104,7 +104,7 @@ (rule (targets test10.ml test10.mli) - (deps test10.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test10.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test10.proto))) @@ -115,7 +115,7 @@ (rule (targets test11.ml test11.mli) - (deps test11.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test11.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test11.proto))) @@ -126,7 +126,7 @@ (rule (targets test12.ml test12.mli) - (deps test12.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test12.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test12.proto))) @@ -137,7 +137,7 @@ (rule (targets test13.ml test13.mli) - (deps test13.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test13.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test13.proto))) @@ -148,7 +148,7 @@ (rule (targets test14.ml test14.mli) - (deps test14.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test14.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test14.proto))) @@ -159,7 +159,7 @@ (rule (targets test15.ml test15.mli) - (deps test15.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test15.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test15.proto))) @@ -171,7 +171,7 @@ (rule (targets test16.ml test16.mli) - (deps test16.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test16.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test16.proto))) @@ -183,7 +183,7 @@ (rule (targets test17.ml test17.mli) - (deps test17.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test17.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test17.proto))) @@ -195,7 +195,7 @@ (rule (targets test18.ml test18.mli) - (deps test18.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test18.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test18.proto))) @@ -207,7 +207,7 @@ (rule (targets test19.ml test19.mli) - (deps test19.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test19.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test19.proto))) @@ -219,7 +219,7 @@ (rule (targets test20.ml test20.mli) - (deps test20.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test20.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test20.proto))) @@ -233,7 +233,7 @@ (rule (targets test21.ml test21.mli) - (deps test21.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test21.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test21.proto))) @@ -247,7 +247,7 @@ (rule (targets test22.ml test22.mli) - (deps test22.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test22.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test22.proto))) @@ -258,7 +258,7 @@ (rule (targets test23.ml test23.mli) - (deps test23.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test23.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test23.proto))) @@ -269,7 +269,7 @@ (rule (targets test24.ml test24.mli) - (deps test24.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test24.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test24.proto))) @@ -280,7 +280,7 @@ (rule (targets test25.ml test25.mli) - (deps test25.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test25.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test25.proto))) @@ -291,7 +291,7 @@ (rule (targets test26.ml test26.mli) - (deps test26.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test26.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test26.proto))) @@ -303,7 +303,7 @@ (rule (targets test27.ml test27.mli) - (deps test27.proto ../../include/ocaml-protoc/ocamloptions.proto) + (deps test27.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ test27.proto))) @@ -316,7 +316,8 @@ (targets test_proto3_optional.ml test_proto3_optional.mli) (deps (:proto test_proto3_optional.proto) - ../../include/ocaml-protoc/ocamloptions.proto) + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ %{proto}))) @@ -329,7 +330,8 @@ (targets test_make.ml test_make.mli) (deps (:proto test_make.proto) - ../../include/ocaml-protoc/ocamloptions.proto) + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --make --ml_out ./ %{proto}))) From b29b9b4cef5599f2308fdbfdd050e9365512bbf7 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 13:38:18 -0400 Subject: [PATCH 41/47] format --- src/tests/integration-tests/dune | 130 ++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 26 deletions(-) diff --git a/src/tests/integration-tests/dune b/src/tests/integration-tests/dune index 9ff19aa9..fb89dfbd 100644 --- a/src/tests/integration-tests/dune +++ b/src/tests/integration-tests/dune @@ -6,7 +6,10 @@ (rule (targets test01.ml test01.mli) - (deps test01.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test01.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ./ -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ocaml_all_types_ppx @@ -21,7 +24,10 @@ (rule (targets test02.ml test02.mli) - (deps test02.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test02.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test02.proto))) @@ -32,7 +38,10 @@ (rule (targets test04.ml test04.mli) - (deps test04.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test04.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test04.proto))) @@ -43,7 +52,10 @@ (rule (targets test05.ml test05.mli) - (deps test05.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test05.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test05.proto))) @@ -54,7 +66,10 @@ (rule (targets test06.ml test06.mli) - (deps test06.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test06.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test06.proto))) @@ -65,7 +80,10 @@ (rule (targets test07.ml test07.mli) - (deps test07.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test07.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test07.proto))) @@ -76,7 +94,10 @@ (rule (targets test08.ml test08.mli) - (deps test08.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test08.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test08.proto))) @@ -87,7 +108,10 @@ (rule (targets test09.ml test09.mli) - (deps test09.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test09.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test09.proto))) @@ -104,7 +128,10 @@ (rule (targets test10.ml test10.mli) - (deps test10.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test10.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test10.proto))) @@ -115,7 +142,10 @@ (rule (targets test11.ml test11.mli) - (deps test11.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test11.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test11.proto))) @@ -126,7 +156,10 @@ (rule (targets test12.ml test12.mli) - (deps test12.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test12.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test12.proto))) @@ -137,7 +170,10 @@ (rule (targets test13.ml test13.mli) - (deps test13.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test13.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test13.proto))) @@ -148,7 +184,10 @@ (rule (targets test14.ml test14.mli) - (deps test14.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test14.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test14.proto))) @@ -159,7 +198,10 @@ (rule (targets test15.ml test15.mli) - (deps test15.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test15.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test15.proto))) @@ -171,7 +213,10 @@ (rule (targets test16.ml test16.mli) - (deps test16.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test16.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test16.proto))) @@ -183,7 +228,10 @@ (rule (targets test17.ml test17.mli) - (deps test17.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test17.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test17.proto))) @@ -195,7 +243,10 @@ (rule (targets test18.ml test18.mli) - (deps test18.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test18.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test18.proto))) @@ -207,7 +258,10 @@ (rule (targets test19.ml test19.mli) - (deps test19.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test19.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test19.proto))) @@ -219,7 +273,10 @@ (rule (targets test20.ml test20.mli) - (deps test20.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test20.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test20.proto))) @@ -233,7 +290,10 @@ (rule (targets test21.ml test21.mli) - (deps test21.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test21.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I ../../include/ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test21.proto))) @@ -247,7 +307,10 @@ (rule (targets test22.ml test22.mli) - (deps test22.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test22.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test22.proto))) @@ -258,7 +321,10 @@ (rule (targets test23.ml test23.mli) - (deps test23.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test23.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test23.proto))) @@ -269,7 +335,10 @@ (rule (targets test24.ml test24.mli) - (deps test24.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test24.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test24.proto))) @@ -280,7 +349,10 @@ (rule (targets test25.ml test25.mli) - (deps test25.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test25.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ ./ test25.proto))) @@ -291,7 +363,10 @@ (rule (targets test26.ml test26.mli) - (deps test26.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test26.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc -I %{env:INCLUDE=/usr/include/} --binary --pp --ml_out ./ ./ test26.proto))) @@ -303,7 +378,10 @@ (rule (targets test27.ml test27.mli) - (deps test27.proto ../../include/ocaml-protoc/ocamloptions.proto (source_tree google)) + (deps + test27.proto + ../../include/ocaml-protoc/ocamloptions.proto + (source_tree google)) (action (run ocaml-protoc --binary --pp --ml_out ./ test27.proto))) From 8722e8dc89db1f961cb14354bd9f25d31c5c6114 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 14:12:58 -0400 Subject: [PATCH 42/47] bumpity bump --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 8fc0370e..bf5b3fc4 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ compiler**. See [here](https://github.com/mransan/bs-protobuf-demo) for complete example. - ### A simple example > This example generates the binary encoding, if you are more interested in a **JavaScript** From ee1a30de74d508b9f9d50ed7827a5e065cb8bdb6 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 15:05:21 -0400 Subject: [PATCH 43/47] fix: crazy link error fixed by moving `-lprotobuf` at the end: --- Makefile.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.test b/Makefile.test index 875c91ad..cfb9b565 100644 --- a/Makefile.test +++ b/Makefile.test @@ -57,10 +57,10 @@ $(INTEGRATION_TESTS_DIR)/test10_cpp.tsk: \ $(INTEGRATION_TESTS_DIR)/test10.pb.cc \ $(INTEGRATION_TESTS_DIR)/test09.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ - -I ./ -I $(INTEGRATION_TESTS_DIR) $(PB_HINC_I) \ - $(PB_LINC_L) -l protobuf \ + -I ./ -I $(INTEGRATION_TESTS_DIR) \ + $(PB_LINC_L) \ $? \ - -o $@ + -o $@ -l protobuf .SECONDARY: From 9672ed090f90d0333f556576966a2ecd5cbb5c9f Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 15:07:07 -0400 Subject: [PATCH 44/47] chore: try to reinforce CI by running integration tests in docker --- .dockerignore | 2 ++ .github/workflows/main.yml | 12 ++++++++---- dep/Dockerfile | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 .dockerignore create mode 100644 dep/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..f485c7c4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +_opam +_build diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a7dd6ebe..a1d7e6a3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,10 +35,14 @@ jobs: - run: opam exec -- dune build @install - run: opam exec -- dune runtest - # integration tests - - run: opam install ppx_deriving -y - - run: sudo apt install protobuf-compiler libprotobuf-dev - - run: opam exec -- make integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/x86_64-linux-gnu/ + integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - run: docker build -f dep/Dockerfile . --target=base + - run: docker build -f dep/Dockerfile . --target=run-the-damn-build format: name: format diff --git a/dep/Dockerfile b/dep/Dockerfile new file mode 100644 index 00000000..e785eea5 --- /dev/null +++ b/dep/Dockerfile @@ -0,0 +1,22 @@ +FROM ocaml/opam:debian-ocaml-4.14 AS base + +WORKDIR /build/ +RUN sudo chown -R opam: /build/ +RUN sudo apt install protobuf-compiler libprotobuf-dev -y +COPY --chown=opam ./src/ ./src/ +COPY --chown=opam pbrt.opam pbrt_services.opam pbrt_yojson.opam ocaml-protoc.opam \ + Makefile Makefile.test dune-project dune .ocamlformat \ + .ocamlformat-ignore ./ + +RUN opam pin -n . +RUN opam depext -yt ocaml-protoc +RUN opam install -t . --deps-only + +FROM base AS run-the-damn-build +RUN opam exec -- dune build @install +RUN opam exec -- dune runtest + +# integration tests +RUN opam install ppx_deriving -y +RUN opam exec -- make clean build integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/x86_64-linux-gnu/ + From 274fc93b80f8b8de9bd5cd7930eb90156f291375 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 7 Jun 2024 15:28:13 -0400 Subject: [PATCH 45/47] fix: turns out we don't need to vendor google's protos! --- Makefile.test | 4 +- dep/Dockerfile | 2 +- .../google/protobuf/any.proto | 162 --- .../google/protobuf/api.proto | 207 --- .../google/protobuf/cpp_features.proto | 30 - .../google/protobuf/descriptor.proto | 1218 ----------------- .../google/protobuf/duration.proto | 115 -- .../google/protobuf/empty.proto | 51 - .../google/protobuf/field_mask.proto | 245 ---- .../google/protobuf/source_context.proto | 48 - .../google/protobuf/struct.proto | 95 -- .../google/protobuf/timestamp.proto | 144 -- .../google/protobuf/type.proto | 193 --- .../google/protobuf/wrappers.proto | 123 -- 14 files changed, 3 insertions(+), 2634 deletions(-) delete mode 100644 src/tests/integration-tests/google/protobuf/any.proto delete mode 100644 src/tests/integration-tests/google/protobuf/api.proto delete mode 100644 src/tests/integration-tests/google/protobuf/cpp_features.proto delete mode 100644 src/tests/integration-tests/google/protobuf/descriptor.proto delete mode 100644 src/tests/integration-tests/google/protobuf/duration.proto delete mode 100644 src/tests/integration-tests/google/protobuf/empty.proto delete mode 100644 src/tests/integration-tests/google/protobuf/field_mask.proto delete mode 100644 src/tests/integration-tests/google/protobuf/source_context.proto delete mode 100644 src/tests/integration-tests/google/protobuf/struct.proto delete mode 100644 src/tests/integration-tests/google/protobuf/timestamp.proto delete mode 100644 src/tests/integration-tests/google/protobuf/type.proto delete mode 100644 src/tests/integration-tests/google/protobuf/wrappers.proto diff --git a/Makefile.test b/Makefile.test index cfb9b565..fb6b1715 100644 --- a/Makefile.test +++ b/Makefile.test @@ -48,7 +48,7 @@ $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc: $(OCAMLOPTIONS_HINC)/ocamloptions.proto %_cpp.tsk: %_cpp.cpp %.pb.cc $(OCAMLOPTIONS_HINC)/ocamloptions.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ -I ./ -I $(INTEGRATION_TESTS_DIR) -I $(OCAMLOPTIONS_HINC) $(PB_HINC_L) \ - $(PB_LINC_L) \ + $(PB_LINC_L) $(PB_HINC_I) \ $? \ -o $@ -l protobuf @@ -58,7 +58,7 @@ $(INTEGRATION_TESTS_DIR)/test10_cpp.tsk: \ $(INTEGRATION_TESTS_DIR)/test09.pb.cc $(CXX) $(CPPFLAGS) $(LDFLAGS) \ -I ./ -I $(INTEGRATION_TESTS_DIR) \ - $(PB_LINC_L) \ + $(PB_LINC_L) $(PB_HINC_I) \ $? \ -o $@ -l protobuf diff --git a/dep/Dockerfile b/dep/Dockerfile index e785eea5..b5a911d7 100644 --- a/dep/Dockerfile +++ b/dep/Dockerfile @@ -18,5 +18,5 @@ RUN opam exec -- dune runtest # integration tests RUN opam install ppx_deriving -y -RUN opam exec -- make clean build integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/x86_64-linux-gnu/ +RUN opam exec -- make clean build integration PB_LINC=/usr/lib/x86_64-linux-gnu/ PB_HINC=/usr/include/ diff --git a/src/tests/integration-tests/google/protobuf/any.proto b/src/tests/integration-tests/google/protobuf/any.proto deleted file mode 100644 index eff44e50..00000000 --- a/src/tests/integration-tests/google/protobuf/any.proto +++ /dev/null @@ -1,162 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/known/anypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// // or ... -// if (any.isSameTypeAs(Foo.getDefaultInstance())) { -// foo = any.unpack(Foo.getDefaultInstance()); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := anypb.New(foo) -// if err != nil { -// ... -// } -// ... -// foo := &pb.Foo{} -// if err := any.UnmarshalTo(foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// JSON -// ==== -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. This string must contain at least - // one "/" character. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. As of May 2023, there are no widely used type server - // implementations and no plans to implement one. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; -} diff --git a/src/tests/integration-tests/google/protobuf/api.proto b/src/tests/integration-tests/google/protobuf/api.proto deleted file mode 100644 index 42223516..00000000 --- a/src/tests/integration-tests/google/protobuf/api.proto +++ /dev/null @@ -1,207 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "google/protobuf/source_context.proto"; -import "google/protobuf/type.proto"; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "ApiProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/apipb"; - -// Api is a light-weight descriptor for an API Interface. -// -// Interfaces are also described as "protocol buffer services" in some contexts, -// such as by the "service" keyword in a .proto file, but they are different -// from API Services, which represent a concrete implementation of an interface -// as opposed to simply a description of methods and bindings. They are also -// sometimes simply referred to as "APIs" in other contexts, such as the name of -// this message itself. See https://cloud.google.com/apis/design/glossary for -// detailed terminology. -message Api { - // The fully qualified name of this interface, including package name - // followed by the interface's simple name. - string name = 1; - - // The methods of this interface, in unspecified order. - repeated Method methods = 2; - - // Any metadata attached to the interface. - repeated Option options = 3; - - // A version string for this interface. If specified, must have the form - // `major-version.minor-version`, as in `1.10`. If the minor version is - // omitted, it defaults to zero. If the entire version field is empty, the - // major version is derived from the package name, as outlined below. If the - // field is not empty, the version in the package name will be verified to be - // consistent with what is provided here. - // - // The versioning schema uses [semantic - // versioning](http://semver.org) where the major version number - // indicates a breaking change and the minor version an additive, - // non-breaking change. Both version numbers are signals to users - // what to expect from different versions, and should be carefully - // chosen based on the product plan. - // - // The major version is also reflected in the package name of the - // interface, which must end in `v`, as in - // `google.feature.v1`. For major versions 0 and 1, the suffix can - // be omitted. Zero major versions must only be used for - // experimental, non-GA interfaces. - // - string version = 4; - - // Source context for the protocol buffer service represented by this - // message. - SourceContext source_context = 5; - - // Included interfaces. See [Mixin][]. - repeated Mixin mixins = 6; - - // The source syntax of the service. - Syntax syntax = 7; -} - -// Method represents a method of an API interface. -message Method { - // The simple name of this method. - string name = 1; - - // A URL of the input message type. - string request_type_url = 2; - - // If true, the request is streamed. - bool request_streaming = 3; - - // The URL of the output message type. - string response_type_url = 4; - - // If true, the response is streamed. - bool response_streaming = 5; - - // Any metadata attached to the method. - repeated Option options = 6; - - // The source syntax of this method. - Syntax syntax = 7; -} - -// Declares an API Interface to be included in this interface. The including -// interface must redeclare all the methods from the included interface, but -// documentation and options are inherited as follows: -// -// - If after comment and whitespace stripping, the documentation -// string of the redeclared method is empty, it will be inherited -// from the original method. -// -// - Each annotation belonging to the service config (http, -// visibility) which is not set in the redeclared method will be -// inherited. -// -// - If an http annotation is inherited, the path pattern will be -// modified as follows. Any version prefix will be replaced by the -// version of the including interface plus the [root][] path if -// specified. -// -// Example of a simple mixin: -// -// package google.acl.v1; -// service AccessControl { -// // Get the underlying ACL object. -// rpc GetAcl(GetAclRequest) returns (Acl) { -// option (google.api.http).get = "/v1/{resource=**}:getAcl"; -// } -// } -// -// package google.storage.v2; -// service Storage { -// rpc GetAcl(GetAclRequest) returns (Acl); -// -// // Get a data record. -// rpc GetData(GetDataRequest) returns (Data) { -// option (google.api.http).get = "/v2/{resource=**}"; -// } -// } -// -// Example of a mixin configuration: -// -// apis: -// - name: google.storage.v2.Storage -// mixins: -// - name: google.acl.v1.AccessControl -// -// The mixin construct implies that all methods in `AccessControl` are -// also declared with same name and request/response types in -// `Storage`. A documentation generator or annotation processor will -// see the effective `Storage.GetAcl` method after inherting -// documentation and annotations as follows: -// -// service Storage { -// // Get the underlying ACL object. -// rpc GetAcl(GetAclRequest) returns (Acl) { -// option (google.api.http).get = "/v2/{resource=**}:getAcl"; -// } -// ... -// } -// -// Note how the version in the path pattern changed from `v1` to `v2`. -// -// If the `root` field in the mixin is specified, it should be a -// relative path under which inherited HTTP paths are placed. Example: -// -// apis: -// - name: google.storage.v2.Storage -// mixins: -// - name: google.acl.v1.AccessControl -// root: acls -// -// This implies the following inherited HTTP annotation: -// -// service Storage { -// // Get the underlying ACL object. -// rpc GetAcl(GetAclRequest) returns (Acl) { -// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; -// } -// ... -// } -message Mixin { - // The fully qualified name of the interface which is included. - string name = 1; - - // If non-empty specifies a path under which inherited HTTP paths - // are rooted. - string root = 2; -} diff --git a/src/tests/integration-tests/google/protobuf/cpp_features.proto b/src/tests/integration-tests/google/protobuf/cpp_features.proto deleted file mode 100644 index 2ba40e55..00000000 --- a/src/tests/integration-tests/google/protobuf/cpp_features.proto +++ /dev/null @@ -1,30 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2023 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -syntax = "proto2"; - -package pb; - -import "google/protobuf/descriptor.proto"; - -extend google.protobuf.FeatureSet { - optional CppFeatures cpp = 1000; -} - -message CppFeatures { - // Whether or not to treat an enum field as closed. This option is only - // applicable to enum fields, and will be removed in the future. It is - // consistent with the legacy behavior of using proto3 enum types for proto2 - // fields. - optional bool legacy_closed_enum = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "true" }, - edition_defaults = { edition: EDITION_PROTO3, value: "false" } - ]; -} diff --git a/src/tests/integration-tests/google/protobuf/descriptor.proto b/src/tests/integration-tests/google/protobuf/descriptor.proto deleted file mode 100644 index 47486435..00000000 --- a/src/tests/integration-tests/google/protobuf/descriptor.proto +++ /dev/null @@ -1,1218 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// The messages in this file describe the definitions found in .proto files. -// A valid .proto file can be translated directly to a FileDescriptorProto -// without any other information (e.g. without reading its imports). - -syntax = "proto2"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/descriptorpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// descriptor.proto must be optimized for speed because reflection-based -// algorithms don't work during bootstrapping. -option optimize_for = SPEED; - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -message FileDescriptorSet { - repeated FileDescriptorProto file = 1; -} - -// The full set of known editions. -enum Edition { - // A placeholder for an unknown edition value. - EDITION_UNKNOWN = 0; - - // Legacy syntax "editions". These pre-date editions, but behave much like - // distinct editions. These can't be used to specify the edition of proto - // files, but feature definitions must supply proto2/proto3 defaults for - // backwards compatibility. - EDITION_PROTO2 = 998; - EDITION_PROTO3 = 999; - - // Editions that have been released. The specific values are arbitrary and - // should not be depended on, but they will always be time-ordered for easy - // comparison. - EDITION_2023 = 1000; - - // Placeholder editions for testing feature resolution. These should not be - // used or relyed on outside of tests. - EDITION_1_TEST_ONLY = 1; - EDITION_2_TEST_ONLY = 2; - EDITION_99997_TEST_ONLY = 99997; - EDITION_99998_TEST_ONLY = 99998; - EDITION_99999_TEST_ONLY = 99999; -} - -// Describes a complete .proto file. -message FileDescriptorProto { - optional string name = 1; // file name, relative to root of source tree - optional string package = 2; // e.g. "foo", "foo.bar", etc. - - // Names of files imported by this file. - repeated string dependency = 3; - // Indexes of the public imported files in the dependency list above. - repeated int32 public_dependency = 10; - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - repeated int32 weak_dependency = 11; - - // All top-level definitions in this file. - repeated DescriptorProto message_type = 4; - repeated EnumDescriptorProto enum_type = 5; - repeated ServiceDescriptorProto service = 6; - repeated FieldDescriptorProto extension = 7; - - optional FileOptions options = 8; - - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - optional SourceCodeInfo source_code_info = 9; - - // The syntax of the proto file. - // The supported values are "proto2", "proto3", and "editions". - // - // If `edition` is present, this value must be "editions". - optional string syntax = 12; - - // The edition of the proto file. - optional Edition edition = 14; -} - -// Describes a message type. -message DescriptorProto { - optional string name = 1; - - repeated FieldDescriptorProto field = 2; - repeated FieldDescriptorProto extension = 6; - - repeated DescriptorProto nested_type = 3; - repeated EnumDescriptorProto enum_type = 4; - - message ExtensionRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - - optional ExtensionRangeOptions options = 3; - } - repeated ExtensionRange extension_range = 5; - - repeated OneofDescriptorProto oneof_decl = 8; - - optional MessageOptions options = 7; - - // Range of reserved tag numbers. Reserved tag numbers may not be used by - // fields or extension ranges in the same message. Reserved ranges may - // not overlap. - message ReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - } - repeated ReservedRange reserved_range = 9; - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - repeated string reserved_name = 10; -} - -message ExtensionRangeOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - message Declaration { - // The extension number declared within the extension range. - optional int32 number = 1; - - // The fully-qualified name of the extension field. There must be a leading - // dot in front of the full name. - optional string full_name = 2; - - // The fully-qualified type name of the extension field. Unlike - // Metadata.type, Declaration.type must have a leading dot for messages - // and enums. - optional string type = 3; - - // If true, indicates that the number is reserved in the extension range, - // and any extension field with the number will fail to compile. Set this - // when a declared extension field is deleted. - optional bool reserved = 5; - - // If true, indicates that the extension must be defined as repeated. - // Otherwise the extension must be defined as optional. - optional bool repeated = 6; - - reserved 4; // removed is_repeated - } - - // For external users: DO NOT USE. We are in the process of open sourcing - // extension declaration and executing internal cleanups before it can be - // used externally. - repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; - - // Any features defined in the specific edition. - optional FeatureSet features = 50; - - // The verification state of the extension range. - enum VerificationState { - // All the extensions of the range must be declared. - DECLARATION = 0; - UNVERIFIED = 1; - } - - // The verification state of the range. - // TODO: flip the default to DECLARATION once all empty ranges - // are marked as UNVERIFIED. - optional VerificationState verification = 3 [default = UNVERIFIED]; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// Describes a field within a message. -message FieldDescriptorProto { - enum Type { - // 0 is reserved for errors. - // Order is weird for historical reasons. - TYPE_DOUBLE = 1; - TYPE_FLOAT = 2; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - TYPE_INT64 = 3; - TYPE_UINT64 = 4; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - TYPE_INT32 = 5; - TYPE_FIXED64 = 6; - TYPE_FIXED32 = 7; - TYPE_BOOL = 8; - TYPE_STRING = 9; - // Tag-delimited aggregate. - // Group type is deprecated and not supported after google.protobuf. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. In Editions, the group wire format - // can be enabled via the `message_encoding` feature. - TYPE_GROUP = 10; - TYPE_MESSAGE = 11; // Length-delimited aggregate. - - // New in version 2. - TYPE_BYTES = 12; - TYPE_UINT32 = 13; - TYPE_ENUM = 14; - TYPE_SFIXED32 = 15; - TYPE_SFIXED64 = 16; - TYPE_SINT32 = 17; // Uses ZigZag encoding. - TYPE_SINT64 = 18; // Uses ZigZag encoding. - } - - enum Label { - // 0 is reserved for errors - LABEL_OPTIONAL = 1; - LABEL_REPEATED = 3; - // The required label is only allowed in google.protobuf. In proto3 and Editions - // it's explicitly prohibited. In Editions, the `field_presence` feature - // can be used to get this behavior. - LABEL_REQUIRED = 2; - } - - optional string name = 1; - optional int32 number = 3; - optional Label label = 4; - - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - optional Type type = 5; - - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - optional string type_name = 6; - - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - optional string extendee = 2; - - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - optional string default_value = 7; - - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - optional int32 oneof_index = 9; - - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - optional string json_name = 10; - - optional FieldOptions options = 8; - - // If true, this is a proto3 "optional". When a proto3 field is optional, it - // tracks presence regardless of field type. - // - // When proto3_optional is true, this field must be belong to a oneof to - // signal to old proto3 clients that presence is tracked for this field. This - // oneof is known as a "synthetic" oneof, and this field must be its sole - // member (each proto3 optional field gets its own synthetic oneof). Synthetic - // oneofs exist in the descriptor only, and do not generate any API. Synthetic - // oneofs must be ordered after all "real" oneofs. - // - // For message fields, proto3_optional doesn't create any semantic change, - // since non-repeated message fields always track presence. However it still - // indicates the semantic detail of whether the user wrote "optional" or not. - // This can be useful for round-tripping the .proto file. For consistency we - // give message fields a synthetic oneof also, even though it is not required - // to track presence. This is especially important because the parser can't - // tell if a field is a message or an enum, so it must always create a - // synthetic oneof. - // - // Proto2 optional fields do not set this flag, because they already indicate - // optional with `LABEL_OPTIONAL`. - optional bool proto3_optional = 17; -} - -// Describes a oneof. -message OneofDescriptorProto { - optional string name = 1; - optional OneofOptions options = 2; -} - -// Describes an enum type. -message EnumDescriptorProto { - optional string name = 1; - - repeated EnumValueDescriptorProto value = 2; - - optional EnumOptions options = 3; - - // Range of reserved numeric values. Reserved values may not be used by - // entries in the same enum. Reserved ranges may not overlap. - // - // Note that this is distinct from DescriptorProto.ReservedRange in that it - // is inclusive such that it can appropriately represent the entire int32 - // domain. - message EnumReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Inclusive. - } - - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - repeated EnumReservedRange reserved_range = 4; - - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - repeated string reserved_name = 5; -} - -// Describes a value within an enum. -message EnumValueDescriptorProto { - optional string name = 1; - optional int32 number = 2; - - optional EnumValueOptions options = 3; -} - -// Describes a service. -message ServiceDescriptorProto { - optional string name = 1; - repeated MethodDescriptorProto method = 2; - - optional ServiceOptions options = 3; -} - -// Describes a method of a service. -message MethodDescriptorProto { - optional string name = 1; - - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - optional string input_type = 2; - optional string output_type = 3; - - optional MethodOptions options = 4; - - // Identifies if client streams multiple client messages - optional bool client_streaming = 5 [default = false]; - // Identifies if server streams multiple server messages - optional bool server_streaming = 6 [default = false]; -} - -// =================================================================== -// Options - -// Each of the definitions above may have "options" attached. These are -// just annotations which may cause code to be generated slightly differently -// or may contain hints for code that manipulates protocol messages. -// -// Clients may define custom options as extensions of the *Options messages. -// These extensions may not yet be known at parsing time, so the parser cannot -// store the values in them. Instead it stores them in a field in the *Options -// message called uninterpreted_option. This field must have the same name -// across all *Options messages. We then use this field to populate the -// extensions when we build a descriptor, at which point all protos have been -// parsed and so all extensions are known. -// -// Extension numbers for custom options may be chosen as follows: -// * For options which will only be used within a single application or -// organization, or for experimental options, use field numbers 50000 -// through 99999. It is up to you to ensure that you do not use the -// same number for multiple options. -// * For options which will be published and used publicly by multiple -// independent entities, e-mail protobuf-global-extension-registry@google.com -// to reserve extension numbers. Simply provide your project name (e.g. -// Objective-C plugin) and your project website (if available) -- there's no -// need to explain how you intend to use them. Usually you only need one -// extension number. You can declare multiple options with only one extension -// number by putting them in a sub-message. See the Custom Options section of -// the docs for examples: -// https://developers.google.com/protocol-buffers/docs/proto#options -// If this turns out to be popular, a web service will be set up -// to automatically assign option numbers. - -message FileOptions { - - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - optional string java_package = 1; - - // Controls the name of the wrapper Java class generated for the .proto file. - // That class will always contain the .proto file's getDescriptor() method as - // well as any top-level extensions defined in the .proto file. - // If java_multiple_files is disabled, then all the other classes from the - // .proto file will be nested inside the single wrapper outer class. - optional string java_outer_classname = 8; - - // If enabled, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the wrapper class - // named by java_outer_classname. However, the wrapper class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - optional bool java_multiple_files = 10 [default = false]; - - // This option does nothing. - optional bool java_generate_equals_and_hash = 20 [deprecated=true]; - - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. - optional bool java_string_check_utf8 = 27 [default = false]; - - // Generated classes can be optimized for speed or code size. - enum OptimizeMode { - SPEED = 1; // Generate complete code for parsing, serialization, - // etc. - CODE_SIZE = 2; // Use ReflectionOps to implement these methods. - LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. - } - optional OptimizeMode optimize_for = 9 [default = SPEED]; - - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - optional string go_package = 11; - - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - optional bool cc_generic_services = 16 [default = false]; - optional bool java_generic_services = 17 [default = false]; - optional bool py_generic_services = 18 [default = false]; - optional bool php_generic_services = 42 [default = false]; - - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - optional bool deprecated = 23 [default = false]; - - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - optional bool cc_enable_arenas = 31 [default = true]; - - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - optional string objc_class_prefix = 36; - - // Namespace for generated classes; defaults to the package. - optional string csharp_namespace = 37; - - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - optional string swift_prefix = 39; - - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - optional string php_class_prefix = 40; - - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - optional string php_namespace = 41; - - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be - // used for determining the namespace. - optional string php_metadata_namespace = 44; - - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - optional string ruby_package = 45; - - // Any features defined in the specific edition. - optional FeatureSet features = 50; - - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. - // See the documentation for the "Options" section above. - extensions 1000 to max; - - reserved 38; -} - -message MessageOptions { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - optional bool message_set_wire_format = 1 [default = false]; - - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - optional bool no_standard_descriptor_accessor = 2 [default = false]; - - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - optional bool deprecated = 3 [default = false]; - - reserved 4, 5, 6; - - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - // - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementations still need to work as - // if the field is a repeated message field. - optional bool map_entry = 7; - - reserved 8; // javalite_serializable - reserved 9; // javanano_as_lite - - // Enable the legacy handling of JSON field name conflicts. This lowercases - // and strips underscored from the fields before comparison in proto3 only. - // The new behavior takes `json_name` into account and applies to proto2 as - // well. - // - // This should only be used as a temporary measure against broken builds due - // to the change in behavior for JSON field name conflicts. - // - // TODO This is legacy behavior we plan to remove once downstream - // teams have had time to migrate. - optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; - - // Any features defined in the specific edition. - optional FeatureSet features = 12; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message FieldOptions { - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is only implemented to support use of - // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - // type "bytes" in the open source release -- sorry, we'll try to include - // other types in a future version! - optional CType ctype = 1 [default = STRING]; - enum CType { - // Default mode. - STRING = 0; - - // The option [ctype=CORD] may be applied to a non-repeated field of type - // "bytes". It indicates that in C++, the data should be stored in a Cord - // instead of a string. For very large strings, this may reduce memory - // fragmentation. It may also allow better performance when parsing from a - // Cord, or when parsing with aliasing enabled, as the parsed Cord may then - // alias the original buffer. - CORD = 1; - - STRING_PIECE = 2; - } - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. This option is prohibited in - // Editions, but the `repeated_field_encoding` feature can be used to control - // the behavior. - optional bool packed = 2; - - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - optional JSType jstype = 6 [default = JS_NORMAL]; - enum JSType { - // Use the default type. - JS_NORMAL = 0; - - // Use JavaScript strings. - JS_STRING = 1; - - // Use JavaScript numbers. - JS_NUMBER = 2; - } - - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. - // - // As of May 2022, lazy verifies the contents of the byte stream during - // parsing. An invalid byte stream will cause the overall parsing to fail. - optional bool lazy = 5 [default = false]; - - // unverified_lazy does no correctness checks on the byte stream. This should - // only be used where lazy with verification is prohibitive for performance - // reasons. - optional bool unverified_lazy = 15 [default = false]; - - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - optional bool deprecated = 3 [default = false]; - - // For Google-internal migration only. Do not use. - optional bool weak = 10 [default = false]; - - // Indicate that the field value should not be printed out when using debug - // formats, e.g. when the field contains sensitive credentials. - optional bool debug_redact = 16 [default = false]; - - // If set to RETENTION_SOURCE, the option will be omitted from the binary. - // Note: as of January 2023, support for this is in progress and does not yet - // have an effect (b/264593489). - enum OptionRetention { - RETENTION_UNKNOWN = 0; - RETENTION_RUNTIME = 1; - RETENTION_SOURCE = 2; - } - - optional OptionRetention retention = 17; - - // This indicates the types of entities that the field may apply to when used - // as an option. If it is unset, then the field may be freely used as an - // option on any kind of entity. Note: as of January 2023, support for this is - // in progress and does not yet have an effect (b/264593489). - enum OptionTargetType { - TARGET_TYPE_UNKNOWN = 0; - TARGET_TYPE_FILE = 1; - TARGET_TYPE_EXTENSION_RANGE = 2; - TARGET_TYPE_MESSAGE = 3; - TARGET_TYPE_FIELD = 4; - TARGET_TYPE_ONEOF = 5; - TARGET_TYPE_ENUM = 6; - TARGET_TYPE_ENUM_ENTRY = 7; - TARGET_TYPE_SERVICE = 8; - TARGET_TYPE_METHOD = 9; - } - - repeated OptionTargetType targets = 19; - - message EditionDefault { - optional Edition edition = 3; - optional string value = 2; // Textproto value. - } - repeated EditionDefault edition_defaults = 20; - - // Any features defined in the specific edition. - optional FeatureSet features = 21; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; - - reserved 4; // removed jtype - reserved 18; // reserve target, target_obsolete_do_not_use -} - -message OneofOptions { - // Any features defined in the specific edition. - optional FeatureSet features = 1; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumOptions { - - // Set this option to true to allow mapping different tag names to the same - // value. - optional bool allow_alias = 2; - - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - optional bool deprecated = 3 [default = false]; - - reserved 5; // javanano_as_lite - - // Enable the legacy handling of JSON field name conflicts. This lowercases - // and strips underscored from the fields before comparison in proto3 only. - // The new behavior takes `json_name` into account and applies to proto2 as - // well. - // TODO Remove this legacy behavior once downstream teams have - // had time to migrate. - optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; - - // Any features defined in the specific edition. - optional FeatureSet features = 7; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumValueOptions { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - optional bool deprecated = 1 [default = false]; - - // Any features defined in the specific edition. - optional FeatureSet features = 2; - - // Indicate that fields annotated with this enum value should not be printed - // out when using debug formats, e.g. when the field contains sensitive - // credentials. - optional bool debug_redact = 3 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message ServiceOptions { - - // Any features defined in the specific edition. - optional FeatureSet features = 34; - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - optional bool deprecated = 33 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message MethodOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - optional bool deprecated = 33 [default = false]; - - // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - // or neither? HTTP based RPC implementation may choose GET verb for safe - // methods, and PUT verb for idempotent methods instead of the default POST. - enum IdempotencyLevel { - IDEMPOTENCY_UNKNOWN = 0; - NO_SIDE_EFFECTS = 1; // implies idempotent - IDEMPOTENT = 2; // idempotent, but may have side effects - } - optional IdempotencyLevel idempotency_level = 34 - [default = IDEMPOTENCY_UNKNOWN]; - - // Any features defined in the specific edition. - optional FeatureSet features = 35; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -message UninterpretedOption { - // The name of the uninterpreted option. Each string represents a segment in - // a dot-separated name. is_extension is true iff a segment represents an - // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents - // "foo.(bar.baz).moo". - message NamePart { - required string name_part = 1; - required bool is_extension = 2; - } - repeated NamePart name = 2; - - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - optional string identifier_value = 3; - optional uint64 positive_int_value = 4; - optional int64 negative_int_value = 5; - optional double double_value = 6; - optional bytes string_value = 7; - optional string aggregate_value = 8; -} - -// =================================================================== -// Features - -// TODO Enums in C++ gencode (and potentially other languages) are -// not well scoped. This means that each of the feature enums below can clash -// with each other. The short names we've chosen maximize call-site -// readability, but leave us very open to this scenario. A future feature will -// be designed and implemented to handle this, hopefully before we ever hit a -// conflict here. -message FeatureSet { - enum FieldPresence { - FIELD_PRESENCE_UNKNOWN = 0; - EXPLICIT = 1; - IMPLICIT = 2; - LEGACY_REQUIRED = 3; - } - optional FieldPresence field_presence = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "EXPLICIT" }, - edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" }, - edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" } - ]; - - enum EnumType { - ENUM_TYPE_UNKNOWN = 0; - OPEN = 1; - CLOSED = 2; - } - optional EnumType enum_type = 2 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "CLOSED" }, - edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" } - ]; - - enum RepeatedFieldEncoding { - REPEATED_FIELD_ENCODING_UNKNOWN = 0; - PACKED = 1; - EXPANDED = 2; - } - optional RepeatedFieldEncoding repeated_field_encoding = 3 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "EXPANDED" }, - edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" } - ]; - - enum Utf8Validation { - UTF8_VALIDATION_UNKNOWN = 0; - NONE = 1; - VERIFY = 2; - } - optional Utf8Validation utf8_validation = 4 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "NONE" }, - edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" } - ]; - - enum MessageEncoding { - MESSAGE_ENCODING_UNKNOWN = 0; - LENGTH_PREFIXED = 1; - DELIMITED = 2; - } - optional MessageEncoding message_encoding = 5 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "LENGTH_PREFIXED" } - ]; - - enum JsonFormat { - JSON_FORMAT_UNKNOWN = 0; - ALLOW = 1; - LEGACY_BEST_EFFORT = 2; - } - optional JsonFormat json_format = 6 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: EDITION_PROTO2, value: "LEGACY_BEST_EFFORT" }, - edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" } - ]; - - reserved 999; - - extensions 1000; // for Protobuf C++ - extensions 1001; // for Protobuf Java - - extensions 9995 to 9999; // For internal testing -} - -// A compiled specification for the defaults of a set of features. These -// messages are generated from FeatureSet extensions and can be used to seed -// feature resolution. The resolution with this object becomes a simple search -// for the closest matching edition, followed by proto merges. -message FeatureSetDefaults { - // A map from every known edition with a unique set of defaults to its - // defaults. Not all editions may be contained here. For a given edition, - // the defaults at the closest matching edition ordered at or before it should - // be used. This field must be in strict ascending order by edition. - message FeatureSetEditionDefault { - optional Edition edition = 3; - optional FeatureSet features = 2; - } - repeated FeatureSetEditionDefault defaults = 1; - - // The minimum supported edition (inclusive) when this was constructed. - // Editions before this will not have defaults. - optional Edition minimum_edition = 4; - - // The maximum known edition (inclusive) when this was constructed. Editions - // after this will not have reliable defaults. - optional Edition maximum_edition = 5; -} - -// =================================================================== -// Optional source code info - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -message SourceCodeInfo { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendant. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - repeated Location location = 1; - message Location { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition occurs. - // For example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - repeated int32 path = 1 [packed = true]; - - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - repeated int32 span = 2 [packed = true]; - - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to moo. - // // - // // Another line attached to moo. - // optional double moo = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to moo or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - optional string leading_comments = 3; - optional string trailing_comments = 4; - repeated string leading_detached_comments = 6; - } -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -message GeneratedCodeInfo { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - repeated Annotation annotation = 1; - message Annotation { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - repeated int32 path = 1 [packed = true]; - - // Identifies the filesystem path to the original source .proto. - optional string source_file = 2; - - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - optional int32 begin = 3; - - // Identifies the ending offset in bytes in the generated code that - // relates to the identified object. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - optional int32 end = 4; - - // Represents the identified object's effect on the element in the original - // .proto file. - enum Semantic { - // There is no effect or the effect is indescribable. - NONE = 0; - // The element is set or otherwise mutated. - SET = 1; - // An alias to the element is returned. - ALIAS = 2; - } - optional Semantic semantic = 5; - } -} diff --git a/src/tests/integration-tests/google/protobuf/duration.proto b/src/tests/integration-tests/google/protobuf/duration.proto deleted file mode 100644 index 41f40c22..00000000 --- a/src/tests/integration-tests/google/protobuf/duration.proto +++ /dev/null @@ -1,115 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/durationpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DurationProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Duration represents a signed, fixed-length span of time represented -// as a count of seconds and fractions of seconds at nanosecond -// resolution. It is independent of any calendar and concepts like "day" -// or "month". It is related to Timestamp in that the difference between -// two Timestamp values is a Duration and it can be added or subtracted -// from a Timestamp. Range is approximately +-10,000 years. -// -// # Examples -// -// Example 1: Compute Duration from two Timestamps in pseudo code. -// -// Timestamp start = ...; -// Timestamp end = ...; -// Duration duration = ...; -// -// duration.seconds = end.seconds - start.seconds; -// duration.nanos = end.nanos - start.nanos; -// -// if (duration.seconds < 0 && duration.nanos > 0) { -// duration.seconds += 1; -// duration.nanos -= 1000000000; -// } else if (duration.seconds > 0 && duration.nanos < 0) { -// duration.seconds -= 1; -// duration.nanos += 1000000000; -// } -// -// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -// -// Timestamp start = ...; -// Duration duration = ...; -// Timestamp end = ...; -// -// end.seconds = start.seconds + duration.seconds; -// end.nanos = start.nanos + duration.nanos; -// -// if (end.nanos < 0) { -// end.seconds -= 1; -// end.nanos += 1000000000; -// } else if (end.nanos >= 1000000000) { -// end.seconds += 1; -// end.nanos -= 1000000000; -// } -// -// Example 3: Compute Duration from datetime.timedelta in Python. -// -// td = datetime.timedelta(days=3, minutes=10) -// duration = Duration() -// duration.FromTimedelta(td) -// -// # JSON Mapping -// -// In JSON format, the Duration type is encoded as a string rather than an -// object, where the string ends in the suffix "s" (indicating seconds) and -// is preceded by the number of seconds, with nanoseconds expressed as -// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -// microsecond should be expressed in JSON format as "3.000001s". -// -message Duration { - // Signed seconds of the span of time. Must be from -315,576,000,000 - // to +315,576,000,000 inclusive. Note: these bounds are computed from: - // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - int64 seconds = 1; - - // Signed fractions of a second at nanosecond resolution of the span - // of time. Durations less than one second are represented with a 0 - // `seconds` field and a positive or negative `nanos` field. For durations - // of one second or more, a non-zero value for the `nanos` field must be - // of the same sign as the `seconds` field. Must be from -999,999,999 - // to +999,999,999 inclusive. - int32 nanos = 2; -} diff --git a/src/tests/integration-tests/google/protobuf/empty.proto b/src/tests/integration-tests/google/protobuf/empty.proto deleted file mode 100644 index b87c89dc..00000000 --- a/src/tests/integration-tests/google/protobuf/empty.proto +++ /dev/null @@ -1,51 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/known/emptypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "EmptyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; - -// A generic empty message that you can re-use to avoid defining duplicated -// empty messages in your APIs. A typical example is to use it as the request -// or the response type of an API method. For instance: -// -// service Foo { -// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); -// } -// -message Empty {} diff --git a/src/tests/integration-tests/google/protobuf/field_mask.proto b/src/tests/integration-tests/google/protobuf/field_mask.proto deleted file mode 100644 index b28334b9..00000000 --- a/src/tests/integration-tests/google/protobuf/field_mask.proto +++ /dev/null @@ -1,245 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "FieldMaskProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; -option cc_enable_arenas = true; - -// `FieldMask` represents a set of symbolic field paths, for example: -// -// paths: "f.a" -// paths: "f.b.d" -// -// Here `f` represents a field in some root message, `a` and `b` -// fields in the message found in `f`, and `d` a field found in the -// message in `f.b`. -// -// Field masks are used to specify a subset of fields that should be -// returned by a get operation or modified by an update operation. -// Field masks also have a custom JSON encoding (see below). -// -// # Field Masks in Projections -// -// When used in the context of a projection, a response message or -// sub-message is filtered by the API to only contain those fields as -// specified in the mask. For example, if the mask in the previous -// example is applied to a response message as follows: -// -// f { -// a : 22 -// b { -// d : 1 -// x : 2 -// } -// y : 13 -// } -// z: 8 -// -// The result will not contain specific values for fields x,y and z -// (their value will be set to the default, and omitted in proto text -// output): -// -// -// f { -// a : 22 -// b { -// d : 1 -// } -// } -// -// A repeated field is not allowed except at the last position of a -// paths string. -// -// If a FieldMask object is not present in a get operation, the -// operation applies to all fields (as if a FieldMask of all fields -// had been specified). -// -// Note that a field mask does not necessarily apply to the -// top-level response message. In case of a REST get operation, the -// field mask applies directly to the response, but in case of a REST -// list operation, the mask instead applies to each individual message -// in the returned resource list. In case of a REST custom method, -// other definitions may be used. Where the mask applies will be -// clearly documented together with its declaration in the API. In -// any case, the effect on the returned resource/resources is required -// behavior for APIs. -// -// # Field Masks in Update Operations -// -// A field mask in update operations specifies which fields of the -// targeted resource are going to be updated. The API is required -// to only change the values of the fields as specified in the mask -// and leave the others untouched. If a resource is passed in to -// describe the updated values, the API ignores the values of all -// fields not covered by the mask. -// -// If a repeated field is specified for an update operation, new values will -// be appended to the existing repeated field in the target resource. Note that -// a repeated field is only allowed in the last position of a `paths` string. -// -// If a sub-message is specified in the last position of the field mask for an -// update operation, then new value will be merged into the existing sub-message -// in the target resource. -// -// For example, given the target message: -// -// f { -// b { -// d: 1 -// x: 2 -// } -// c: [1] -// } -// -// And an update message: -// -// f { -// b { -// d: 10 -// } -// c: [2] -// } -// -// then if the field mask is: -// -// paths: ["f.b", "f.c"] -// -// then the result will be: -// -// f { -// b { -// d: 10 -// x: 2 -// } -// c: [1, 2] -// } -// -// An implementation may provide options to override this default behavior for -// repeated and message fields. -// -// In order to reset a field's value to the default, the field must -// be in the mask and set to the default value in the provided resource. -// Hence, in order to reset all fields of a resource, provide a default -// instance of the resource and set all fields in the mask, or do -// not provide a mask as described below. -// -// If a field mask is not present on update, the operation applies to -// all fields (as if a field mask of all fields has been specified). -// Note that in the presence of schema evolution, this may mean that -// fields the client does not know and has therefore not filled into -// the request will be reset to their default. If this is unwanted -// behavior, a specific service may require a client to always specify -// a field mask, producing an error if not. -// -// As with get operations, the location of the resource which -// describes the updated values in the request message depends on the -// operation kind. In any case, the effect of the field mask is -// required to be honored by the API. -// -// ## Considerations for HTTP REST -// -// The HTTP kind of an update operation which uses a field mask must -// be set to PATCH instead of PUT in order to satisfy HTTP semantics -// (PUT must only be used for full updates). -// -// # JSON Encoding of Field Masks -// -// In JSON, a field mask is encoded as a single string where paths are -// separated by a comma. Fields name in each path are converted -// to/from lower-camel naming conventions. -// -// As an example, consider the following message declarations: -// -// message Profile { -// User user = 1; -// Photo photo = 2; -// } -// message User { -// string display_name = 1; -// string address = 2; -// } -// -// In proto a field mask for `Profile` may look as such: -// -// mask { -// paths: "user.display_name" -// paths: "photo" -// } -// -// In JSON, the same mask is represented as below: -// -// { -// mask: "user.displayName,photo" -// } -// -// # Field Masks and Oneof Fields -// -// Field masks treat fields in oneofs just as regular fields. Consider the -// following message: -// -// message SampleMessage { -// oneof test_oneof { -// string name = 4; -// SubMessage sub_message = 9; -// } -// } -// -// The field mask can be: -// -// mask { -// paths: "name" -// } -// -// Or: -// -// mask { -// paths: "sub_message" -// } -// -// Note that oneof type names ("test_oneof" in this case) cannot be used in -// paths. -// -// ## Field Mask Verification -// -// The implementation of any API method which has a FieldMask type field in the -// request should verify the included field paths, and return an -// `INVALID_ARGUMENT` error if any path is unmappable. -message FieldMask { - // The set of field mask paths. - repeated string paths = 1; -} diff --git a/src/tests/integration-tests/google/protobuf/source_context.proto b/src/tests/integration-tests/google/protobuf/source_context.proto deleted file mode 100644 index 135f50fe..00000000 --- a/src/tests/integration-tests/google/protobuf/source_context.proto +++ /dev/null @@ -1,48 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "SourceContextProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; - -// `SourceContext` represents information about the source of a -// protobuf element, like the file in which it is defined. -message SourceContext { - // The path-qualified name of the .proto file that contained the associated - // protobuf element. For example: `"google/protobuf/source_context.proto"`. - string file_name = 1; -} diff --git a/src/tests/integration-tests/google/protobuf/struct.proto b/src/tests/integration-tests/google/protobuf/struct.proto deleted file mode 100644 index 1bf0c1ad..00000000 --- a/src/tests/integration-tests/google/protobuf/struct.proto +++ /dev/null @@ -1,95 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/structpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "StructProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Struct` represents a structured data value, consisting of fields -// which map to dynamically typed values. In some languages, `Struct` -// might be supported by a native representation. For example, in -// scripting languages like JS a struct is represented as an -// object. The details of that representation are described together -// with the proto support for the language. -// -// The JSON representation for `Struct` is JSON object. -message Struct { - // Unordered map of dynamically typed values. - map fields = 1; -} - -// `Value` represents a dynamically typed value which can be either -// null, a number, a string, a boolean, a recursive struct value, or a -// list of values. A producer of value is expected to set one of these -// variants. Absence of any variant indicates an error. -// -// The JSON representation for `Value` is JSON value. -message Value { - // The kind of value. - oneof kind { - // Represents a null value. - NullValue null_value = 1; - // Represents a double value. - double number_value = 2; - // Represents a string value. - string string_value = 3; - // Represents a boolean value. - bool bool_value = 4; - // Represents a structured value. - Struct struct_value = 5; - // Represents a repeated `Value`. - ListValue list_value = 6; - } -} - -// `NullValue` is a singleton enumeration to represent the null value for the -// `Value` type union. -// -// The JSON representation for `NullValue` is JSON `null`. -enum NullValue { - // Null value. - NULL_VALUE = 0; -} - -// `ListValue` is a wrapper around a repeated field of values. -// -// The JSON representation for `ListValue` is JSON array. -message ListValue { - // Repeated field of dynamically typed values. - repeated Value values = 1; -} diff --git a/src/tests/integration-tests/google/protobuf/timestamp.proto b/src/tests/integration-tests/google/protobuf/timestamp.proto deleted file mode 100644 index fd0bc07d..00000000 --- a/src/tests/integration-tests/google/protobuf/timestamp.proto +++ /dev/null @@ -1,144 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/timestamppb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TimestampProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Timestamp represents a point in time independent of any time zone or local -// calendar, encoded as a count of seconds and fractions of seconds at -// nanosecond resolution. The count is relative to an epoch at UTC midnight on -// January 1, 1970, in the proleptic Gregorian calendar which extends the -// Gregorian calendar backwards to year one. -// -// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap -// second table is needed for interpretation, using a [24-hour linear -// smear](https://developers.google.com/time/smear). -// -// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By -// restricting to that range, we ensure that we can convert to and from [RFC -// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// Example 5: Compute Timestamp from Java `Instant.now()`. -// -// Instant now = Instant.now(); -// -// Timestamp timestamp = -// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) -// .setNanos(now.getNano()).build(); -// -// Example 6: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A proto3 JSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a proto3 JSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard -// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using -// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with -// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use -// the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() -// ) to obtain a formatter capable of generating timestamps in this format. -// -message Timestamp { - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - int32 nanos = 2; -} diff --git a/src/tests/integration-tests/google/protobuf/type.proto b/src/tests/integration-tests/google/protobuf/type.proto deleted file mode 100644 index 48cb11e7..00000000 --- a/src/tests/integration-tests/google/protobuf/type.proto +++ /dev/null @@ -1,193 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "google/protobuf/any.proto"; -import "google/protobuf/source_context.proto"; - -option cc_enable_arenas = true; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TypeProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/typepb"; - -// A protocol buffer message type. -message Type { - // The fully qualified message name. - string name = 1; - // The list of fields. - repeated Field fields = 2; - // The list of types appearing in `oneof` definitions in this type. - repeated string oneofs = 3; - // The protocol buffer options. - repeated Option options = 4; - // The source context. - SourceContext source_context = 5; - // The source syntax. - Syntax syntax = 6; - // The source edition string, only valid when syntax is SYNTAX_EDITIONS. - string edition = 7; -} - -// A single field of a message type. -message Field { - // Basic field types. - enum Kind { - // Field type unknown. - TYPE_UNKNOWN = 0; - // Field type double. - TYPE_DOUBLE = 1; - // Field type float. - TYPE_FLOAT = 2; - // Field type int64. - TYPE_INT64 = 3; - // Field type uint64. - TYPE_UINT64 = 4; - // Field type int32. - TYPE_INT32 = 5; - // Field type fixed64. - TYPE_FIXED64 = 6; - // Field type fixed32. - TYPE_FIXED32 = 7; - // Field type bool. - TYPE_BOOL = 8; - // Field type string. - TYPE_STRING = 9; - // Field type group. Proto2 syntax only, and deprecated. - TYPE_GROUP = 10; - // Field type message. - TYPE_MESSAGE = 11; - // Field type bytes. - TYPE_BYTES = 12; - // Field type uint32. - TYPE_UINT32 = 13; - // Field type enum. - TYPE_ENUM = 14; - // Field type sfixed32. - TYPE_SFIXED32 = 15; - // Field type sfixed64. - TYPE_SFIXED64 = 16; - // Field type sint32. - TYPE_SINT32 = 17; - // Field type sint64. - TYPE_SINT64 = 18; - } - - // Whether a field is optional, required, or repeated. - enum Cardinality { - // For fields with unknown cardinality. - CARDINALITY_UNKNOWN = 0; - // For optional fields. - CARDINALITY_OPTIONAL = 1; - // For required fields. Proto2 syntax only. - CARDINALITY_REQUIRED = 2; - // For repeated fields. - CARDINALITY_REPEATED = 3; - } - - // The field type. - Kind kind = 1; - // The field cardinality. - Cardinality cardinality = 2; - // The field number. - int32 number = 3; - // The field name. - string name = 4; - // The field type URL, without the scheme, for message or enumeration - // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. - string type_url = 6; - // The index of the field type in `Type.oneofs`, for message or enumeration - // types. The first type has index 1; zero means the type is not in the list. - int32 oneof_index = 7; - // Whether to use alternative packed wire representation. - bool packed = 8; - // The protocol buffer options. - repeated Option options = 9; - // The field JSON name. - string json_name = 10; - // The string value of the default value of this field. Proto2 syntax only. - string default_value = 11; -} - -// Enum type definition. -message Enum { - // Enum type name. - string name = 1; - // Enum value definitions. - repeated EnumValue enumvalue = 2; - // Protocol buffer options. - repeated Option options = 3; - // The source context. - SourceContext source_context = 4; - // The source syntax. - Syntax syntax = 5; - // The source edition string, only valid when syntax is SYNTAX_EDITIONS. - string edition = 6; -} - -// Enum value definition. -message EnumValue { - // Enum value name. - string name = 1; - // Enum value number. - int32 number = 2; - // Protocol buffer options. - repeated Option options = 3; -} - -// A protocol buffer option, which can be attached to a message, field, -// enumeration, etc. -message Option { - // The option's name. For protobuf built-in options (options defined in - // descriptor.proto), this is the short name. For example, `"map_entry"`. - // For custom options, it should be the fully-qualified name. For example, - // `"google.api.http"`. - string name = 1; - // The option's value packed in an Any message. If the value is a primitive, - // the corresponding wrapper type defined in google/protobuf/wrappers.proto - // should be used. If the value is an enum, it should be stored as an int32 - // value using the google.protobuf.Int32Value type. - Any value = 2; -} - -// The syntax in which a protocol buffer element is defined. -enum Syntax { - // Syntax `proto2`. - SYNTAX_PROTO2 = 0; - // Syntax `proto3`. - SYNTAX_PROTO3 = 1; - // Syntax `editions`. - SYNTAX_EDITIONS = 2; -} diff --git a/src/tests/integration-tests/google/protobuf/wrappers.proto b/src/tests/integration-tests/google/protobuf/wrappers.proto deleted file mode 100644 index 1959fa55..00000000 --- a/src/tests/integration-tests/google/protobuf/wrappers.proto +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Wrappers for primitive (non-message) types. These types are useful -// for embedding primitives in the `google.protobuf.Any` type and for places -// where we need to distinguish between the absence of a primitive -// typed field and its default value. -// -// These wrappers have no meaningful use within repeated fields as they lack -// the ability to detect presence on individual elements. -// These wrappers have no meaningful use within a map or a oneof since -// individual entries of a map or fields of a oneof can already detect presence. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// Wrapper message for `double`. -// -// The JSON representation for `DoubleValue` is JSON number. -message DoubleValue { - // The double value. - double value = 1; -} - -// Wrapper message for `float`. -// -// The JSON representation for `FloatValue` is JSON number. -message FloatValue { - // The float value. - float value = 1; -} - -// Wrapper message for `int64`. -// -// The JSON representation for `Int64Value` is JSON string. -message Int64Value { - // The int64 value. - int64 value = 1; -} - -// Wrapper message for `uint64`. -// -// The JSON representation for `UInt64Value` is JSON string. -message UInt64Value { - // The uint64 value. - uint64 value = 1; -} - -// Wrapper message for `int32`. -// -// The JSON representation for `Int32Value` is JSON number. -message Int32Value { - // The int32 value. - int32 value = 1; -} - -// Wrapper message for `uint32`. -// -// The JSON representation for `UInt32Value` is JSON number. -message UInt32Value { - // The uint32 value. - uint32 value = 1; -} - -// Wrapper message for `bool`. -// -// The JSON representation for `BoolValue` is JSON `true` and `false`. -message BoolValue { - // The bool value. - bool value = 1; -} - -// Wrapper message for `string`. -// -// The JSON representation for `StringValue` is JSON string. -message StringValue { - // The string value. - string value = 1; -} - -// Wrapper message for `bytes`. -// -// The JSON representation for `BytesValue` is JSON string. -message BytesValue { - // The bytes value. - bytes value = 1; -} From 3e2b2a9996a867293934f1c9417a6f70949b7ee9 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Tue, 11 Jun 2024 10:52:40 +0400 Subject: [PATCH 46/47] Fix compilation of option_processing.proto --- src/tests/expectation/dune | 7 +++++++ src/tests/expectation/it_compiles.ml | 3 +++ .../expectation/option_processing.ml.expected | 16 ++++++++-------- src/tests/expectation/option_processing.proto | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 src/tests/expectation/it_compiles.ml diff --git a/src/tests/expectation/dune b/src/tests/expectation/dune index 0912187d..47a5edc8 100644 --- a/src/tests/expectation/dune +++ b/src/tests/expectation/dune @@ -12,6 +12,13 @@ (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)) + (rule (targets option_processing.ml option_processing.mli) (deps option_processing.proto) diff --git a/src/tests/expectation/it_compiles.ml b/src/tests/expectation/it_compiles.ml new file mode 100644 index 00000000..844e98a6 --- /dev/null +++ b/src/tests/expectation/it_compiles.ml @@ -0,0 +1,3 @@ +[@@@warning "-66"] + +open! Option_processing diff --git a/src/tests/expectation/option_processing.ml.expected b/src/tests/expectation/option_processing.ml.expected index 72bc09b8..95634a35 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 8aae5c13..c7af9c19 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"]; From 53bcc4736937ff9c35ffc2a9803865a1f22c4963 Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Tue, 11 Jun 2024 10:21:42 +0400 Subject: [PATCH 47/47] Parsing of Pb_options according to protobuf schema --- src/compilerlib/dune | 11 +- .../pb_codegen_decode_pb_options.ml | 346 +++ .../pb_codegen_decode_pb_options.mli | 5 + src/ocaml-protoc/ocaml_protoc_cmdline.ml | 6 + src/ocaml-protoc/ocaml_protoc_generation.ml | 4 + src/runtime-pb-options/dune | 6 + src/runtime-pb-options/pbrt_pb_options.ml | 147 + src/runtime-pb-options/pbrt_pb_options.mli | 34 + src/tests/expectation/dune | 18 + .../test_decode_pb_options.expected | 87 + .../expectation/test_decode_pb_options.ml | 74 + src/tests/expectation/validate.ml.expected | 2480 +++++++++++++++++ src/tests/expectation/validate.proto | 883 ++++++ 13 files changed, 4096 insertions(+), 5 deletions(-) create mode 100644 src/compilerlib/pb_codegen_decode_pb_options.ml create mode 100644 src/compilerlib/pb_codegen_decode_pb_options.mli create mode 100644 src/runtime-pb-options/dune create mode 100644 src/runtime-pb-options/pbrt_pb_options.ml create mode 100644 src/runtime-pb-options/pbrt_pb_options.mli create mode 100644 src/tests/expectation/test_decode_pb_options.expected create mode 100644 src/tests/expectation/test_decode_pb_options.ml create mode 100644 src/tests/expectation/validate.ml.expected create mode 100644 src/tests/expectation/validate.proto diff --git a/src/compilerlib/dune b/src/compilerlib/dune index 8a8acde4..d0cd6229 100644 --- a/src/compilerlib/dune +++ b/src/compilerlib/dune @@ -13,9 +13,10 @@ pb_codegen_make pb_codegen_encode_binary pb_codegen_encode_bs pb_codegen_encode_yojson pb_codegen_formatting pb_codegen_ocaml_type_dump pb_codegen_ocaml_type pb_codegen_pp pb_codegen_plugin pb_codegen_types - pb_codegen_services pb_codegen_util pb_exception pb_field_type pb_location - pb_logger pb_option pb_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 00000000..5278ea4b --- /dev/null +++ b/src/compilerlib/pb_codegen_decode_pb_options.ml @@ -0,0 +1,346 @@ +module Ot = Pb_codegen_ocaml_type +module F = Pb_codegen_formatting + +let sp = Pb_codegen_util.sp + +let field_pattern_match ~r_name ~rf_label field_type = + match field_type with + | Ot.Ft_basic_type bt -> + let decode runtime_f = + sp "Pbrt_pb_options.%s pb_options_value \"%s\" \"%s\"" runtime_f r_name + rf_label + in + let exp = + match bt with + | Ot.Bt_string -> decode "string" + | Ot.Bt_float -> decode "float" + | Ot.Bt_int -> decode "int" + | Ot.Bt_int32 -> decode "int32" + | Ot.Bt_int64 -> decode "int64" + | Ot.Bt_uint32 -> sp "`unsigned (%s)" (decode "int32") + | Ot.Bt_uint64 -> sp "`unsigned (%s)" (decode "int64") + | Ot.Bt_bool -> decode "bool" + | Ot.Bt_bytes -> decode "bytes" + in + "pb_options_value", exp + | Ot.Ft_unit -> + ( "pb_options_value", + sp "Pbrt_pb_options.unit pb_options_value \"%s\" \"%s\"" r_name rf_label ) + | Ot.Ft_user_defined_type udt -> + let f_name = + let function_prefix = "decode_pb_options" in + Pb_codegen_util.function_name_of_user_defined ~function_prefix udt + in + let value_expression = "(" ^ f_name ^ " pb_options_value)" in + "pb_options_value", value_expression + | _ -> assert false + +let pb_options_label_of_field_label rf_label = + match rf_label with + | "and_" | "as_" | "assert_" | "begin_" | "class_" | "constraint_" | "do_" + | "done_" | "downto_" | "else_" | "end_" | "exception_" | "external_" + | "false_" | "for_" | "fun_" | "function_" | "functor_" | "if_" | "in_" + | "include_" | "inherit_" | "initializer_" | "lazy_" | "let_" | "match_" + | "method_" | "module_" | "mutable_" | "new_" | "nonrec_" | "object_" | "of_" + | "open_" | "or_" | "private_" | "rec_" | "sig_" | "struct_" | "then_" | "to_" + | "true_" | "try_" | "type_" | "unit_" | "val_" | "virtual_" | "when_" + | "while_" | "with_" | "mod_" | "land_" | "lor_" | "lxor_" | "lsl_" | "lsr_" + | "asr_" -> + String.sub rf_label 0 (String.length rf_label - 1) + | _ -> rf_label + +(* Generate all the pattern matches for a record field *) +let gen_rft_nolabel sc ~r_name ~rf_label (field_type, _, _) = + let pb_options_label = pb_options_label_of_field_label rf_label in + + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + F.linep sc "| (\"%s\", %s) -> " pb_options_label match_variable_name; + F.linep sc " v.%s <- %s" rf_label exp + +(* Generate all the pattern matches for a repeated field *) +let gen_rft_repeated_field sc ~r_name ~rf_label repeated_field = + let _, field_type, _, _, _ = repeated_field in + + let pb_options_label = pb_options_label_of_field_label rf_label in + + F.linep sc + "| (\"%s\", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin" + pb_options_label; + + F.sub_scope sc (fun sc -> + F.linep sc "v.%s <- List.map (function" rf_label; + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + F.linep sc " | %s -> %s" match_variable_name exp; + F.line sc ") l;"); + + F.line sc "end" + +let gen_rft_optional_field sc ~r_name ~rf_label optional_field = + let field_type, _, _, _ = optional_field in + + let pb_options_label = pb_options_label_of_field_label rf_label in + + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + + F.linep sc "| (\"%s\", %s) -> " pb_options_label match_variable_name; + F.linep sc " v.%s <- Some (%s)" rf_label exp + +(* Generate pattern match for a variant field *) +let gen_rft_variant_field sc ~r_name ~rf_label { Ot.v_constructors; _ } = + List.iter + (fun { Ot.vc_constructor; vc_field_type; _ } -> + let pb_options_label = + Pb_codegen_util.camel_case_of_constructor vc_constructor + in + + match vc_field_type with + | Ot.Vct_nullary -> + F.linep sc "| (\"%s\", _) -> v.%s <- Some %s" pb_options_label rf_label + vc_constructor + | Ot.Vct_non_nullary_constructor field_type -> + let match_variable_name, exp = + field_pattern_match ~r_name ~rf_label field_type + in + F.linep sc "| (\"%s\", %s) -> " pb_options_label match_variable_name; + F.linep sc " v.%s <- Some (%s (%s))" rf_label vc_constructor exp) + v_constructors + +let gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type ~value_type = + let pb_options_label = pb_options_label_of_field_label rf_label in + F.linep sc + "| (\"%s\", Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc) ->" + pb_options_label; + F.sub_scope sc (fun sc -> + let value_name, value_exp = + field_pattern_match ~r_name ~rf_label value_type + in + let key_name = "key" in + let key_exp = + match key_type with + | Ot.Bt_string -> "key" + | Ot.Bt_int -> "(Int.of_string key)" + | Ot.Bt_int32 -> "(Int32.of_string key)" + | Ot.Bt_int64 -> "(Int64.of_string key)" + | Ot.Bt_uint32 -> "(`unsigned (Int32.of_string key))" + | Ot.Bt_uint64 -> "(`unsigned (Int64.of_string key))" + | Ot.Bt_bool -> "(Bool.of_string key)" + | Ot.Bt_float -> + Printf.eprintf "float cannot be used as a map key type"; + exit 1 + | Ot.Bt_bytes -> + Printf.eprintf "bytes cannot be used as a map key type"; + exit 1 + in + F.line sc "let assoc ="; + F.sub_scope sc (fun sc -> + F.line sc "assoc"; + F.linep sc "|> List.map (fun (%s, %s) -> (%s, %s)) " key_name + value_name key_exp value_exp; + F.line sc "|> List.to_seq"; + (* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there + is a repeated key we take the last value associated with it. *) + F.line sc "|> Hashtbl.of_seq"); + F.line sc "in"; + let assoc_exp = + match assoc_type with + | Ot.At_hashtable -> "assoc" + | Ot.At_list -> "assoc |> Hashtbl.to_seq |> List.of_seq" + in + F.linep sc "v.%s <- %s" rf_label assoc_exp) + +(* Generate decode function for a record *) +let gen_record ?and_ { Ot.r_name; r_fields } sc = + let mutable_record_name = Pb_codegen_util.mutable_record_name r_name in + + F.line sc + @@ sp "%s decode_pb_options_%s d =" + (Pb_codegen_util.let_decl_of_and and_) + r_name; + + F.sub_scope sc (fun sc -> + F.linep sc "let v = default_%s () in" mutable_record_name; + F.line sc @@ "let assoc = match d with"; + F.line sc + @@ " | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> \ + assoc"; + F.line sc @@ " | _ -> assert(false)"; + (* TODO raise E *) + F.line sc @@ "in"; + + F.line sc "List.iter (function "; + F.sub_scope sc (fun sc -> + (* Generate pattern match for all the possible message field *) + List.iter + (fun { Ot.rf_label; rf_field_type; _ } -> + match rf_field_type with + | Ot.Rft_nolabel nolabel_field -> + gen_rft_nolabel sc ~r_name ~rf_label nolabel_field + | Ot.Rft_repeated repeated_field -> + gen_rft_repeated_field sc ~r_name ~rf_label repeated_field + | Ot.Rft_variant variant_field -> + gen_rft_variant_field sc ~r_name ~rf_label variant_field + | Ot.Rft_optional optional_field -> + gen_rft_optional_field sc ~r_name ~rf_label optional_field + | Ot.Rft_required _ -> + Printf.eprintf + "Only proto3 syntax supported in pb_options encoding"; + exit 1 + | Ot.Rft_associative + (assoc_type, _, (key_type, _), (value_type, _)) -> + gen_rft_assoc_field sc ~r_name ~rf_label ~assoc_type ~key_type + ~value_type) + r_fields; + + (* Unknown fields are simply ignored *) + F.empty_line sc; + F.line sc "| (_, _) -> () (*Unknown fields are ignored*)"); + F.line sc ") assoc;"; + + (* Transform the mutable record in an immutable one *) + F.line sc "({"; + F.sub_scope sc (fun sc -> + List.iter + (fun { Ot.rf_label; _ } -> + F.linep sc "%s = v.%s;" rf_label rf_label) + r_fields); + F.linep sc "} : %s)" r_name) + +(* Generate decode function for an empty record *) +let gen_unit ?and_ { Ot.er_name } sc = + F.line sc + @@ sp "%s decode_pb_options_%s d =" + (Pb_codegen_util.let_decl_of_and and_) + er_name; + F.line sc (sp "Pbrt_pb_options.unit d \"%s\" \"%s\"" er_name "empty record") + +(* Generate decode function for a variant type *) +let gen_variant ?and_ { Ot.v_name; v_constructors } sc = + (* helper function for each constructor case *) + let process_v_constructor sc { Ot.vc_constructor; vc_field_type; _ } = + let pb_options_label = + Pb_codegen_util.camel_case_of_constructor vc_constructor + in + + match vc_field_type with + | Ot.Vct_nullary -> + F.linep sc "| (\"%s\", _)::_-> (%s : %s)" pb_options_label vc_constructor + v_name + | Ot.Vct_non_nullary_constructor field_type -> + let match_, exp = + let r_name = v_name and rf_label = vc_constructor in + field_pattern_match ~r_name ~rf_label field_type + in + + F.linep sc "| (\"%s\", %s)::_ -> " pb_options_label match_; + F.linep sc " (%s (%s) : %s)" vc_constructor exp v_name + in + + F.linep sc "%s decode_pb_options_%s pb_options =" + (Pb_codegen_util.let_decl_of_and and_) + v_name; + + F.sub_scope sc (fun sc -> + (* even though a variant should be an object with a single field, + * it is possible other fields are present in the pb_options object. Therefore + * we still need a loop to iterate over the key/value, even if in 99.99% + * of the cases it will be a single iteration *) + F.line sc "let assoc = match pb_options with"; + F.line sc + " | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc"; + F.line sc " | _ -> assert(false)"; + (* TODO raise E *) + F.line sc "in"; + + F.line sc "let rec loop = function"; + F.sub_scope sc (fun sc -> + (* termination condition *) + F.linep sc "| [] -> Pbrt_pb_options.E.malformed_variant \"%s\"" v_name; + + List.iter (process_v_constructor sc) v_constructors; + + F.empty_line sc; + F.line sc "| _ :: tl -> loop tl"); + F.line sc "in"; + F.line sc "loop assoc") + +let gen_const_variant ?and_ { Ot.cv_name; cv_constructors } sc = + F.linep sc "%s decode_pb_options_%s pb_options =" + (Pb_codegen_util.let_decl_of_and and_) + cv_name; + + F.sub_scope sc (fun sc -> + F.line sc "match pb_options with"; + List.iter + (fun { Ot.cvc_name; cvc_string_value; _ } -> + F.linep sc + "| Ocaml_protoc_compiler_lib.Pb_option.Scalar_value \ + (Constant_literal \"%s\") -> (%s : %s)" + cvc_string_value cvc_name cv_name) + cv_constructors; + F.linep sc "| _ -> Pbrt_pb_options.E.malformed_variant \"%s\"" cv_name) + +let gen_struct ?and_ t sc = + let { Ot.spec; _ } = t in + let has_encoded = + match spec with + | Ot.Record r -> + gen_record ?and_ r sc; + true + | Ot.Variant v -> + gen_variant ?and_ v sc; + true + | Ot.Const_variant v -> + gen_const_variant ?and_ v sc; + true + | Ot.Unit u -> + gen_unit ?and_ u sc; + true + in + has_encoded + +let gen_sig ?and_ t sc = + let _ = and_ in + let { Ot.spec; _ } = t in + + let f type_name = + F.linep sc + "val decode_pb_options_%s : Ocaml_protoc_compiler_lib.Pb_option.value -> \ + %s" + type_name type_name; + F.linep sc + ("(** [decode_pb_options_%s decoder] decodes a " + ^^ "[%s] value from [decoder] *)") + type_name type_name + in + + match spec with + | Ot.Record { Ot.r_name; _ } -> + f r_name; + true + | Ot.Variant { Ot.v_name; _ } -> + f v_name; + true + | Ot.Const_variant { Ot.cv_name; _ } -> + f cv_name; + true + | Ot.Unit { Ot.er_name; _ } -> + f er_name; + true + +let ocamldoc_title = "Pb_option.set Decoding" +let requires_mutable_records = true + +let plugin : Pb_codegen_plugin.t = + let module P = struct + let gen_sig = gen_sig + let gen_struct = gen_struct + let ocamldoc_title = ocamldoc_title + let requires_mutable_records = requires_mutable_records + end in + (module P) diff --git a/src/compilerlib/pb_codegen_decode_pb_options.mli b/src/compilerlib/pb_codegen_decode_pb_options.mli new file mode 100644 index 00000000..6f01a688 --- /dev/null +++ b/src/compilerlib/pb_codegen_decode_pb_options.mli @@ -0,0 +1,5 @@ +(** Code generator to decode messages from protobuf message options *) + +include Pb_codegen_plugin.S + +val plugin : Pb_codegen_plugin.t diff --git a/src/ocaml-protoc/ocaml_protoc_cmdline.ml b/src/ocaml-protoc/ocaml_protoc_cmdline.ml index d33a0141..f665f04a 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 a1cc999b..e7d55a2f 100644 --- a/src/ocaml-protoc/ocaml_protoc_generation.ml +++ b/src/ocaml-protoc/ocaml_protoc_generation.ml @@ -60,6 +60,10 @@ let generate_code ocaml_types ~proto_file_options cmdline : unit = [ Pb_codegen_ocaml_type_dump.plugin ] else []); + (if !(cmdline.Cmdline.pb_options) then + [ Pb_codegen_decode_pb_options.plugin ] + else + []); (if !(cmdline.Cmdline.pp) then [ Pb_codegen_pp.plugin ] else diff --git a/src/runtime-pb-options/dune b/src/runtime-pb-options/dune new file mode 100644 index 00000000..f62703c0 --- /dev/null +++ b/src/runtime-pb-options/dune @@ -0,0 +1,6 @@ +(library + (name pbrt_pb_options) + (public_name ocaml-protoc.rt-pb-options) + (wrapped false) + (libraries + (re_export ocaml-protoc.compiler-lib))) diff --git a/src/runtime-pb-options/pbrt_pb_options.ml b/src/runtime-pb-options/pbrt_pb_options.ml new file mode 100644 index 00000000..2bdd18ff --- /dev/null +++ b/src/runtime-pb-options/pbrt_pb_options.ml @@ -0,0 +1,147 @@ +module E = struct + type error = + | Unexpected_option_type of string * string + | Malformed_variant of string + + exception Failure of error + + let unexpected_option_type record_name field_name = + raise (Failure (Unexpected_option_type (record_name, field_name))) + + let malformed_variant variant_name = + raise (Failure (Malformed_variant variant_name)) + + let string_of_error = function + | Unexpected_option_type (record_name, field_name) -> + Printf.sprintf "Unexpected option type (record name:%s, field_name:%s)" + record_name field_name + | Malformed_variant variant_name -> + Printf.sprintf "Malformed variant (variant name: %s)" variant_name + + let () = + Printexc.register_printer (fun exn -> + match exn with + | Failure e -> Some (string_of_error e) + | _ -> None) +end + +open Ocaml_protoc_compiler_lib + +let unescape_string str = + let buffer = Buffer.create (String.length str) in + let rec aux i = + if i < String.length str then ( + match str.[i] with + | '\\' -> + (match str.[i + 1] with + | 'a' -> + Buffer.add_char buffer '\007'; + aux (i + 2) + | 'b' -> + Buffer.add_char buffer '\b'; + aux (i + 2) + | 'f' -> + Buffer.add_char buffer '\012'; + aux (i + 2) + | 'n' -> + Buffer.add_char buffer '\n'; + aux (i + 2) + | 'r' -> + Buffer.add_char buffer '\r'; + aux (i + 2) + | 't' -> + Buffer.add_char buffer '\t'; + aux (i + 2) + | 'v' -> + Buffer.add_char buffer '\011'; + aux (i + 2) + | '?' -> + Buffer.add_char buffer '?'; + aux (i + 2) + | '\\' -> + Buffer.add_char buffer '\\'; + aux (i + 2) + | '\'' -> + Buffer.add_char buffer '\''; + aux (i + 2) + | '"' -> + Buffer.add_char buffer '"'; + aux (i + 2) + | 'x' -> + (* handle hexadecimal escape *) + let hex = String.sub str (i + 2) 2 in + Buffer.add_char buffer (Char.chr (int_of_string ("0x" ^ hex))); + aux (i + 4) + | 'u' -> + (* handle Unicode escape with 4 hex digits *) + let unicode = String.sub str (i + 2) 4 in + Buffer.add_char buffer (Char.chr (int_of_string ("0x" ^ unicode))); + aux (i + 6) + | 'U' -> + (* handle Unicode escape with 5 hex digits *) + let unicode = String.sub str (i + 2) 5 in + Buffer.add_char buffer (Char.chr (int_of_string ("0x" ^ unicode))); + aux (i + 7) + | c when c >= '0' && c <= '7' -> + (* handle octal escape *) + let end_idx = min (i + 4) (String.length str) in + let rec find_octal_end idx = + if idx < end_idx && str.[idx] >= '0' && str.[idx] <= '7' then + find_octal_end (idx + 1) + else + idx + in + let octal_end = find_octal_end (i + 2) in + let octal = String.sub str (i + 1) (octal_end - i - 1) in + Buffer.add_char buffer (Char.chr (int_of_string ("0o" ^ octal))); + aux octal_end + | c -> failwith (Printf.sprintf "Invalid escape sequence: \\%c" c)) + | c -> + Buffer.add_char buffer c; + aux (i + 1) + ) + in + aux 0; + Buffer.contents buffer + +let int32 v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> Int32.of_float v + | Pb_option.Scalar_value (Constant_int v) -> Int32.of_int v + | _ -> E.unexpected_option_type record_name field_name + +let float v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> v + | Pb_option.Scalar_value (Constant_int v) -> float_of_int v + | _ -> E.unexpected_option_type record_name field_name + +let int64 v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> Int64.of_float v + | Pb_option.Scalar_value (Constant_int v) -> Int64.of_int v + | _ -> E.unexpected_option_type record_name field_name + +let int v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_float v) -> int_of_float v + | Pb_option.Scalar_value (Constant_int v) -> v + | _ -> E.unexpected_option_type record_name field_name + +let string v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_string v) -> unescape_string v + | _ -> E.unexpected_option_type record_name field_name + +let bool v record_name field_name = + match v with + | Pb_option.Scalar_value (Constant_bool v) -> v + | _ -> E.unexpected_option_type record_name field_name + +let bytes v record_name field_name = + string v record_name field_name |> Bytes.of_string + +let unit v record_name field_name = + match v with + | Pb_option.Message_literal [] -> () + | _ -> E.unexpected_option_type record_name field_name diff --git a/src/runtime-pb-options/pbrt_pb_options.mli b/src/runtime-pb-options/pbrt_pb_options.mli new file mode 100644 index 00000000..062dff7a --- /dev/null +++ b/src/runtime-pb-options/pbrt_pb_options.mli @@ -0,0 +1,34 @@ +(** Protobuf JSON encoding runtime *) + +(** All exception which could be raised by the generated JSON encoder + and decode function *) +module E : sig + type error = + | Unexpected_option_type of string * string + | Malformed_variant of string + + exception Failure of error + (** Decoding/Encoding failure *) + + val unexpected_option_type : string -> string -> 'a + (** [unexpected_option_type record_name field_name] raises + [Failure (Unexpected_json_type (record_name, field_name))] *) + + val malformed_variant : string -> 'a + (** [malformed_variant variant_name] raise + [Failure (Malformed_variant variant_name)] *) +end + +open Ocaml_protoc_compiler_lib + +(** Helper module for the generated code for common + functionality *) + +val string : Pb_option.value -> string -> string -> string +val float : Pb_option.value -> string -> string -> float +val int32 : Pb_option.value -> string -> string -> int32 +val int64 : Pb_option.value -> string -> string -> int64 +val int : Pb_option.value -> string -> string -> int +val bool : Pb_option.value -> string -> string -> bool +val bytes : Pb_option.value -> string -> string -> bytes +val unit : Pb_option.value -> string -> string -> unit diff --git a/src/tests/expectation/dune b/src/tests/expectation/dune index 47a5edc8..75676633 100644 --- a/src/tests/expectation/dune +++ b/src/tests/expectation/dune @@ -19,6 +19,13 @@ (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) @@ -29,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/test_decode_pb_options.expected b/src/tests/expectation/test_decode_pb_options.expected new file mode 100644 index 00000000..47bbcfd3 --- /dev/null +++ b/src/tests/expectation/test_decode_pb_options.expected @@ -0,0 +1,87 @@ +====================== ====================== +[{ + "(validate.rules)": {"uint64": {"gt": 999}} + }] +===================== ====================== +======================= ======================= +{ message = None; + type_ = Some(Uint64({ const = None; lt = None; lte = None; gt = Some(999); gte = None; in_ = []; not_in = []; ignore_empty = None; })); +} +====================== ======================= + + +====================== ====================== +[{ + "(validate.rules)": {"string": {"email": true}} + }] +===================== ====================== +======================= ======================= +{ message = None; + type_ = + Some( + String( + { const = None; + len = None; + min_len = None; + max_len = None; + len_bytes = None; + min_bytes = None; + max_bytes = None; + pattern = None; + prefix = None; + suffix = None; + contains = None; + not_contains = None; + in_ = []; + not_in = []; + well_known = Some(Email(true)); + strict = Some(true); + ignore_empty = None; + })); +} +====================== ======================= + + +====================== ====================== +[{ + "(validate.rules)": {"string": {"pattern": "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + "max_bytes": 256}} + }] +===================== ====================== +======================= ======================= +{ message = None; + type_ = + Some( + String( + { const = None; + len = None; + min_len = None; + max_len = None; + len_bytes = None; + min_bytes = None; + max_bytes = Some(256); + pattern = Some("^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$"); + prefix = None; + suffix = None; + contains = None; + not_contains = None; + in_ = []; + not_in = []; + well_known = None; + strict = Some(true); + ignore_empty = None; + })); +} +====================== ======================= + + +====================== ====================== +[{ + "(validate.rules)": {"message": {"required": true}} + }] +===================== ====================== +======================= ======================= +{ message = Some({ skip = None; required = Some(true); }); type_ = None; } +====================== ======================= + + diff --git a/src/tests/expectation/test_decode_pb_options.ml b/src/tests/expectation/test_decode_pb_options.ml new file mode 100644 index 00000000..e36402b6 --- /dev/null +++ b/src/tests/expectation/test_decode_pb_options.ml @@ -0,0 +1,74 @@ +module E = Pb_exception +module Pt = Pb_parsing_parse_tree + +let process_field_options ppf field = + let options = + field.Pt.field_options |> Pb_typing_validation.compile_options + in + if options <> Pb_option.empty then ( + let parsed = + Pb_option.get_ext options "validate.rules" + |> Option.map Validate.decode_pb_options_field_rules + in + Format.fprintf ppf + "====================== \ + ======================@.%a@.===================== \ + ======================@.======================= \ + =======================@.%a@.====================== \ + =======================@.@.@." + Pb_option.pp_set options + (Format.pp_print_option Validate.pp_field_rules) + parsed; + () + ) + +let run proto = + let protos = + Pb_parsing.parse_file + (fun f -> + match f with + | "test.proto" -> f, proto + | _ -> f, "") + "test.proto" + in + let ppf = Format.std_formatter in + Format.set_margin 150; + protos + |> List.iter (fun proto -> + proto.Pt.messages + |> List.iter (fun message -> + message.Pt.message_body + |> List.iter (function + | Pt.Message_field field -> process_field_options ppf field + | _ -> ()))) + +let test_cases = + [ + {| + syntax = "proto3"; + + package examplepb; + + import "validate/validate.proto"; + + message Person { + uint64 id = 1 [(validate.rules).uint64.gt = 999]; + + string email = 2 [(validate.rules).string.email = true]; + + string name = 3 [(validate.rules).string = { + pattern: "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", + max_bytes: 256, + }]; + + Location home = 4 [(validate.rules).message.required = true]; + + message Location { + double lat = 1 [(validate.rules).double = {gte: -90, lte: 90}]; + double lng = 2 [(validate.rules).double = {gte: -180, lte: 180}]; + } + } + |}; + ] + +let () = List.iter run test_cases diff --git a/src/tests/expectation/validate.ml.expected b/src/tests/expectation/validate.ml.expected new file mode 100644 index 00000000..70e3fb0d --- /dev/null +++ b/src/tests/expectation/validate.ml.expected @@ -0,0 +1,2480 @@ +[@@@ocaml.warning "-27-30-39-44"] + +type message_options = { + disabled : bool option; + ignored : bool option; +} + +type oneof_options = { + required : bool option; +} + +type message_rules = { + skip : bool option; + required : bool option; +} + +type float_rules = { + const : float option; + lt : float option; + lte : float option; + gt : float option; + gte : float option; + in_ : float list; + not_in : float list; + ignore_empty : bool option; +} + +type double_rules = { + const : float option; + lt : float option; + lte : float option; + gt : float option; + gte : float option; + in_ : float list; + not_in : float list; + ignore_empty : bool option; +} + +type int32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type int64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type uint32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type uint64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type sint32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type sint64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type fixed32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type fixed64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type sfixed32_rules = { + const : int32 option; + lt : int32 option; + lte : int32 option; + gt : int32 option; + gte : int32 option; + in_ : int32 list; + not_in : int32 list; + ignore_empty : bool option; +} + +type sfixed64_rules = { + const : int64 option; + lt : int64 option; + lte : int64 option; + gt : int64 option; + gte : int64 option; + in_ : int64 list; + not_in : int64 list; + ignore_empty : bool option; +} + +type bool_rules = { + const : bool option; +} + +type known_regex = + | Unknown + | Http_header_name + | Http_header_value + +type string_rules_well_known = + | Email of bool + | Hostname of bool + | Ip of bool + | Ipv4 of bool + | Ipv6 of bool + | Uri of bool + | Uri_ref of bool + | Address of bool + | Uuid of bool + | Well_known_regex of known_regex + +and string_rules = { + const : string option; + len : int64 option; + min_len : int64 option; + max_len : int64 option; + len_bytes : int64 option; + min_bytes : int64 option; + max_bytes : int64 option; + pattern : string option; + prefix : string option; + suffix : string option; + contains : string option; + not_contains : string option; + in_ : string list; + not_in : string list; + well_known : string_rules_well_known option; + strict : bool option; + ignore_empty : bool option; +} + +type bytes_rules_well_known = + | Ip of bool + | Ipv4 of bool + | Ipv6 of bool + +and bytes_rules = { + const : bytes option; + len : int64 option; + min_len : int64 option; + max_len : int64 option; + pattern : string option; + prefix : bytes option; + suffix : bytes option; + contains : bytes option; + in_ : bytes list; + not_in : bytes list; + well_known : bytes_rules_well_known option; + ignore_empty : bool option; +} + +type enum_rules = { + const : int32 option; + defined_only : bool option; + in_ : int32 list; + not_in : int32 list; +} + +type any_rules = { + required : bool option; + in_ : string list; + not_in : string list; +} + +type field_rules_type = + | Float of float_rules + | Double of double_rules + | Int32 of int32_rules + | Int64 of int64_rules + | Uint32 of uint32_rules + | Uint64 of uint64_rules + | Sint32 of sint32_rules + | Sint64 of sint64_rules + | Fixed32 of fixed32_rules + | Fixed64 of fixed64_rules + | Sfixed32 of sfixed32_rules + | Sfixed64 of sfixed64_rules + | Bool of bool_rules + | String of string_rules + | Bytes of bytes_rules + | Enum of enum_rules + | Repeated of repeated_rules + | Map of map_rules + | Any of any_rules + +and field_rules = { + message : message_rules option; + type_ : field_rules_type option; +} + +and repeated_rules = { + min_items : int64 option; + max_items : int64 option; + unique : bool option; + items : field_rules option; + ignore_empty : bool option; +} + +and map_rules = { + min_pairs : int64 option; + max_pairs : int64 option; + no_sparse : bool option; + keys : field_rules option; + values : field_rules option; + ignore_empty : bool option; +} + +type field_options = { + rules : field_rules option; +} + +let rec default_message_options + ?disabled:((disabled:bool option) = None) + ?ignored:((ignored:bool option) = None) + () : message_options = { + disabled; + ignored; +} + +let rec default_oneof_options + ?required:((required:bool option) = None) + () : oneof_options = { + required; +} + +let rec default_message_rules + ?skip:((skip:bool option) = None) + ?required:((required:bool option) = None) + () : message_rules = { + skip; + required; +} + +let rec default_float_rules + ?const:((const:float option) = None) + ?lt:((lt:float option) = None) + ?lte:((lte:float option) = None) + ?gt:((gt:float option) = None) + ?gte:((gte:float option) = None) + ?in_:((in_:float list) = []) + ?not_in:((not_in:float list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : float_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_double_rules + ?const:((const:float option) = None) + ?lt:((lt:float option) = None) + ?lte:((lte:float option) = None) + ?gt:((gt:float option) = None) + ?gte:((gte:float option) = None) + ?in_:((in_:float list) = []) + ?not_in:((not_in:float list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : double_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_int32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : int32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_int64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : int64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_uint32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : uint32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_uint64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : uint64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sint32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sint32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sint64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sint64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_fixed32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : fixed32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_fixed64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : fixed64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sfixed32_rules + ?const:((const:int32 option) = None) + ?lt:((lt:int32 option) = None) + ?lte:((lte:int32 option) = None) + ?gt:((gt:int32 option) = None) + ?gte:((gte:int32 option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sfixed32_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_sfixed64_rules + ?const:((const:int64 option) = None) + ?lt:((lt:int64 option) = None) + ?lte:((lte:int64 option) = None) + ?gt:((gt:int64 option) = None) + ?gte:((gte:int64 option) = None) + ?in_:((in_:int64 list) = []) + ?not_in:((not_in:int64 list) = []) + ?ignore_empty:((ignore_empty:bool option) = None) + () : sfixed64_rules = { + const; + lt; + lte; + gt; + gte; + in_; + not_in; + ignore_empty; +} + +let rec default_bool_rules + ?const:((const:bool option) = None) + () : bool_rules = { + const; +} + +let rec default_known_regex () = (Unknown:known_regex) + +let rec default_string_rules_well_known () : string_rules_well_known = Email (false) + +and default_string_rules + ?const:((const:string option) = None) + ?len:((len:int64 option) = None) + ?min_len:((min_len:int64 option) = None) + ?max_len:((max_len:int64 option) = None) + ?len_bytes:((len_bytes:int64 option) = None) + ?min_bytes:((min_bytes:int64 option) = None) + ?max_bytes:((max_bytes:int64 option) = None) + ?pattern:((pattern:string option) = None) + ?prefix:((prefix:string option) = None) + ?suffix:((suffix:string option) = None) + ?contains:((contains:string option) = None) + ?not_contains:((not_contains:string option) = None) + ?in_:((in_:string list) = []) + ?not_in:((not_in:string list) = []) + ?well_known:((well_known:string_rules_well_known option) = None) + ?strict:((strict:bool option) = Some (true)) + ?ignore_empty:((ignore_empty:bool option) = None) + () : string_rules = { + const; + len; + min_len; + max_len; + len_bytes; + min_bytes; + max_bytes; + pattern; + prefix; + suffix; + contains; + not_contains; + in_; + not_in; + well_known; + strict; + ignore_empty; +} + +let rec default_bytes_rules_well_known () : bytes_rules_well_known = Ip (false) + +and default_bytes_rules + ?const:((const:bytes option) = None) + ?len:((len:int64 option) = None) + ?min_len:((min_len:int64 option) = None) + ?max_len:((max_len:int64 option) = None) + ?pattern:((pattern:string option) = None) + ?prefix:((prefix:bytes option) = None) + ?suffix:((suffix:bytes option) = None) + ?contains:((contains:bytes option) = None) + ?in_:((in_:bytes list) = []) + ?not_in:((not_in:bytes list) = []) + ?well_known:((well_known:bytes_rules_well_known option) = None) + ?ignore_empty:((ignore_empty:bool option) = None) + () : bytes_rules = { + const; + len; + min_len; + max_len; + pattern; + prefix; + suffix; + contains; + in_; + not_in; + well_known; + ignore_empty; +} + +let rec default_enum_rules + ?const:((const:int32 option) = None) + ?defined_only:((defined_only:bool option) = None) + ?in_:((in_:int32 list) = []) + ?not_in:((not_in:int32 list) = []) + () : enum_rules = { + const; + defined_only; + in_; + not_in; +} + +let rec default_any_rules + ?required:((required:bool option) = None) + ?in_:((in_:string list) = []) + ?not_in:((not_in:string list) = []) + () : any_rules = { + required; + in_; + not_in; +} + +let rec default_field_rules_type () : field_rules_type = Float (default_float_rules ()) + +and default_field_rules + ?message:((message:message_rules option) = None) + ?type_:((type_:field_rules_type option) = None) + () : field_rules = { + message; + type_; +} + +and default_repeated_rules + ?min_items:((min_items:int64 option) = None) + ?max_items:((max_items:int64 option) = None) + ?unique:((unique:bool option) = None) + ?items:((items:field_rules option) = None) + ?ignore_empty:((ignore_empty:bool option) = None) + () : repeated_rules = { + min_items; + max_items; + unique; + items; + ignore_empty; +} + +and default_map_rules + ?min_pairs:((min_pairs:int64 option) = None) + ?max_pairs:((max_pairs:int64 option) = None) + ?no_sparse:((no_sparse:bool option) = None) + ?keys:((keys:field_rules option) = None) + ?values:((values:field_rules option) = None) + ?ignore_empty:((ignore_empty:bool option) = None) + () : map_rules = { + min_pairs; + max_pairs; + no_sparse; + keys; + values; + ignore_empty; +} + +let rec default_field_options + ?rules:((rules:field_rules option) = None) + () : field_options = { + rules; +} + +type message_options_mutable = { + mutable disabled : bool option; + mutable ignored : bool option; +} + +let default_message_options_mutable () : message_options_mutable = { + disabled = None; + ignored = None; +} + +type oneof_options_mutable = { + mutable required : bool option; +} + +let default_oneof_options_mutable () : oneof_options_mutable = { + required = None; +} + +type message_rules_mutable = { + mutable skip : bool option; + mutable required : bool option; +} + +let default_message_rules_mutable () : message_rules_mutable = { + skip = None; + required = None; +} + +type float_rules_mutable = { + mutable const : float option; + mutable lt : float option; + mutable lte : float option; + mutable gt : float option; + mutable gte : float option; + mutable in_ : float list; + mutable not_in : float list; + mutable ignore_empty : bool option; +} + +let default_float_rules_mutable () : float_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type double_rules_mutable = { + mutable const : float option; + mutable lt : float option; + mutable lte : float option; + mutable gt : float option; + mutable gte : float option; + mutable in_ : float list; + mutable not_in : float list; + mutable ignore_empty : bool option; +} + +let default_double_rules_mutable () : double_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type int32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_int32_rules_mutable () : int32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type int64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_int64_rules_mutable () : int64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type uint32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_uint32_rules_mutable () : uint32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type uint64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_uint64_rules_mutable () : uint64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sint32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_sint32_rules_mutable () : sint32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sint64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_sint64_rules_mutable () : sint64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type fixed32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_fixed32_rules_mutable () : fixed32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type fixed64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_fixed64_rules_mutable () : fixed64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sfixed32_rules_mutable = { + mutable const : int32 option; + mutable lt : int32 option; + mutable lte : int32 option; + mutable gt : int32 option; + mutable gte : int32 option; + mutable in_ : int32 list; + mutable not_in : int32 list; + mutable ignore_empty : bool option; +} + +let default_sfixed32_rules_mutable () : sfixed32_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type sfixed64_rules_mutable = { + mutable const : int64 option; + mutable lt : int64 option; + mutable lte : int64 option; + mutable gt : int64 option; + mutable gte : int64 option; + mutable in_ : int64 list; + mutable not_in : int64 list; + mutable ignore_empty : bool option; +} + +let default_sfixed64_rules_mutable () : sfixed64_rules_mutable = { + const = None; + lt = None; + lte = None; + gt = None; + gte = None; + in_ = []; + not_in = []; + ignore_empty = None; +} + +type bool_rules_mutable = { + mutable const : bool option; +} + +let default_bool_rules_mutable () : bool_rules_mutable = { + const = None; +} + +type string_rules_mutable = { + mutable const : string option; + mutable len : int64 option; + mutable min_len : int64 option; + mutable max_len : int64 option; + mutable len_bytes : int64 option; + mutable min_bytes : int64 option; + mutable max_bytes : int64 option; + mutable pattern : string option; + mutable prefix : string option; + mutable suffix : string option; + mutable contains : string option; + mutable not_contains : string option; + mutable in_ : string list; + mutable not_in : string list; + mutable well_known : string_rules_well_known option; + mutable strict : bool option; + mutable ignore_empty : bool option; +} + +let default_string_rules_mutable () : string_rules_mutable = { + const = None; + len = None; + min_len = None; + max_len = None; + len_bytes = None; + min_bytes = None; + max_bytes = None; + pattern = None; + prefix = None; + suffix = None; + contains = None; + not_contains = None; + in_ = []; + not_in = []; + well_known = None; + strict = Some (true); + ignore_empty = None; +} + +type bytes_rules_mutable = { + mutable const : bytes option; + mutable len : int64 option; + mutable min_len : int64 option; + mutable max_len : int64 option; + mutable pattern : string option; + mutable prefix : bytes option; + mutable suffix : bytes option; + mutable contains : bytes option; + mutable in_ : bytes list; + mutable not_in : bytes list; + mutable well_known : bytes_rules_well_known option; + mutable ignore_empty : bool option; +} + +let default_bytes_rules_mutable () : bytes_rules_mutable = { + const = None; + len = None; + min_len = None; + max_len = None; + pattern = None; + prefix = None; + suffix = None; + contains = None; + in_ = []; + not_in = []; + well_known = None; + ignore_empty = None; +} + +type enum_rules_mutable = { + mutable const : int32 option; + mutable defined_only : bool option; + mutable in_ : int32 list; + mutable not_in : int32 list; +} + +let default_enum_rules_mutable () : enum_rules_mutable = { + const = None; + defined_only = None; + in_ = []; + not_in = []; +} + +type any_rules_mutable = { + mutable required : bool option; + mutable in_ : string list; + mutable not_in : string list; +} + +let default_any_rules_mutable () : any_rules_mutable = { + required = None; + in_ = []; + not_in = []; +} + +type field_rules_mutable = { + mutable message : message_rules option; + mutable type_ : field_rules_type option; +} + +let default_field_rules_mutable () : field_rules_mutable = { + message = None; + type_ = None; +} + +type repeated_rules_mutable = { + mutable min_items : int64 option; + mutable max_items : int64 option; + mutable unique : bool option; + mutable items : field_rules option; + mutable ignore_empty : bool option; +} + +let default_repeated_rules_mutable () : repeated_rules_mutable = { + min_items = None; + max_items = None; + unique = None; + items = None; + ignore_empty = None; +} + +type map_rules_mutable = { + mutable min_pairs : int64 option; + mutable max_pairs : int64 option; + mutable no_sparse : bool option; + mutable keys : field_rules option; + mutable values : field_rules option; + mutable ignore_empty : bool option; +} + +let default_map_rules_mutable () : map_rules_mutable = { + min_pairs = None; + max_pairs = None; + no_sparse = None; + keys = None; + values = None; + ignore_empty = None; +} + +type field_options_mutable = { + mutable rules : field_rules option; +} + +let default_field_options_mutable () : field_options_mutable = { + rules = None; +} + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Pb_option.set Decoding} *) + +let rec decode_pb_options_message_options d = + let v = default_message_options_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("disabled", pb_options_value) -> + v.disabled <- Some (Pbrt_pb_options.bool pb_options_value "message_options" "disabled") + | ("ignored", pb_options_value) -> + v.ignored <- Some (Pbrt_pb_options.bool pb_options_value "message_options" "ignored") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + disabled = v.disabled; + ignored = v.ignored; + } : message_options) + +let rec decode_pb_options_oneof_options d = + let v = default_oneof_options_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("required", pb_options_value) -> + v.required <- Some (Pbrt_pb_options.bool pb_options_value "oneof_options" "required") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + required = v.required; + } : oneof_options) + +let rec decode_pb_options_message_rules d = + let v = default_message_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("skip", pb_options_value) -> + v.skip <- Some (Pbrt_pb_options.bool pb_options_value "message_rules" "skip") + | ("required", pb_options_value) -> + v.required <- Some (Pbrt_pb_options.bool pb_options_value "message_rules" "required") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + skip = v.skip; + required = v.required; + } : message_rules) + +let rec decode_pb_options_float_rules d = + let v = default_float_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.float pb_options_value "float_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "float_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "float_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "float_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : float_rules) + +let rec decode_pb_options_double_rules d = + let v = default_double_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.float pb_options_value "double_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "double_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.float pb_options_value "double_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "double_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : double_rules) + +let rec decode_pb_options_int32_rules d = + let v = default_int32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "int32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "int32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "int32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "int32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : int32_rules) + +let rec decode_pb_options_int64_rules d = + let v = default_int64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "int64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "int64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "int64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "int64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : int64_rules) + +let rec decode_pb_options_uint32_rules d = + let v = default_uint32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "uint32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "uint32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "uint32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "uint32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : uint32_rules) + +let rec decode_pb_options_uint64_rules d = + let v = default_uint64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "uint64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "uint64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "uint64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "uint64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : uint64_rules) + +let rec decode_pb_options_sint32_rules d = + let v = default_sint32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "sint32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sint32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sint32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sint32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sint32_rules) + +let rec decode_pb_options_sint64_rules d = + let v = default_sint64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "sint64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sint64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sint64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sint64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sint64_rules) + +let rec decode_pb_options_fixed32_rules d = + let v = default_fixed32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "fixed32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "fixed32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : fixed32_rules) + +let rec decode_pb_options_fixed64_rules d = + let v = default_fixed64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "fixed64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "fixed64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : fixed64_rules) + +let rec decode_pb_options_sfixed32_rules d = + let v = default_sfixed32_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "sfixed32_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sfixed32_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sfixed32_rules) + +let rec decode_pb_options_sfixed64_rules d = + let v = default_sfixed64_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "const") + | ("lt", pb_options_value) -> + v.lt <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "lt") + | ("lte", pb_options_value) -> + v.lte <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "lte") + | ("gt", pb_options_value) -> + v.gt <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "gt") + | ("gte", pb_options_value) -> + v.gte <- Some (Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "gte") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int64 pb_options_value "sfixed64_rules" "not_in" + ) l; + end + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "sfixed64_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + lt = v.lt; + lte = v.lte; + gt = v.gt; + gte = v.gte; + in_ = v.in_; + not_in = v.not_in; + ignore_empty = v.ignore_empty; + } : sfixed64_rules) + +let rec decode_pb_options_bool_rules d = + let v = default_bool_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.bool pb_options_value "bool_rules" "const") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + } : bool_rules) + +let rec decode_pb_options_known_regex pb_options = + match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Scalar_value (Constant_literal "UNKNOWN") -> (Unknown : known_regex) + | Ocaml_protoc_compiler_lib.Pb_option.Scalar_value (Constant_literal "HTTP_HEADER_NAME") -> (Http_header_name : known_regex) + | Ocaml_protoc_compiler_lib.Pb_option.Scalar_value (Constant_literal "HTTP_HEADER_VALUE") -> (Http_header_value : known_regex) + | _ -> Pbrt_pb_options.E.malformed_variant "known_regex" + +let rec decode_pb_options_string_rules_well_known pb_options = + let assoc = match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_pb_options.E.malformed_variant "string_rules_well_known" + | ("email", pb_options_value)::_ -> + (Email (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Email") : string_rules_well_known) + | ("hostname", pb_options_value)::_ -> + (Hostname (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Hostname") : string_rules_well_known) + | ("ip", pb_options_value)::_ -> + (Ip (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Ip") : string_rules_well_known) + | ("ipv4", pb_options_value)::_ -> + (Ipv4 (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Ipv4") : string_rules_well_known) + | ("ipv6", pb_options_value)::_ -> + (Ipv6 (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Ipv6") : string_rules_well_known) + | ("uri", pb_options_value)::_ -> + (Uri (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Uri") : string_rules_well_known) + | ("uriRef", pb_options_value)::_ -> + (Uri_ref (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Uri_ref") : string_rules_well_known) + | ("address", pb_options_value)::_ -> + (Address (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Address") : string_rules_well_known) + | ("uuid", pb_options_value)::_ -> + (Uuid (Pbrt_pb_options.bool pb_options_value "string_rules_well_known" "Uuid") : string_rules_well_known) + | ("wellKnownRegex", pb_options_value)::_ -> + (Well_known_regex ((decode_pb_options_known_regex pb_options_value)) : string_rules_well_known) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_pb_options_string_rules d = + let v = default_string_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "const") + | ("len", pb_options_value) -> + v.len <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "len") + | ("min_len", pb_options_value) -> + v.min_len <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "min_len") + | ("max_len", pb_options_value) -> + v.max_len <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "max_len") + | ("len_bytes", pb_options_value) -> + v.len_bytes <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "len_bytes") + | ("min_bytes", pb_options_value) -> + v.min_bytes <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "min_bytes") + | ("max_bytes", pb_options_value) -> + v.max_bytes <- Some (Pbrt_pb_options.int64 pb_options_value "string_rules" "max_bytes") + | ("pattern", pb_options_value) -> + v.pattern <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "pattern") + | ("prefix", pb_options_value) -> + v.prefix <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "prefix") + | ("suffix", pb_options_value) -> + v.suffix <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "suffix") + | ("contains", pb_options_value) -> + v.contains <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "contains") + | ("not_contains", pb_options_value) -> + v.not_contains <- Some (Pbrt_pb_options.string pb_options_value "string_rules" "not_contains") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "string_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "string_rules" "not_in" + ) l; + end + | ("email", pb_options_value) -> + v.well_known <- Some (Email (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("hostname", pb_options_value) -> + v.well_known <- Some (Hostname (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("ip", pb_options_value) -> + v.well_known <- Some (Ip (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("ipv4", pb_options_value) -> + v.well_known <- Some (Ipv4 (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("ipv6", pb_options_value) -> + v.well_known <- Some (Ipv6 (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("uri", pb_options_value) -> + v.well_known <- Some (Uri (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("uriRef", pb_options_value) -> + v.well_known <- Some (Uri_ref (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("address", pb_options_value) -> + v.well_known <- Some (Address (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("uuid", pb_options_value) -> + v.well_known <- Some (Uuid (Pbrt_pb_options.bool pb_options_value "string_rules" "well_known")) + | ("wellKnownRegex", pb_options_value) -> + v.well_known <- Some (Well_known_regex ((decode_pb_options_known_regex pb_options_value))) + | ("strict", pb_options_value) -> + v.strict <- Some (Pbrt_pb_options.bool pb_options_value "string_rules" "strict") + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "string_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + len = v.len; + min_len = v.min_len; + max_len = v.max_len; + len_bytes = v.len_bytes; + min_bytes = v.min_bytes; + max_bytes = v.max_bytes; + pattern = v.pattern; + prefix = v.prefix; + suffix = v.suffix; + contains = v.contains; + not_contains = v.not_contains; + in_ = v.in_; + not_in = v.not_in; + well_known = v.well_known; + strict = v.strict; + ignore_empty = v.ignore_empty; + } : string_rules) + +let rec decode_pb_options_bytes_rules_well_known pb_options = + let assoc = match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_pb_options.E.malformed_variant "bytes_rules_well_known" + | ("ip", pb_options_value)::_ -> + (Ip (Pbrt_pb_options.bool pb_options_value "bytes_rules_well_known" "Ip") : bytes_rules_well_known) + | ("ipv4", pb_options_value)::_ -> + (Ipv4 (Pbrt_pb_options.bool pb_options_value "bytes_rules_well_known" "Ipv4") : bytes_rules_well_known) + | ("ipv6", pb_options_value)::_ -> + (Ipv6 (Pbrt_pb_options.bool pb_options_value "bytes_rules_well_known" "Ipv6") : bytes_rules_well_known) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_pb_options_bytes_rules d = + let v = default_bytes_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "const") + | ("len", pb_options_value) -> + v.len <- Some (Pbrt_pb_options.int64 pb_options_value "bytes_rules" "len") + | ("min_len", pb_options_value) -> + v.min_len <- Some (Pbrt_pb_options.int64 pb_options_value "bytes_rules" "min_len") + | ("max_len", pb_options_value) -> + v.max_len <- Some (Pbrt_pb_options.int64 pb_options_value "bytes_rules" "max_len") + | ("pattern", pb_options_value) -> + v.pattern <- Some (Pbrt_pb_options.string pb_options_value "bytes_rules" "pattern") + | ("prefix", pb_options_value) -> + v.prefix <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "prefix") + | ("suffix", pb_options_value) -> + v.suffix <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "suffix") + | ("contains", pb_options_value) -> + v.contains <- Some (Pbrt_pb_options.bytes pb_options_value "bytes_rules" "contains") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.bytes pb_options_value "bytes_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.bytes pb_options_value "bytes_rules" "not_in" + ) l; + end + | ("ip", pb_options_value) -> + v.well_known <- Some (Ip (Pbrt_pb_options.bool pb_options_value "bytes_rules" "well_known")) + | ("ipv4", pb_options_value) -> + v.well_known <- Some (Ipv4 (Pbrt_pb_options.bool pb_options_value "bytes_rules" "well_known")) + | ("ipv6", pb_options_value) -> + v.well_known <- Some (Ipv6 (Pbrt_pb_options.bool pb_options_value "bytes_rules" "well_known")) + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "bytes_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + len = v.len; + min_len = v.min_len; + max_len = v.max_len; + pattern = v.pattern; + prefix = v.prefix; + suffix = v.suffix; + contains = v.contains; + in_ = v.in_; + not_in = v.not_in; + well_known = v.well_known; + ignore_empty = v.ignore_empty; + } : bytes_rules) + +let rec decode_pb_options_enum_rules d = + let v = default_enum_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("const", pb_options_value) -> + v.const <- Some (Pbrt_pb_options.int32 pb_options_value "enum_rules" "const") + | ("defined_only", pb_options_value) -> + v.defined_only <- Some (Pbrt_pb_options.bool pb_options_value "enum_rules" "defined_only") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "enum_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.int32 pb_options_value "enum_rules" "not_in" + ) l; + end + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + const = v.const; + defined_only = v.defined_only; + in_ = v.in_; + not_in = v.not_in; + } : enum_rules) + +let rec decode_pb_options_any_rules d = + let v = default_any_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("required", pb_options_value) -> + v.required <- Some (Pbrt_pb_options.bool pb_options_value "any_rules" "required") + | ("in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.in_ <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "any_rules" "in_" + ) l; + end + | ("not_in", Ocaml_protoc_compiler_lib.Pb_option.List_literal l) -> begin + v.not_in <- List.map (function + | pb_options_value -> Pbrt_pb_options.string pb_options_value "any_rules" "not_in" + ) l; + end + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + required = v.required; + in_ = v.in_; + not_in = v.not_in; + } : any_rules) + +let rec decode_pb_options_field_rules_type pb_options = + let assoc = match pb_options with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + let rec loop = function + | [] -> Pbrt_pb_options.E.malformed_variant "field_rules_type" + | ("float", pb_options_value)::_ -> + (Float ((decode_pb_options_float_rules pb_options_value)) : field_rules_type) + | ("double", pb_options_value)::_ -> + (Double ((decode_pb_options_double_rules pb_options_value)) : field_rules_type) + | ("int32", pb_options_value)::_ -> + (Int32 ((decode_pb_options_int32_rules pb_options_value)) : field_rules_type) + | ("int64", pb_options_value)::_ -> + (Int64 ((decode_pb_options_int64_rules pb_options_value)) : field_rules_type) + | ("uint32", pb_options_value)::_ -> + (Uint32 ((decode_pb_options_uint32_rules pb_options_value)) : field_rules_type) + | ("uint64", pb_options_value)::_ -> + (Uint64 ((decode_pb_options_uint64_rules pb_options_value)) : field_rules_type) + | ("sint32", pb_options_value)::_ -> + (Sint32 ((decode_pb_options_sint32_rules pb_options_value)) : field_rules_type) + | ("sint64", pb_options_value)::_ -> + (Sint64 ((decode_pb_options_sint64_rules pb_options_value)) : field_rules_type) + | ("fixed32", pb_options_value)::_ -> + (Fixed32 ((decode_pb_options_fixed32_rules pb_options_value)) : field_rules_type) + | ("fixed64", pb_options_value)::_ -> + (Fixed64 ((decode_pb_options_fixed64_rules pb_options_value)) : field_rules_type) + | ("sfixed32", pb_options_value)::_ -> + (Sfixed32 ((decode_pb_options_sfixed32_rules pb_options_value)) : field_rules_type) + | ("sfixed64", pb_options_value)::_ -> + (Sfixed64 ((decode_pb_options_sfixed64_rules pb_options_value)) : field_rules_type) + | ("bool", pb_options_value)::_ -> + (Bool ((decode_pb_options_bool_rules pb_options_value)) : field_rules_type) + | ("string", pb_options_value)::_ -> + (String ((decode_pb_options_string_rules pb_options_value)) : field_rules_type) + | ("bytes", pb_options_value)::_ -> + (Bytes ((decode_pb_options_bytes_rules pb_options_value)) : field_rules_type) + | ("enum", pb_options_value)::_ -> + (Enum ((decode_pb_options_enum_rules pb_options_value)) : field_rules_type) + | ("repeated", pb_options_value)::_ -> + (Repeated ((decode_pb_options_repeated_rules pb_options_value)) : field_rules_type) + | ("map", pb_options_value)::_ -> + (Map ((decode_pb_options_map_rules pb_options_value)) : field_rules_type) + | ("any", pb_options_value)::_ -> + (Any ((decode_pb_options_any_rules pb_options_value)) : field_rules_type) + + | _ :: tl -> loop tl + in + loop assoc + +and decode_pb_options_field_rules d = + let v = default_field_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("message", pb_options_value) -> + v.message <- Some ((decode_pb_options_message_rules pb_options_value)) + | ("float", pb_options_value) -> + v.type_ <- Some (Float ((decode_pb_options_float_rules pb_options_value))) + | ("double", pb_options_value) -> + v.type_ <- Some (Double ((decode_pb_options_double_rules pb_options_value))) + | ("int32", pb_options_value) -> + v.type_ <- Some (Int32 ((decode_pb_options_int32_rules pb_options_value))) + | ("int64", pb_options_value) -> + v.type_ <- Some (Int64 ((decode_pb_options_int64_rules pb_options_value))) + | ("uint32", pb_options_value) -> + v.type_ <- Some (Uint32 ((decode_pb_options_uint32_rules pb_options_value))) + | ("uint64", pb_options_value) -> + v.type_ <- Some (Uint64 ((decode_pb_options_uint64_rules pb_options_value))) + | ("sint32", pb_options_value) -> + v.type_ <- Some (Sint32 ((decode_pb_options_sint32_rules pb_options_value))) + | ("sint64", pb_options_value) -> + v.type_ <- Some (Sint64 ((decode_pb_options_sint64_rules pb_options_value))) + | ("fixed32", pb_options_value) -> + v.type_ <- Some (Fixed32 ((decode_pb_options_fixed32_rules pb_options_value))) + | ("fixed64", pb_options_value) -> + v.type_ <- Some (Fixed64 ((decode_pb_options_fixed64_rules pb_options_value))) + | ("sfixed32", pb_options_value) -> + v.type_ <- Some (Sfixed32 ((decode_pb_options_sfixed32_rules pb_options_value))) + | ("sfixed64", pb_options_value) -> + v.type_ <- Some (Sfixed64 ((decode_pb_options_sfixed64_rules pb_options_value))) + | ("bool", pb_options_value) -> + v.type_ <- Some (Bool ((decode_pb_options_bool_rules pb_options_value))) + | ("string", pb_options_value) -> + v.type_ <- Some (String ((decode_pb_options_string_rules pb_options_value))) + | ("bytes", pb_options_value) -> + v.type_ <- Some (Bytes ((decode_pb_options_bytes_rules pb_options_value))) + | ("enum", pb_options_value) -> + v.type_ <- Some (Enum ((decode_pb_options_enum_rules pb_options_value))) + | ("repeated", pb_options_value) -> + v.type_ <- Some (Repeated ((decode_pb_options_repeated_rules pb_options_value))) + | ("map", pb_options_value) -> + v.type_ <- Some (Map ((decode_pb_options_map_rules pb_options_value))) + | ("any", pb_options_value) -> + v.type_ <- Some (Any ((decode_pb_options_any_rules pb_options_value))) + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + message = v.message; + type_ = v.type_; + } : field_rules) + +and decode_pb_options_repeated_rules d = + let v = default_repeated_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("min_items", pb_options_value) -> + v.min_items <- Some (Pbrt_pb_options.int64 pb_options_value "repeated_rules" "min_items") + | ("max_items", pb_options_value) -> + v.max_items <- Some (Pbrt_pb_options.int64 pb_options_value "repeated_rules" "max_items") + | ("unique", pb_options_value) -> + v.unique <- Some (Pbrt_pb_options.bool pb_options_value "repeated_rules" "unique") + | ("items", pb_options_value) -> + v.items <- Some ((decode_pb_options_field_rules pb_options_value)) + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "repeated_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + min_items = v.min_items; + max_items = v.max_items; + unique = v.unique; + items = v.items; + ignore_empty = v.ignore_empty; + } : repeated_rules) + +and decode_pb_options_map_rules d = + let v = default_map_rules_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("min_pairs", pb_options_value) -> + v.min_pairs <- Some (Pbrt_pb_options.int64 pb_options_value "map_rules" "min_pairs") + | ("max_pairs", pb_options_value) -> + v.max_pairs <- Some (Pbrt_pb_options.int64 pb_options_value "map_rules" "max_pairs") + | ("no_sparse", pb_options_value) -> + v.no_sparse <- Some (Pbrt_pb_options.bool pb_options_value "map_rules" "no_sparse") + | ("keys", pb_options_value) -> + v.keys <- Some ((decode_pb_options_field_rules pb_options_value)) + | ("values", pb_options_value) -> + v.values <- Some ((decode_pb_options_field_rules pb_options_value)) + | ("ignore_empty", pb_options_value) -> + v.ignore_empty <- Some (Pbrt_pb_options.bool pb_options_value "map_rules" "ignore_empty") + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + min_pairs = v.min_pairs; + max_pairs = v.max_pairs; + no_sparse = v.no_sparse; + keys = v.keys; + values = v.values; + ignore_empty = v.ignore_empty; + } : map_rules) + +let rec decode_pb_options_field_options d = + let v = default_field_options_mutable () in + let assoc = match d with + | Ocaml_protoc_compiler_lib.Pb_option.Message_literal assoc -> assoc + | _ -> assert(false) + in + List.iter (function + | ("rules", pb_options_value) -> + v.rules <- Some ((decode_pb_options_field_rules pb_options_value)) + + | (_, _) -> () (*Unknown fields are ignored*) + ) assoc; + ({ + rules = v.rules; + } : field_options) + +[@@@ocaml.warning "-27-30-39"] + +(** {2 Formatters} *) + +let rec pp_message_options fmt (v:message_options) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "disabled" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.disabled; + Pbrt.Pp.pp_record_field ~first:false "ignored" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignored; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_oneof_options fmt (v:oneof_options) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "required" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.required; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_message_rules fmt (v:message_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "skip" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.skip; + Pbrt.Pp.pp_record_field ~first:false "required" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.required; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_float_rules fmt (v:float_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_double_rules fmt (v:double_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_float) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_float) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_int32_rules fmt (v:int32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_int64_rules fmt (v:int64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_uint32_rules fmt (v:uint32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_uint64_rules fmt (v:uint64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sint32_rules fmt (v:sint32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sint64_rules fmt (v:sint64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_fixed32_rules fmt (v:fixed32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_fixed64_rules fmt (v:fixed64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sfixed32_rules fmt (v:sfixed32_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_sfixed64_rules fmt (v:sfixed64_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "lt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lt; + Pbrt.Pp.pp_record_field ~first:false "lte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.lte; + Pbrt.Pp.pp_record_field ~first:false "gt" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gt; + Pbrt.Pp.pp_record_field ~first:false "gte" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.gte; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int64) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_bool_rules fmt (v:bool_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.const; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_known_regex fmt (v:known_regex) = + match v with + | Unknown -> Format.fprintf fmt "Unknown" + | Http_header_name -> Format.fprintf fmt "Http_header_name" + | Http_header_value -> Format.fprintf fmt "Http_header_value" + +let rec pp_string_rules_well_known fmt (v:string_rules_well_known) = + match v with + | Email x -> Format.fprintf fmt "@[Email(@,%a)@]" Pbrt.Pp.pp_bool x + | Hostname x -> Format.fprintf fmt "@[Hostname(@,%a)@]" Pbrt.Pp.pp_bool x + | Ip x -> Format.fprintf fmt "@[Ip(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv4 x -> Format.fprintf fmt "@[Ipv4(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv6 x -> Format.fprintf fmt "@[Ipv6(@,%a)@]" Pbrt.Pp.pp_bool x + | Uri x -> Format.fprintf fmt "@[Uri(@,%a)@]" Pbrt.Pp.pp_bool x + | Uri_ref x -> Format.fprintf fmt "@[Uri_ref(@,%a)@]" Pbrt.Pp.pp_bool x + | Address x -> Format.fprintf fmt "@[Address(@,%a)@]" Pbrt.Pp.pp_bool x + | Uuid x -> Format.fprintf fmt "@[Uuid(@,%a)@]" Pbrt.Pp.pp_bool x + | Well_known_regex x -> Format.fprintf fmt "@[Well_known_regex(@,%a)@]" pp_known_regex x + +and pp_string_rules fmt (v:string_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.len; + Pbrt.Pp.pp_record_field ~first:false "min_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_len; + Pbrt.Pp.pp_record_field ~first:false "max_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_len; + Pbrt.Pp.pp_record_field ~first:false "len_bytes" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.len_bytes; + Pbrt.Pp.pp_record_field ~first:false "min_bytes" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_bytes; + Pbrt.Pp.pp_record_field ~first:false "max_bytes" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_bytes; + Pbrt.Pp.pp_record_field ~first:false "pattern" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.pattern; + Pbrt.Pp.pp_record_field ~first:false "prefix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.prefix; + Pbrt.Pp.pp_record_field ~first:false "suffix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.suffix; + Pbrt.Pp.pp_record_field ~first:false "contains" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.contains; + Pbrt.Pp.pp_record_field ~first:false "not_contains" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.not_contains; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "well_known" (Pbrt.Pp.pp_option pp_string_rules_well_known) fmt v.well_known; + Pbrt.Pp.pp_record_field ~first:false "strict" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.strict; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_bytes_rules_well_known fmt (v:bytes_rules_well_known) = + match v with + | Ip x -> Format.fprintf fmt "@[Ip(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv4 x -> Format.fprintf fmt "@[Ipv4(@,%a)@]" Pbrt.Pp.pp_bool x + | Ipv6 x -> Format.fprintf fmt "@[Ipv6(@,%a)@]" Pbrt.Pp.pp_bool x + +and pp_bytes_rules fmt (v:bytes_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.len; + Pbrt.Pp.pp_record_field ~first:false "min_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_len; + Pbrt.Pp.pp_record_field ~first:false "max_len" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_len; + Pbrt.Pp.pp_record_field ~first:false "pattern" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.pattern; + Pbrt.Pp.pp_record_field ~first:false "prefix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.prefix; + Pbrt.Pp.pp_record_field ~first:false "suffix" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.suffix; + Pbrt.Pp.pp_record_field ~first:false "contains" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bytes) fmt v.contains; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_bytes) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_bytes) fmt v.not_in; + Pbrt.Pp.pp_record_field ~first:false "well_known" (Pbrt.Pp.pp_option pp_bytes_rules_well_known) fmt v.well_known; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_enum_rules fmt (v:enum_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "const" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.const; + Pbrt.Pp.pp_record_field ~first:false "defined_only" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.defined_only; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_int32) fmt v.not_in; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_any_rules fmt (v:any_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "required" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.required; + Pbrt.Pp.pp_record_field ~first:false "in_" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.in_; + Pbrt.Pp.pp_record_field ~first:false "not_in" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.not_in; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_field_rules_type fmt (v:field_rules_type) = + match v with + | Float x -> Format.fprintf fmt "@[Float(@,%a)@]" pp_float_rules x + | Double x -> Format.fprintf fmt "@[Double(@,%a)@]" pp_double_rules x + | Int32 x -> Format.fprintf fmt "@[Int32(@,%a)@]" pp_int32_rules x + | Int64 x -> Format.fprintf fmt "@[Int64(@,%a)@]" pp_int64_rules x + | Uint32 x -> Format.fprintf fmt "@[Uint32(@,%a)@]" pp_uint32_rules x + | Uint64 x -> Format.fprintf fmt "@[Uint64(@,%a)@]" pp_uint64_rules x + | Sint32 x -> Format.fprintf fmt "@[Sint32(@,%a)@]" pp_sint32_rules x + | Sint64 x -> Format.fprintf fmt "@[Sint64(@,%a)@]" pp_sint64_rules x + | Fixed32 x -> Format.fprintf fmt "@[Fixed32(@,%a)@]" pp_fixed32_rules x + | Fixed64 x -> Format.fprintf fmt "@[Fixed64(@,%a)@]" pp_fixed64_rules x + | Sfixed32 x -> Format.fprintf fmt "@[Sfixed32(@,%a)@]" pp_sfixed32_rules x + | Sfixed64 x -> Format.fprintf fmt "@[Sfixed64(@,%a)@]" pp_sfixed64_rules x + | Bool x -> Format.fprintf fmt "@[Bool(@,%a)@]" pp_bool_rules x + | String x -> Format.fprintf fmt "@[String(@,%a)@]" pp_string_rules x + | Bytes x -> Format.fprintf fmt "@[Bytes(@,%a)@]" pp_bytes_rules x + | Enum x -> Format.fprintf fmt "@[Enum(@,%a)@]" pp_enum_rules x + | Repeated x -> Format.fprintf fmt "@[Repeated(@,%a)@]" pp_repeated_rules x + | Map x -> Format.fprintf fmt "@[Map(@,%a)@]" pp_map_rules x + | Any x -> Format.fprintf fmt "@[Any(@,%a)@]" pp_any_rules x + +and pp_field_rules fmt (v:field_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "message" (Pbrt.Pp.pp_option pp_message_rules) fmt v.message; + Pbrt.Pp.pp_record_field ~first:false "type_" (Pbrt.Pp.pp_option pp_field_rules_type) fmt v.type_; + in + Pbrt.Pp.pp_brk pp_i fmt () + +and pp_repeated_rules fmt (v:repeated_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "min_items" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_items; + Pbrt.Pp.pp_record_field ~first:false "max_items" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_items; + Pbrt.Pp.pp_record_field ~first:false "unique" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.unique; + Pbrt.Pp.pp_record_field ~first:false "items" (Pbrt.Pp.pp_option pp_field_rules) fmt v.items; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +and pp_map_rules fmt (v:map_rules) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "min_pairs" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.min_pairs; + Pbrt.Pp.pp_record_field ~first:false "max_pairs" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int64) fmt v.max_pairs; + Pbrt.Pp.pp_record_field ~first:false "no_sparse" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.no_sparse; + Pbrt.Pp.pp_record_field ~first:false "keys" (Pbrt.Pp.pp_option pp_field_rules) fmt v.keys; + Pbrt.Pp.pp_record_field ~first:false "values" (Pbrt.Pp.pp_option pp_field_rules) fmt v.values; + Pbrt.Pp.pp_record_field ~first:false "ignore_empty" (Pbrt.Pp.pp_option Pbrt.Pp.pp_bool) fmt v.ignore_empty; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_field_options fmt (v:field_options) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "rules" (Pbrt.Pp.pp_option pp_field_rules) fmt v.rules; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/tests/expectation/validate.proto b/src/tests/expectation/validate.proto new file mode 100644 index 00000000..cb0ada05 --- /dev/null +++ b/src/tests/expectation/validate.proto @@ -0,0 +1,883 @@ +// Copyright 2024 protoc-gen-validate contributors +// Origin: https://github.com/bufbuild/protoc-gen-validate/blob/main/validate/validate.proto + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// NOTE: this file was modified a bit from the upstream version, extends were +// replaced with actual messages, google protobuf imports commented out, +// Duration and Timestamp rules were commented out for now. + + +syntax = "proto2"; +package validate; + +option go_package = "github.com/envoyproxy/protoc-gen-validate/validate"; +option java_package = "io.envoyproxy.pgv.validate"; + +// import "google/protobuf/descriptor.proto"; +// import "google/protobuf/duration.proto"; +// import "google/protobuf/timestamp.proto"; + +// Validation rules applied at the message level +message MessageOptions { + // Disabled nullifies any validation rules for this message, including any + // message fields associated with it that do support validation. + optional bool disabled = 1071; + // Ignore skips generation of validation methods for this message. + optional bool ignored = 1072; +} + +// Validation rules applied at the oneof level +message OneofOptions { + // Required ensures that exactly one the field options in a oneof is set; + // validation fails if no fields in the oneof are set. + optional bool required = 1071; +} + +// Validation rules applied at the field level +message FieldOptions { + // Rules specify the validations to be performed on this field. By default, + // no validation is performed against a field. + optional FieldRules rules = 1071; +} + +// FieldRules encapsulates the rules for each type of field. Depending on the +// field, the correct set should be used to ensure proper validations. +message FieldRules { + optional MessageRules message = 17; + oneof type { + // Scalar Field Types + FloatRules float = 1; + DoubleRules double = 2; + Int32Rules int32 = 3; + Int64Rules int64 = 4; + UInt32Rules uint32 = 5; + UInt64Rules uint64 = 6; + SInt32Rules sint32 = 7; + SInt64Rules sint64 = 8; + Fixed32Rules fixed32 = 9; + Fixed64Rules fixed64 = 10; + SFixed32Rules sfixed32 = 11; + SFixed64Rules sfixed64 = 12; + BoolRules bool = 13; + StringRules string = 14; + BytesRules bytes = 15; + + // Complex Field Types + EnumRules enum = 16; + RepeatedRules repeated = 18; + MapRules map = 19; + + // Well-Known Field Types + AnyRules any = 20; + //DurationRules duration = 21; + //TimestampRules timestamp = 22; + } +} + +// FloatRules describes the constraints applied to `float` values +message FloatRules { + // Const specifies that this field must be exactly the specified value + optional float const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional float lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional float lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional float gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional float gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated float in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated float not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// DoubleRules describes the constraints applied to `double` values +message DoubleRules { + // Const specifies that this field must be exactly the specified value + optional double const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional double lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional double lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional double gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional double gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated double in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated double not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Int32Rules describes the constraints applied to `int32` values +message Int32Rules { + // Const specifies that this field must be exactly the specified value + optional int32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional int32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional int32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional int32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional int32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated int32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Int64Rules describes the constraints applied to `int64` values +message Int64Rules { + // Const specifies that this field must be exactly the specified value + optional int64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional int64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional int64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional int64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional int64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated int64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// UInt32Rules describes the constraints applied to `uint32` values +message UInt32Rules { + // Const specifies that this field must be exactly the specified value + optional uint32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional uint32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional uint32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional uint32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional uint32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated uint32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated uint32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// UInt64Rules describes the constraints applied to `uint64` values +message UInt64Rules { + // Const specifies that this field must be exactly the specified value + optional uint64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional uint64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional uint64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional uint64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional uint64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated uint64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated uint64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SInt32Rules describes the constraints applied to `sint32` values +message SInt32Rules { + // Const specifies that this field must be exactly the specified value + optional sint32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sint32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sint32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sint32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sint32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sint32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sint32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SInt64Rules describes the constraints applied to `sint64` values +message SInt64Rules { + // Const specifies that this field must be exactly the specified value + optional sint64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sint64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sint64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sint64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sint64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sint64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sint64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Fixed32Rules describes the constraints applied to `fixed32` values +message Fixed32Rules { + // Const specifies that this field must be exactly the specified value + optional fixed32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional fixed32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional fixed32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional fixed32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional fixed32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated fixed32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated fixed32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Fixed64Rules describes the constraints applied to `fixed64` values +message Fixed64Rules { + // Const specifies that this field must be exactly the specified value + optional fixed64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional fixed64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional fixed64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional fixed64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional fixed64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated fixed64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated fixed64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SFixed32Rules describes the constraints applied to `sfixed32` values +message SFixed32Rules { + // Const specifies that this field must be exactly the specified value + optional sfixed32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sfixed32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sfixed32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sfixed32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sfixed32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sfixed32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sfixed32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SFixed64Rules describes the constraints applied to `sfixed64` values +message SFixed64Rules { + // Const specifies that this field must be exactly the specified value + optional sfixed64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sfixed64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sfixed64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sfixed64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sfixed64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sfixed64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sfixed64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// BoolRules describes the constraints applied to `bool` values +message BoolRules { + // Const specifies that this field must be exactly the specified value + optional bool const = 1; +} + +// StringRules describe the constraints applied to `string` values +message StringRules { + // Const specifies that this field must be exactly the specified value + optional string const = 1; + + // Len specifies that this field must be the specified number of + // characters (Unicode code points). Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 len = 19; + + // MinLen specifies that this field must be the specified number of + // characters (Unicode code points) at a minimum. Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 min_len = 2; + + // MaxLen specifies that this field must be the specified number of + // characters (Unicode code points) at a maximum. Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 max_len = 3; + + // LenBytes specifies that this field must be the specified number of bytes + optional uint64 len_bytes = 20; + + // MinBytes specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 min_bytes = 4; + + // MaxBytes specifies that this field must be the specified number of bytes + // at a maximum + optional uint64 max_bytes = 5; + + // Pattern specifies that this field must match against the specified + // regular expression (RE2 syntax). The included expression should elide + // any delimiters. + optional string pattern = 6; + + // Prefix specifies that this field must have the specified substring at + // the beginning of the string. + optional string prefix = 7; + + // Suffix specifies that this field must have the specified substring at + // the end of the string. + optional string suffix = 8; + + // Contains specifies that this field must have the specified substring + // anywhere in the string. + optional string contains = 9; + + // NotContains specifies that this field cannot have the specified substring + // anywhere in the string. + optional string not_contains = 23; + + // In specifies that this field must be equal to one of the specified + // values + repeated string in = 10; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated string not_in = 11; + + // WellKnown rules provide advanced constraints against common string + // patterns + oneof well_known { + // Email specifies that the field must be a valid email address as + // defined by RFC 5322 + bool email = 12; + + // Hostname specifies that the field must be a valid hostname as + // defined by RFC 1034. This constraint does not support + // internationalized domain names (IDNs). + bool hostname = 13; + + // Ip specifies that the field must be a valid IP (v4 or v6) address. + // Valid IPv6 addresses should not include surrounding square brackets. + bool ip = 14; + + // Ipv4 specifies that the field must be a valid IPv4 address. + bool ipv4 = 15; + + // Ipv6 specifies that the field must be a valid IPv6 address. Valid + // IPv6 addresses should not include surrounding square brackets. + bool ipv6 = 16; + + // Uri specifies that the field must be a valid, absolute URI as defined + // by RFC 3986 + bool uri = 17; + + // UriRef specifies that the field must be a valid URI as defined by RFC + // 3986 and may be relative or absolute. + bool uri_ref = 18; + + // Address specifies that the field must be either a valid hostname as + // defined by RFC 1034 (which does not support internationalized domain + // names or IDNs), or it can be a valid IP (v4 or v6). + bool address = 21; + + // Uuid specifies that the field must be a valid UUID as defined by + // RFC 4122 + bool uuid = 22; + + // WellKnownRegex specifies a common well known pattern defined as a regex. + KnownRegex well_known_regex = 24; + } + + // This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable + // strict header validation. + // By default, this is true, and HTTP header validations are RFC-compliant. + // Setting to false will enable a looser validations that only disallows + // \r\n\0 characters, which can be used to bypass header matching rules. + optional bool strict = 25 [default = true]; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 26; +} + +// WellKnownRegex contain some well-known patterns. +enum KnownRegex { + UNKNOWN = 0; + + // HTTP header name as defined by RFC 7230. + HTTP_HEADER_NAME = 1; + + // HTTP header value as defined by RFC 7230. + HTTP_HEADER_VALUE = 2; +} + +// BytesRules describe the constraints applied to `bytes` values +message BytesRules { + // Const specifies that this field must be exactly the specified value + optional bytes const = 1; + + // Len specifies that this field must be the specified number of bytes + optional uint64 len = 13; + + // MinLen specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 min_len = 2; + + // MaxLen specifies that this field must be the specified number of bytes + // at a maximum + optional uint64 max_len = 3; + + // Pattern specifies that this field must match against the specified + // regular expression (RE2 syntax). The included expression should elide + // any delimiters. + optional string pattern = 4; + + // Prefix specifies that this field must have the specified bytes at the + // beginning of the string. + optional bytes prefix = 5; + + // Suffix specifies that this field must have the specified bytes at the + // end of the string. + optional bytes suffix = 6; + + // Contains specifies that this field must have the specified bytes + // anywhere in the string. + optional bytes contains = 7; + + // In specifies that this field must be equal to one of the specified + // values + repeated bytes in = 8; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated bytes not_in = 9; + + // WellKnown rules provide advanced constraints against common byte + // patterns + oneof well_known { + // Ip specifies that the field must be a valid IP (v4 or v6) address in + // byte format + bool ip = 10; + + // Ipv4 specifies that the field must be a valid IPv4 address in byte + // format + bool ipv4 = 11; + + // Ipv6 specifies that the field must be a valid IPv6 address in byte + // format + bool ipv6 = 12; + } + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 14; +} + +// EnumRules describe the constraints applied to enum values +message EnumRules { + // Const specifies that this field must be exactly the specified value + optional int32 const = 1; + + // DefinedOnly specifies that this field must be only one of the defined + // values for this enum, failing on any undefined value. + optional bool defined_only = 2; + + // In specifies that this field must be equal to one of the specified + // values + repeated int32 in = 3; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int32 not_in = 4; +} + +// MessageRules describe the constraints applied to embedded message values. +// For message-type fields, validation is performed recursively. +message MessageRules { + // Skip specifies that the validation rules of this field should not be + // evaluated + optional bool skip = 1; + + // Required specifies that this field must be set + optional bool required = 2; +} + +// RepeatedRules describe the constraints applied to `repeated` values +message RepeatedRules { + // MinItems specifies that this field must have the specified number of + // items at a minimum + optional uint64 min_items = 1; + + // MaxItems specifies that this field must have the specified number of + // items at a maximum + optional uint64 max_items = 2; + + // Unique specifies that all elements in this field must be unique. This + // constraint is only applicable to scalar and enum types (messages are not + // supported). + optional bool unique = 3; + + // Items specifies the constraints to be applied to each item in the field. + // Repeated message fields will still execute validation against each item + // unless skip is specified here. + optional FieldRules items = 4; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 5; +} + +// MapRules describe the constraints applied to `map` values +message MapRules { + // MinPairs specifies that this field must have the specified number of + // KVs at a minimum + optional uint64 min_pairs = 1; + + // MaxPairs specifies that this field must have the specified number of + // KVs at a maximum + optional uint64 max_pairs = 2; + + // NoSparse specifies values in this field cannot be unset. This only + // applies to map's with message value types. + optional bool no_sparse = 3; + + // Keys specifies the constraints to be applied to each key in the field. + optional FieldRules keys = 4; + + // Values specifies the constraints to be applied to the value of each key + // in the field. Message values will still have their validations evaluated + // unless skip is specified here. + optional FieldRules values = 5; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 6; +} + +// AnyRules describe constraints applied exclusively to the +// `google.protobuf.Any` well-known type +message AnyRules { + // Required specifies that this field must be set + optional bool required = 1; + + // In specifies that this field's `type_url` must be equal to one of the + // specified values. + repeated string in = 2; + + // NotIn specifies that this field's `type_url` must not be equal to any of + // the specified values. + repeated string not_in = 3; +} + +// // DurationRules describe the constraints applied exclusively to the +// // `google.protobuf.Duration` well-known type +// message DurationRules { +// // Required specifies that this field must be set +// optional bool required = 1; +// +// // Const specifies that this field must be exactly the specified value +// optional google.protobuf.Duration const = 2; +// +// // Lt specifies that this field must be less than the specified value, +// // exclusive +// optional google.protobuf.Duration lt = 3; +// +// // Lt specifies that this field must be less than the specified value, +// // inclusive +// optional google.protobuf.Duration lte = 4; +// +// // Gt specifies that this field must be greater than the specified value, +// // exclusive +// optional google.protobuf.Duration gt = 5; +// +// // Gte specifies that this field must be greater than the specified value, +// // inclusive +// optional google.protobuf.Duration gte = 6; +// +// // In specifies that this field must be equal to one of the specified +// // values +// repeated google.protobuf.Duration in = 7; +// +// // NotIn specifies that this field cannot be equal to one of the specified +// // values +// repeated google.protobuf.Duration not_in = 8; +// } +// +// // TimestampRules describe the constraints applied exclusively to the +// // `google.protobuf.Timestamp` well-known type +// message TimestampRules { +// // Required specifies that this field must be set +// optional bool required = 1; +// +// // Const specifies that this field must be exactly the specified value +// optional google.protobuf.Timestamp const = 2; +// +// // Lt specifies that this field must be less than the specified value, +// // exclusive +// optional google.protobuf.Timestamp lt = 3; +// +// // Lte specifies that this field must be less than the specified value, +// // inclusive +// optional google.protobuf.Timestamp lte = 4; +// +// // Gt specifies that this field must be greater than the specified value, +// // exclusive +// optional google.protobuf.Timestamp gt = 5; +// +// // Gte specifies that this field must be greater than the specified value, +// // inclusive +// optional google.protobuf.Timestamp gte = 6; +// +// // LtNow specifies that this must be less than the current time. LtNow +// // can only be used with the Within rule. +// optional bool lt_now = 7; +// +// // GtNow specifies that this must be greater than the current time. GtNow +// // can only be used with the Within rule. +// optional bool gt_now = 8; +// +// // Within specifies that this field must be within this duration of the +// // current time. This constraint can be used alone or with the LtNow and +// // GtNow rules. +// optional google.protobuf.Duration within = 9; +// } +// \ No newline at end of file