proto-lens 0.6.0.0 → 0.7.1.7
raw patch · 15 files changed
Files
- Changelog.md +27/−0
- proto-lens-imports/google/protobuf/compiler/plugin.proto +44/−31
- proto-lens-imports/google/protobuf/descriptor.proto +534/−121
- proto-lens.cabal +13/−15
- src/Data/ProtoLens/Combinators.hs +1/−1
- src/Data/ProtoLens/Encoding/Bytes.hs +8/−7
- src/Data/ProtoLens/Encoding/Parser.hs +10/−3
- src/Data/ProtoLens/Encoding/Wire.hs +26/−0
- src/Data/ProtoLens/Field.hs +0/−1
- src/Data/ProtoLens/Labels.hs +1/−0
- src/Data/ProtoLens/Message.hs +14/−0
- src/Data/ProtoLens/Service/Types.hs +6/−4
- src/Data/ProtoLens/TextFormat.hs +5/−4
- src/Data/ProtoLens/TextFormat/Parser.hs +48/−45
- tests/parser_test.hs +2/−3
Changelog.md view
@@ -1,5 +1,32 @@ # Changelog for `proto-lens` +## v0.7.1.7+- Relax upper bounds for ghc-9.10.+- Bump upper bound to allow ghc-prim-0.12 (ghc-9.10.2).+- Support GHC 9.12.+- Support GHC 9.14.++## v0.7.1.2+- Support GHC 9.4++## v0.7.1.1+- Relax upper bounds for ghc-9.2++## v0.7.1.0+- Support GHC 9.0.+- Fixed parsing of UTF8 chars in text format proto string literals.+- Support all valid text format boolean field values+- Remove redundant (.&. 127) from putVarInt (#396)++## v0.7.0.0+- Support GHC 8.10.+- Add a method to `Data.ProtoLens.Message` for getting the `DescriptorProto`+ of a given message. For a simpler API, see `Data.ProtoLens.Descriptor`+ from `proto-lens-protobuf-types`.+- Bump ghc-source-gen to version 0.4.0.0.+- Bump upper bound to allow base-4.14.+- Bump upper bound to allow ghc-prim-0.6.+ ## v0.6.0.0 ### Breaking Changes
proto-lens-imports/google/protobuf/compiler/plugin.proto view
@@ -1,38 +1,12 @@ // 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.+// 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 // Author: kenton@google.com (Kenton Varda) //-// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to-// change.-// // protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is // just a program that reads a CodeGeneratorRequest from stdin and writes a // CodeGeneratorResponse to stdout.@@ -45,11 +19,13 @@ // flag "--${NAME}_out" is passed to protoc. syntax = "proto2";+ package google.protobuf.compiler; option java_package = "com.google.protobuf.compiler"; option java_outer_classname = "PluginProtos"; -option go_package = "github.com/golang/protobuf/protoc-gen-go/plugin;plugin_go";+option csharp_namespace = "Google.Protobuf.Compiler";+option go_package = "google.golang.org/protobuf/types/pluginpb"; import "google/protobuf/descriptor.proto"; @@ -77,6 +53,11 @@ // they import. The files will appear in topological order, so each file // appears before any file that imports it. //+ // Note: the files listed in files_to_generate will include runtime-retention+ // options only, but all other files will include source-retention options.+ // The source_file_descriptors field below is available in case you need+ // source-retention options for files_to_generate.+ // // protoc guarantees that all proto_files will be written after // the fields above, even though this is not technically guaranteed by the // protobuf wire format. This theoretically could allow a plugin to stream@@ -89,9 +70,13 @@ // fully qualified. repeated FileDescriptorProto proto_file = 15; + // File descriptors with all options, including source-retention options.+ // These descriptors are only provided for the files listed in+ // files_to_generate.+ repeated FileDescriptorProto source_file_descriptors = 17;+ // The version number of protocol compiler. optional Version compiler_version = 3;- } // The plugin writes an encoded CodeGeneratorResponse to stdout.@@ -106,6 +91,29 @@ // exiting with a non-zero status code. optional string error = 1; + // A bitmask of supported features that the code generator supports.+ // This is a bitwise "or" of values from the Feature enum.+ optional uint64 supported_features = 2;++ // Sync with code_generator.h.+ enum Feature {+ FEATURE_NONE = 0;+ FEATURE_PROTO3_OPTIONAL = 1;+ FEATURE_SUPPORTS_EDITIONS = 2;+ }++ // The minimum edition this plugin supports. This will be treated as an+ // Edition enum, but we want to allow unknown values. It should be specified+ // according the edition enum value, *not* the edition number. Only takes+ // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.+ optional int32 minimum_edition = 3;++ // The maximum edition this plugin supports. This will be treated as an+ // Edition enum, but we want to allow unknown values. It should be specified+ // according the edition enum value, *not* the edition number. Only takes+ // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.+ optional int32 maximum_edition = 4;+ // Represents a single generated file. message File { // The file name, relative to the output directory. The name must not@@ -162,6 +170,11 @@ // The file contents. optional string content = 15;++ // Information describing the file content being inserted. If an insertion+ // point is used, this information will be appropriately offset and inserted+ // into the code generation metadata for the generated files.+ optional GeneratedCodeInfo generated_code_info = 16; } repeated File file = 15; }
proto-lens-imports/google/protobuf/descriptor.proto view
@@ -36,11 +36,11 @@ // 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 = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";++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";@@ -57,10 +57,46 @@ repeated FileDescriptorProto file = 1; } +// The full set of known editions.+enum Edition {+ // A placeholder for an unknown edition value.+ EDITION_UNKNOWN = 0;++ // A placeholder edition for specifying default behaviors *before* a feature+ // was first introduced. This is effectively an "infinite past".+ EDITION_LEGACY = 900;++ // 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;+ EDITION_2024 = 1001;++ // 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;++ // Placeholder for specifying unbounded edition support. This should only+ // ever be used by plugins that can expect to never require any changes to+ // support a new edition.+ EDITION_MAX = 0x7FFFFFFF;+}+ // 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.+ 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;@@ -85,8 +121,13 @@ optional SourceCodeInfo source_code_info = 9; // The syntax of the proto file.- // The supported values are "proto2" and "proto3".+ // 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.@@ -100,8 +141,8 @@ repeated EnumDescriptorProto enum_type = 4; message ExtensionRange {- optional int32 start = 1;- optional int32 end = 2;+ optional int32 start = 1; // Inclusive.+ optional int32 end = 2; // Exclusive. optional ExtensionRangeOptions options = 3; }@@ -115,8 +156,8 @@ // 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.+ 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.@@ -128,6 +169,52 @@ // 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, retention = RETENTION_SOURCE];+ // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; }@@ -137,42 +224,46 @@ enum Type { // 0 is reserved for errors. // Order is weird for historical reasons.- TYPE_DOUBLE = 1;- TYPE_FLOAT = 2;+ 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;+ 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;+ 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 in proto3. However, Proto3+ // 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.- TYPE_GROUP = 10;- TYPE_MESSAGE = 11; // Length-delimited aggregate.+ // 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.- };+ 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_REQUIRED = 2;- LABEL_REPEATED = 3;- };+ 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;@@ -197,7 +288,6 @@ // 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.- // TODO(kenton): Base-64 encode? optional string default_value = 7; // If set, gives the index of a oneof in the containing type's oneof_decl@@ -211,6 +301,29 @@ 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 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.@@ -234,8 +347,8 @@ // is inclusive such that it can appropriately represent the entire int32 // domain. message EnumReservedRange {- optional int32 start = 1; // Inclusive.- optional int32 end = 2; // Inclusive.+ optional int32 start = 1; // Inclusive.+ optional int32 end = 2; // Inclusive. } // Range of reserved numeric values. Reserved numeric values may not be used@@ -276,12 +389,11 @@ optional MethodOptions options = 4; // Identifies if client streams multiple client messages- optional bool client_streaming = 5 [default=false];+ optional bool client_streaming = 5 [default = false]; // Identifies if server streams multiple server messages- optional bool server_streaming = 6 [default=false];+ optional bool server_streaming = 6 [default = false]; } - // =================================================================== // Options @@ -314,7 +426,6 @@ // 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@@ -323,42 +434,44 @@ // domain names. optional string java_package = 1; -- // If set, all the classes from the .proto file are wrapped in a single- // outer class with the given name. This applies to both Proto1- // (equivalent to the old "--one_java_file" option) and Proto2 (where- // a .proto always translates to a single class, but you may want to- // explicitly choose the class name).+ // 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 set true, then the Java code generator will generate a separate .java+ // 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 outer class- // named by java_outer_classname. However, the outer class will still be+ // 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];+ 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];-+ // A proto2 file can set this to true to opt in to UTF-8 checking for Java,+ // which will throw an exception if invalid UTF-8 is parsed from the wire or+ // assigned to a string field.+ //+ // TODO: clarify exactly what kinds of field types this option+ // applies to, and update these docs accordingly.+ //+ // Proto3 files already perform these checks. Setting the option explicitly to+ // false has no effect: it cannot be used to opt proto3 files out of UTF-8+ // checks.+ 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.+ 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];+ 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:@@ -367,8 +480,6 @@ // - 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).@@ -379,21 +490,21 @@ // 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];+ optional bool cc_generic_services = 16 [default = false];+ optional bool java_generic_services = 17 [default = false];+ optional bool py_generic_services = 18 [default = false];+ reserved 42; // removed php_generic_services+ reserved "php_generic_services"; // 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];+ 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=false];-+ 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.@@ -417,10 +528,9 @@ // 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.+ // 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@@ -428,6 +538,9 @@ // 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;@@ -458,19 +571,21 @@ // // 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];+ 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];+ 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];+ optional bool deprecated = 3 [default = false]; + reserved 4, 5, 6;+ // Whether the message is an automatically generated map entry type for the // maps field. //@@ -486,7 +601,7 @@ // // 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 implementions still need to work as+ // The reflection APIs in such implementations still need to work as // if the field is a repeated message field. // // NOTE: Do not set the option in .proto files. Always use the maps syntax@@ -497,6 +612,21 @@ 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; @@ -505,15 +635,24 @@ } message FieldOptions {+ // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. // 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 not yet implemented in the open source- // release -- sorry, we'll try to include it in a future version!- optional CType ctype = 1 [default = STRING];+ // 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.+ // TODO: make ctype actually deprecated.+ optional CType ctype = 1 [/*deprecated = true,*/ 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;@@ -522,7 +661,9 @@ // 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.+ // 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@@ -565,39 +706,106 @@ // 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.- optional bool lazy = 5 [default=false];+ // Note that lazy message fields are still eagerly verified to check+ // ill-formed wireformat or missing required fields. Calling IsInitialized()+ // on the outer message would fail if the inner message has missing required+ // fields. Failed verification would result in parsing failure (except when+ // uninitialized messages are acceptable).+ 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];+ optional bool deprecated = 3 [default = false]; // For Google-internal migration only. Do not use.- optional bool weak = 10 [default=false];+ 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;++ // Information about the support window of a feature.+ message FeatureSupport {+ // The edition that this feature was first available in. In editions+ // earlier than this one, the default assigned to EDITION_LEGACY will be+ // used, and proto files will not be able to override it.+ optional Edition edition_introduced = 1;++ // The edition this feature becomes deprecated in. Using this after this+ // edition may trigger warnings.+ optional Edition edition_deprecated = 2;++ // The deprecation warning text if this feature is used after the edition it+ // was marked deprecated in.+ optional string deprecation_warning = 3;++ // The edition this feature is no longer available in. In editions after+ // this one, the last default assigned will be used, and proto files will+ // not be able to override it.+ optional Edition edition_removed = 4;+ }+ optional FeatureSupport feature_support = 22;+ // 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 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; @@ -615,10 +823,21 @@ // 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];+ 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; @@ -631,8 +850,19 @@ // 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];+ 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];++ // Information about the support window of a feature value.+ optional FieldOptions.FeatureSupport feature_support = 4;+ // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -642,6 +872,9 @@ 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@@ -651,7 +884,7 @@ // 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];+ optional bool deprecated = 33 [default = false]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999;@@ -671,19 +904,22 @@ // 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];+ 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+ NO_SIDE_EFFECTS = 1; // implies idempotent+ IDEMPOTENT = 2; // idempotent, but may have side effects }- optional IdempotencyLevel idempotency_level =- 34 [default=IDEMPOTENCY_UNKNOWN];+ 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; @@ -691,7 +927,6 @@ 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,@@ -702,8 +937,8 @@ // 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], ["qux", false] } represents- // "foo.(bar.baz).qux".+ // 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;@@ -721,6 +956,172 @@ } // ===================================================================+// 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,+ feature_support = {+ edition_introduced: EDITION_2023,+ },+ edition_defaults = { edition: EDITION_LEGACY, 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,+ feature_support = {+ edition_introduced: EDITION_2023,+ },+ edition_defaults = { edition: EDITION_LEGACY, 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,+ feature_support = {+ edition_introduced: EDITION_2023,+ },+ edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" },+ edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" }+ ];++ enum Utf8Validation {+ UTF8_VALIDATION_UNKNOWN = 0;+ VERIFY = 2;+ NONE = 3;+ reserved 1;+ }+ optional Utf8Validation utf8_validation = 4 [+ retention = RETENTION_RUNTIME,+ targets = TARGET_TYPE_FIELD,+ targets = TARGET_TYPE_FILE,+ feature_support = {+ edition_introduced: EDITION_2023,+ },+ edition_defaults = { edition: EDITION_LEGACY, 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,+ feature_support = {+ edition_introduced: EDITION_2023,+ },+ edition_defaults = { edition: EDITION_LEGACY, 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,+ feature_support = {+ edition_introduced: EDITION_2023,+ },+ edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" },+ edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" }+ ];++ reserved 999;++ extensions 1000 to 9994 [+ declaration = {+ number: 1000,+ full_name: ".pb.cpp",+ type: ".pb.CppFeatures"+ },+ declaration = {+ number: 1001,+ full_name: ".pb.java",+ type: ".pb.JavaFeatures"+ },+ declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" },+ declaration = {+ number: 9990,+ full_name: ".pb.proto1",+ type: ".pb.Proto1Features"+ }+ ];++ extensions 9995 to 9999; // For internal testing+ extensions 10000; // for https://github.com/bufbuild/protobuf-es+}++// 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;++ // Defaults of features that can be overridden in this edition.+ optional FeatureSet overridable_features = 4;++ // Defaults of features that can't be overridden in this edition.+ optional FeatureSet fixed_features = 5;++ reserved 1, 2;+ reserved "features";+ }+ 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@@ -763,7 +1164,7 @@ // 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 descendent. For example, a "group" defines+ // 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@@ -775,8 +1176,8 @@ // location. // // Each element is a field number or an index. They form a path from- // the root FileDescriptorProto to the place where the definition. For- // example, this path:+ // the root FileDescriptorProto to the place where the definition appears.+ // For example, this path: // [ 4, 3, 2, 7, 1 ] // refers to: // file.message_type(3) // 4, 3@@ -794,14 +1195,14 @@ // [ 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];+ 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];+ 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@@ -830,13 +1231,13 @@ // // Comment attached to baz. // // Another line attached to baz. //- // // Comment attached to qux.+ // // Comment attached to moo. // //- // // Another line attached to qux.- // optional double qux = 4;+ // // Another line attached to moo.+ // optional double moo = 4; // // // Detached comment for corge. This is not leading or trailing comments- // // to qux or corge because there are blank lines separating it from+ // // to moo or corge because there are blank lines separating it from // // both. // // // Detached comment for corge paragraph 2.@@ -866,7 +1267,7 @@ 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];+ repeated int32 path = 1 [packed = true]; // Identifies the filesystem path to the original source .proto. optional string source_file = 2;@@ -876,8 +1277,20 @@ optional int32 begin = 3; // Identifies the ending offset in bytes in the generated code that- // relates to the identified offset. The end offset should be one past+ // 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; } }
proto-lens.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.2.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack------ hash: 5006405422ef969b41707de8219c7bbf95f72fb7bb41c12a2f22d30086de9113 name: proto-lens-version: 0.6.0.0+version: 0.7.1.7 synopsis: A lens-based implementation of protocol buffers in Haskell. description: The proto-lens library provides an API for protocol buffers using modern Haskell language and library patterns. Specifically, it provides: .@@ -60,20 +58,20 @@ hs-source-dirs: src build-depends:- base >=4.10 && <4.14- , bytestring ==0.10.*- , containers >=0.5 && <0.7- , deepseq ==1.4.*- , ghc-prim >=0.4 && <0.6- , lens-family >=1.2 && <2.1+ base >=4.10 && <4.23+ , bytestring >=0.10 && <0.14+ , containers >=0.5 && <0.9+ , deepseq >=1.4 && <1.6+ , ghc-prim >=0.4 && <0.14+ , lens-family >=1.2 && <2.2 , parsec ==3.1.* , pretty ==1.1.*- , primitive >=0.6 && <0.8- , profunctors >=5.2 && <5.6+ , primitive >=0.6 && <0.10+ , profunctors >=5.2 && <6.0 , tagged ==0.8.*- , text ==1.2.*- , transformers >=0.4 && <0.6- , vector >=0.11 && <0.13+ , text >=1.2 && <2.2+ , transformers >=0.4 && <0.7+ , vector >=0.11 && <0.14 default-language: Haskell2010 test-suite growing_test
src/Data/ProtoLens/Combinators.hs view
@@ -29,7 +29,7 @@ -- | Sets the provided lens in @a@ to @Nothing@. clear :: Setter a a' b (Maybe b') -> a -> a'-clear = (.~ Nothing)+clear setter = setter .~ Nothing -- | Creates a 'Default' and then applies the provided `State` to it. This is -- convenient for creating complicated structures.
src/Data/ProtoLens/Encoding/Bytes.hs view
@@ -6,7 +6,6 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE LambdaCase #-}@@ -22,6 +21,8 @@ -- * Bytestrings getBytes, putBytes,+ -- * Text+ getText, -- * Integral types getVarInt, getVarIntH,@@ -51,7 +52,7 @@ import Control.Monad.Trans.Except (throwE, ExceptT) import Data.Bits import Data.ByteString (ByteString)-import Data.ByteString.Lazy.Builder as Builder+import Data.ByteString.Builder as Builder import qualified Data.ByteString.Builder.Internal as Internal import qualified Data.ByteString.Lazy as L import Data.Int (Int32, Int64)@@ -61,14 +62,14 @@ import qualified Data.Vector.Generic as V import Data.Word (Word8, Word32, Word64) import Foreign.Marshal (malloc, free)-import Foreign.Storable (peek) import System.IO (Handle, hGetBuf) #if MIN_VERSION_base(4,11,0) import qualified GHC.Float as Float+import Foreign.Storable (peek) #else import Foreign.Ptr (castPtr) import Foreign.Marshal.Alloc (alloca)-import Foreign.Storable (Storable, poke)+import Foreign.Storable (Storable, peek, poke) import System.IO.Unsafe (unsafePerformIO) #endif @@ -94,9 +95,9 @@ getVarIntH h = do buf <- liftIO malloc let loopStart !n !s =- (liftIO $ hGetBuf h buf 1) >>=+ liftIO (hGetBuf h buf 1) >>= \case- 1 -> (liftIO $ peek buf) >>=+ 1 -> liftIO (peek buf) >>= getVarIntLoopFinish loopStart n s _ -> throwE "Unexpected end of file" res <- loopStart 0 1@@ -126,7 +127,7 @@ putVarInt :: Word64 -> Builder putVarInt n | n < 128 = Builder.word8 (fromIntegral n)- | otherwise = Builder.word8 (fromIntegral $ n .&. 127 .|. 128)+ | otherwise = Builder.word8 (fromIntegral $ n .|. 128) <> putVarInt (n `shiftR` 7) getFixed32 :: Parser Word32
src/Data/ProtoLens/Encoding/Parser.hs view
@@ -1,6 +1,4 @@ -- | A custom parsing monad, optimized for speed.-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} module Data.ProtoLens.Encoding.Parser@@ -11,6 +9,7 @@ , getWord8 , getWord32le , getBytes+ , getText , (<?>) ) where @@ -18,6 +17,8 @@ import Data.Word (Word8, Word32) import Data.ByteString (ByteString, packCStringLen) import qualified Data.ByteString.Unsafe as B+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8') import Foreign.Ptr import Foreign.Storable import System.IO.Unsafe (unsafePerformIO)@@ -68,6 +69,12 @@ getBytes n = withSized n "getBytes: Unexpected end of input" $ \pos -> packCStringLen (castPtr pos, n) +getText :: Int -> Parser Text+getText n = do+ r <- withSized n "getText: Unexpected end of input" $ \pos ->+ decodeUtf8' <$> B.unsafePackCStringLen (castPtr pos, n)+ either (fail . show) pure r+ -- | Helper function for reading bytes from the current position and -- advancing the pointer. --@@ -86,7 +93,7 @@ | otherwise = fail "withSized: negative length" {-# INLINE withSized #-} --- | Run the given parsing action as if there are only +-- | Run the given parsing action as if there are only -- @len@ bytes remaining. That is, once @len@ bytes have been -- consumed, 'atEnd' will return 'True' and other actions -- like 'getWord8' will act like there is no input remaining.
src/Data/ProtoLens/Encoding/Wire.hs view
@@ -16,7 +16,9 @@ , joinTypeAndTag , parseFieldSet , buildFieldSet+ , buildMessageSet , parseTaggedValueFromWire+ , parseMessageSetTaggedValueFromWire ) where import Control.DeepSeq (NFData(..))@@ -63,6 +65,15 @@ putVarInt (joinTypeAndTag tag (wireValueToInt wv)) <> buildWireValue wv +-- builds in legacy MessageSet format.+-- See https://github.com/protocolbuffers/protobuf/blob/dec4939439d9ca2adf2bb14edccf876c2587faf2/src/google/protobuf/descriptor.proto#L444+buildTaggedValueAsMessageSet :: TaggedValue -> Builder+buildTaggedValueAsMessageSet (TaggedValue (Tag t) wv) =+ buildTaggedValue ( TaggedValue 1 StartGroup)+ <> buildTaggedValue (TaggedValue 2 (VarInt $ fromIntegral t))+ <> buildTaggedValue (TaggedValue 3 wv)+ <> buildTaggedValue (TaggedValue 1 EndGroup)+ buildWireValue :: WireValue -> Builder buildWireValue (VarInt w) = putVarInt w buildWireValue (Fixed64 w) = putFixed64 w@@ -98,6 +109,18 @@ 5 -> Fixed32 <$> getFixed32 _ -> fail $ "Unknown wire type " ++ show w +parseMessageSetTaggedValueFromWire :: Word64 -> Parser TaggedValue+parseMessageSetTaggedValueFromWire t =+ parseTaggedValueFromWire t >>= \v -> case v of+ TaggedValue 1 StartGroup -> parseTaggedValue >>= \ft -> case ft of+ TaggedValue 2 (VarInt f) -> parseTaggedValue >>= \dt -> case dt of+ TaggedValue 3 (Lengthy b) -> parseTaggedValue >>= \et -> case et of+ TaggedValue 1 EndGroup -> return $ TaggedValue (Tag $ fromIntegral f) (Lengthy b)+ _ -> fail "missing end_group"+ _ -> fail "missing message"+ _ -> fail "missing field tag"+ _ -> return v+ splitTypeAndTag :: Word64 -> (Tag, Word8) splitTypeAndTag w = (fromIntegral $ w `shiftR` 3, fromIntegral (w .&. 7)) @@ -117,3 +140,6 @@ buildFieldSet :: FieldSet -> Builder buildFieldSet = mconcat . map buildTaggedValue ++buildMessageSet :: FieldSet -> Builder+buildMessageSet = mconcat . map buildTaggedValueAsMessageSet
src/Data/ProtoLens/Field.hs view
@@ -17,7 +17,6 @@ {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ScopedTypeVariables #-} module Data.ProtoLens.Field
src/Data/ProtoLens/Labels.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE MagicHash #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} #if __GLASGOW_HASKELL__ >= 802 {-# LANGUAGE ScopedTypeVariables #-}
src/Data/ProtoLens/Message.hs view
@@ -75,6 +75,20 @@ -- @"packagename.messagename"@. messageName :: Proxy msg -> T.Text + -- | The serialized protobuffer message descriptor for this type.+ --+ -- For a friendlier version which returns the actual descriptor type,+ -- use @Data.ProtoLens.Descriptor.messageDescriptor@+ -- from the @proto-lens-protobuf-types@ package.+ packedMessageDescriptor :: Proxy msg -> B.ByteString++ -- | The serialized protobuffer file message descriptor containing this type.+ --+ -- For a friendlier version which returns the actual file descriptor type,+ -- use @Data.ProtoLens.Descriptor.fileDescriptor@+ -- from the @proto-lens-protobuf-types@ package.+ packedFileDescriptor :: Proxy msg -> B.ByteString+ -- | A message with all fields set to their default values. -- -- Satisfies @encodeMessage defMessage == ""@ and @decodeMessage "" == Right defMessage@.
src/Data/ProtoLens/Service/Types.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-}@@ -23,8 +22,10 @@ , StreamingType (..) ) where -import Data.Kind (Constraint)+import qualified Data.ByteString as B+import Data.Kind (Constraint, Type) import Data.ProtoLens.Message (Message)+import Data.Proxy (Proxy(..)) import GHC.TypeLits @@ -53,6 +54,7 @@ type ServicePackage s :: Symbol type ServiceMethods s :: [Symbol] + packedServiceDescriptor :: Proxy s -> B.ByteString ------------------------------------------------------------------------------ -- | Data type to be used as a promoted type for 'MethodStreamingType'.@@ -82,8 +84,8 @@ , Message (MethodOutput s m) ) => HasMethodImpl s (m :: Symbol) where type MethodName s m :: Symbol- type MethodInput s m :: *- type MethodOutput s m :: *+ type MethodInput s m :: Type+ type MethodOutput s m :: Type type MethodStreamingType s m :: StreamingType
src/Data/ProtoLens/TextFormat.hs view
@@ -28,7 +28,8 @@ import Data.Bifunctor (first) import qualified Data.ByteString import Data.Char (isPrint, isAscii, chr)-import Data.Foldable (foldlM, foldl')+import Data.Foldable (foldlM)+import qualified Data.Foldable as F import qualified Data.Map as Map import Data.Maybe (catMaybes) import Data.Proxy (Proxy(Proxy))@@ -228,7 +229,7 @@ <$> buildMessageFromDescriptor reg defMessage fields missingFields :: forall msg . Message msg => Proxy msg -> Parser.Message -> [String]-missingFields _ = Set.toList . foldl' deleteField requiredFieldNames+missingFields _ = Set.toList . F.foldl' deleteField requiredFieldNames where requiredFieldNames :: Set.Set String requiredFieldNames = Set.fromList $ Map.keys@@ -317,8 +318,8 @@ makeScalarValue DoubleField (Parser.DoubleValue x) = Right x makeScalarValue FloatField (Parser.DoubleValue x) = Right (realToFrac x) makeScalarValue BoolField (Parser.EnumValue x)- | x == "true" = Right True- | x == "false" = Right False+ | x `elem` ["true", "True", "t"] = Right True+ | x `elem` ["false", "False", "f"] = Right False | otherwise = Left $ "Unrecognized bool value " ++ show x makeScalarValue StringField (Parser.ByteStringValue x) = Right (Text.decodeUtf8 x) makeScalarValue BytesField (Parser.ByteStringValue x) = Right x
src/Data/ProtoLens/TextFormat/Parser.hs view
@@ -16,23 +16,23 @@ , parser ) where -import Data.ByteString (ByteString, pack)-import Data.Char (ord, isSpace)+import Control.Applicative ((<|>), many)+import Control.Monad (liftM, liftM2, mzero, unless)+import Data.ByteString (ByteString)+import Data.ByteString.Builder (Builder, char8, charUtf8, toLazyByteString, word8)+import Data.ByteString.Lazy (toStrict)+import Data.Char (digitToInt, isSpace)+import Data.Functor (($>)) import Data.Functor.Identity (Identity) import Data.List (intercalate)-import Data.Maybe (catMaybes)-import Data.Text.Lazy (Text) import qualified Data.Text as StrictText-import Data.Word (Word8)-import Numeric (readOct, readHex)+import Data.Text.Lazy (Text) import Text.Parsec ((<?>)) import Text.Parsec.Char (alphaNum, char, hexDigit, letter, octDigit, oneOf, satisfy) import Text.Parsec.Text.Lazy (Parser)-import Text.Parsec.Combinator (choice, eof, many1, optionMaybe, sepBy1)+import Text.Parsec.Combinator (choice, eof, many1, sepBy1) import Text.Parsec.Token hiding (octal)-import Control.Applicative ((<|>), many)-import Control.Monad (liftM, liftM2, mzero) -- | A 'TokenParser' for the protobuf text format. ptp :: GenTokenParser Text () Identity@@ -55,7 +55,6 @@ , caseSensitive = True } - type Message = [Field] data Field = Field Key Value@@ -103,7 +102,7 @@ value <- naturalOrFloat ptp return $ makeNumberValue negative value parseString = liftM (ByteStringValue . mconcat)- $ many1 $ lexeme ptp $ protoStringLiteral+ $ many1 $ lexeme ptp protoStringLiteral parseEnumValue = liftM EnumValue (identifier ptp) parseMessageValue = braces ptp (parseAny <|>@@ -131,39 +130,43 @@ protoStringLiteral :: Parser ByteString protoStringLiteral = do initialQuoteChar <- char '\'' <|> char '\"'- word8s <- many $ stringChar initialQuoteChar+ let quoted = do+ _ <- char '\\'+ choice+ [ char 'a' $> char8 '\a'+ , char 'b' $> char8 '\b'+ , char 'f' $> char8 '\f'+ , char 'n' $> char8 '\n'+ , char 'r' $> char8 '\r'+ , char 't' $> char8 '\t'+ , char 'v' $> char8 '\v'+ , char '\\' $> char8 '\\'+ , char '\'' $> char8 '\''+ , char '\"' $> char8 '\"'+ , oneOf "xX" *> parse8BitToBuilder hexDigit 16 (1, 2)+ , oneOf "uU" *> fail "Unicode in string literals not yet supported"+ , parse8BitToBuilder octDigit 8 (1, 3)+ ]+ unquoted = charUtf8 <$> satisfy (/= initialQuoteChar)+ builders <- many $ quoted <|> unquoted _ <- char initialQuoteChar- return $ pack word8s+ return $ toStrict $ toLazyByteString $ mconcat builders where- stringChar :: Char -> Parser Word8- stringChar quote = (nonEscape quote) <|> stringEscape- nonEscape quote = fmap (fromIntegral . ord)- $ satisfy (\c -> c `notElem` "\\" ++ [quote] && ord c < 256)- stringEscape = char '\\' >> (octal <|> hex <|> unicode <|> simple)- octal = do d0 <- octDigit- d1 <- optionMaybe octDigit- d2 <- optionMaybe octDigit- readMaybeDigits readOct [Just d0, d1, d2]- readMaybeDigits :: ReadS Word8 -> [Maybe Char] -> Parser Word8- readMaybeDigits reader- = return . (\str -> let [(v, "")] = reader str in v) . catMaybes- hex = do _ <- oneOf "xX"- d0 <- hexDigit- d1 <- optionMaybe hexDigit- readMaybeDigits readHex [Just d0, d1]- unicode = oneOf "uU" >> fail "Unicode in string literals not yet supported"- simple = choice $ map charRet [ ('a', '\a')- , ('b', '\b')- , ('f', '\f')- , ('n', '\n')- , ('r', '\r')- , ('t', '\t')- , ('v', '\v')- , ('\\', '\\')- , ('\'', '\'')- , ('\"', '\"')- ]- where- charRet :: (Char, Char) -> Parser Word8- charRet (escapeCh, ch) = do _ <- char escapeCh- return $ fromIntegral $ ord ch+ -- | Apply a parser between 'min' and 'max' times, failing otherwise.+ manyN :: Parser a -> (Int, Int) -> Parser [a]+ manyN _ (_, 0) = return []+ manyN p (0, maX) = ((:) <$> p <*> manyN p (0, maX - 1)) <|> pure []+ manyN p (miN, maX) = (:) <$> p <*> manyN p (miN - 1, maX - 1)++ -- | Parse a number in 'base' with between 'min' and 'max' digits.+ parseNum :: Parser Char -> Int -> (Int, Int) -> Parser Int+ parseNum p base range = do+ digits <- map digitToInt <$> manyN p range+ return $ foldl (\a d -> a * base + d) 0 digits++ -- | Parse a number and return a builder for the 8-bit char it represents.+ parse8BitToBuilder :: Parser Char -> Int -> (Int, Int) -> Parser Builder+ parse8BitToBuilder p base range = do+ value <- parseNum p base range+ unless (value < 256) $ fail "Escaped number is not 8-bit"+ return $ word8 $ fromIntegral value
tests/parser_test.hs view
@@ -1,7 +1,6 @@ -- | Unit and property tests for our custom parsing monad. module Main (main) where -import Control.Applicative (liftA2) import qualified Data.ByteString as B import Data.Either (isLeft) @@ -74,8 +73,8 @@ testIsolate :: [TestTree] testIsolate = [ testProperty "many" $ \bs bs' ->- runParser (liftA2 (,) (isolate (length bs) $ manyTillEnd getWord8)- (manyTillEnd getWord8))+ runParser ((,) <$> isolate (length bs) (manyTillEnd getWord8) <*>+ manyTillEnd getWord8) (B.pack (bs ++ bs')) == Right (bs, bs') , testProperty "negative length" $ \n ws ->