aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2023-03-28 08:18:22 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-28 08:18:22 +0000
commit930dfa49953345e7e74a11c21f7c62fd86a03044 (patch)
tree52ddb6e645db2fa36d5772c15b5d4cc47a662d62
parent94de443db7c9dd53a8358bec9612466989799791 (diff)
parent9a9d43c8c3946bbcda3d4bb1e249989f641dbe61 (diff)
downloadprotobuf-codegen-930dfa49953345e7e74a11c21f7c62fd86a03044.tar.gz
Introduce libprotobuf_codegen_deprecated am: 9a9d43c8c3
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/protobuf-codegen/+/2509876 Change-Id: I1c22f3dcf344b31ceefe5d1ee4e3f9eda0c99057 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--2.27.1/.cargo_vcs_info.json6
-rw-r--r--2.27.1/Android.bp48
-rw-r--r--2.27.1/Cargo.lock16
-rw-r--r--2.27.1/Cargo.toml44
-rw-r--r--2.27.1/Cargo.toml.orig35
l---------2.27.1/LICENSE1
-rw-r--r--2.27.1/LICENSE.txt19
-rw-r--r--2.27.1/METADATA19
-rw-r--r--2.27.1/MODULE_LICENSE_MIT0
l---------2.27.1/NOTICE1
-rw-r--r--2.27.1/OWNERS1
-rw-r--r--2.27.1/README.md80
-rw-r--r--2.27.1/cargo2android.json4
-rw-r--r--2.27.1/src/bin/protobuf-bin-gen-rust-do-not-use.rs37
-rw-r--r--2.27.1/src/bin/protoc-gen-rust.rs5
-rw-r--r--2.27.1/src/code_writer.rs387
-rw-r--r--2.27.1/src/customize.rs237
-rw-r--r--2.27.1/src/enums.rs377
-rw-r--r--2.27.1/src/extensions.rs116
-rw-r--r--2.27.1/src/field/mod.rs2031
-rw-r--r--2.27.1/src/file.rs87
-rw-r--r--2.27.1/src/file_and_mod.rs9
-rw-r--r--2.27.1/src/file_descriptor.rs5
-rw-r--r--2.27.1/src/float.rs67
-rw-r--r--2.27.1/src/inside.rs10
-rw-r--r--2.27.1/src/lib.rs387
-rw-r--r--2.27.1/src/message.rs626
-rw-r--r--2.27.1/src/oneof.rs198
-rw-r--r--2.27.1/src/protobuf_name.rs374
-rw-r--r--2.27.1/src/rust.rs62
-rw-r--r--2.27.1/src/rust_name.rs273
-rw-r--r--2.27.1/src/rust_types_values.rs593
-rw-r--r--2.27.1/src/scope.rs555
-rw-r--r--2.27.1/src/serde.rs9
-rw-r--r--2.27.1/src/strx.rs57
-rw-r--r--2.27.1/src/syntax.rs15
-rw-r--r--2.27.1/src/well_known_types.rs63
37 files changed, 6854 insertions, 0 deletions
diff --git a/2.27.1/.cargo_vcs_info.json b/2.27.1/.cargo_vcs_info.json
new file mode 100644
index 0000000..8ec5394
--- /dev/null
+++ b/2.27.1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "ec31ce829473039ac598ca6fdcb245cbd6fa82ba"
+ },
+ "path_in_vcs": "protobuf-codegen"
+} \ No newline at end of file
diff --git a/2.27.1/Android.bp b/2.27.1/Android.bp
new file mode 100644
index 0000000..2a96b07
--- /dev/null
+++ b/2.27.1/Android.bp
@@ -0,0 +1,48 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+rust_library_host {
+ name: "libprotobuf_codegen_deprecated",
+ crate_name: "protobuf_codegen",
+ cargo_env_compat: true,
+ cargo_pkg_version: "2.27.1",
+ srcs: ["src/lib.rs"],
+ edition: "2015",
+ rustlibs: [
+ "libprotobuf_deprecated",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
+
+rust_test_host {
+ name: "protobuf-codegen_deprecated_test_src_lib",
+ crate_name: "protobuf_codegen",
+ cargo_env_compat: true,
+ cargo_pkg_version: "2.27.1",
+ srcs: ["src/lib.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
+ edition: "2015",
+ rustlibs: [
+ "libprotobuf_deprecated",
+ ],
+}
+
+rust_binary_host {
+ name: "protoc-gen-rust-deprecated",
+ crate_name: "protoc_gen_rust",
+ cargo_env_compat: true,
+ cargo_pkg_version: "2.27.1",
+ srcs: ["src/bin/protoc-gen-rust.rs"],
+ edition: "2015",
+ rustlibs: [
+ "libprotobuf_deprecated",
+ "libprotobuf_codegen_deprecated",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
diff --git a/2.27.1/Cargo.lock b/2.27.1/Cargo.lock
new file mode 100644
index 0000000..e9b0703
--- /dev/null
+++ b/2.27.1/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "protobuf"
+version = "2.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96"
+
+[[package]]
+name = "protobuf-codegen"
+version = "2.27.1"
+dependencies = [
+ "protobuf",
+]
diff --git a/2.27.1/Cargo.toml b/2.27.1/Cargo.toml
new file mode 100644
index 0000000..ca327e2
--- /dev/null
+++ b/2.27.1/Cargo.toml
@@ -0,0 +1,44 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+name = "protobuf-codegen"
+version = "2.27.1"
+authors = ["Stepan Koltsov <stepan.koltsov@gmail.com>"]
+description = """
+Code generator for rust-protobuf.
+
+Includes a library and `protoc-gen-rust` binary.
+
+See `protoc-rust` and `protobuf-codegen-pure` crates.
+"""
+homepage = "https://github.com/stepancheg/rust-protobuf/"
+license = "MIT"
+repository = "https://github.com/stepancheg/rust-protobuf/"
+
+[package.metadata.docs.rs]
+all-features = true
+
+[lib]
+bench = false
+
+[[bin]]
+name = "protoc-gen-rust"
+path = "src/bin/protoc-gen-rust.rs"
+test = false
+
+[[bin]]
+name = "protobuf-bin-gen-rust-do-not-use"
+path = "src/bin/protobuf-bin-gen-rust-do-not-use.rs"
+test = false
+
+[dependencies.protobuf]
+version = "=2.27.1"
diff --git a/2.27.1/Cargo.toml.orig b/2.27.1/Cargo.toml.orig
new file mode 100644
index 0000000..3400e66
--- /dev/null
+++ b/2.27.1/Cargo.toml.orig
@@ -0,0 +1,35 @@
+[package]
+name = "protobuf-codegen"
+version = "2.27.1"
+authors = ["Stepan Koltsov <stepan.koltsov@gmail.com>"]
+license = "MIT"
+homepage = "https://github.com/stepancheg/rust-protobuf/"
+repository = "https://github.com/stepancheg/rust-protobuf/"
+description = """
+Code generator for rust-protobuf.
+
+Includes a library and `protoc-gen-rust` binary.
+
+See `protoc-rust` and `protobuf-codegen-pure` crates.
+"""
+
+[lib]
+bench = false
+
+[dependencies]
+protobuf = { path = "../protobuf", version = "=2.27.1" }
+
+[[bin]]
+
+name = "protoc-gen-rust"
+path = "src/bin/protoc-gen-rust.rs"
+test = false
+
+[[bin]]
+
+name = "protobuf-bin-gen-rust-do-not-use"
+path = "src/bin/protobuf-bin-gen-rust-do-not-use.rs"
+test = false
+
+[package.metadata.docs.rs]
+all-features = true
diff --git a/2.27.1/LICENSE b/2.27.1/LICENSE
new file mode 120000
index 0000000..85de3d4
--- /dev/null
+++ b/2.27.1/LICENSE
@@ -0,0 +1 @@
+LICENSE.txt \ No newline at end of file
diff --git a/2.27.1/LICENSE.txt b/2.27.1/LICENSE.txt
new file mode 100644
index 0000000..acce639
--- /dev/null
+++ b/2.27.1/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2019 Stepan Koltsov
+
+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. \ No newline at end of file
diff --git a/2.27.1/METADATA b/2.27.1/METADATA
new file mode 100644
index 0000000..4593845
--- /dev/null
+++ b/2.27.1/METADATA
@@ -0,0 +1,19 @@
+name: "protobuf-codegen"
+description: "Code generator for rust-protobuf. Includes a library and `protoc-gen-rust` binary. See `protoc-rust` and `protobuf-codegen-pure` crates."
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/protobuf-codegen"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/protobuf-codegen/protobuf-codegen-2.27.1.crate"
+ }
+ version: "2.27.1"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2022
+ month: 3
+ day: 1
+ }
+}
diff --git a/2.27.1/MODULE_LICENSE_MIT b/2.27.1/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/2.27.1/MODULE_LICENSE_MIT
diff --git a/2.27.1/NOTICE b/2.27.1/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/2.27.1/NOTICE
@@ -0,0 +1 @@
+LICENSE \ No newline at end of file
diff --git a/2.27.1/OWNERS b/2.27.1/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/2.27.1/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/2.27.1/README.md b/2.27.1/README.md
new file mode 100644
index 0000000..2ab7e05
--- /dev/null
+++ b/2.27.1/README.md
@@ -0,0 +1,80 @@
+<!-- cargo-sync-readme start -->
+
+# Protobuf code generator
+
+This crate contains protobuf code generator implementation
+and a `protoc-gen-rust` `protoc` plugin.
+
+This crate:
+* provides `protoc-gen-rust` plugin for `protoc` command
+* implement protobuf codegen
+
+This crate is not meant to be used directly, in fact, it does not provide any public API
+(except for `protoc-gen-rust` binary).
+
+Code can be generated with either:
+* `protoc-gen-rust` plugin for `protoc` or
+* [`protoc-rust`](https://docs.rs/protoc) crate
+ (code generator which depends on `protoc` binary for parsing of `.proto` files)
+* [`protobuf-codegen-pure`](https://docs.rs/protobuf-codegen-pure) crate,
+ similar API to `protoc-rust`, but uses pure rust parser of `.proto` files.
+
+# `protoc-gen-rust` plugin for `protoc`
+
+When non-cargo build system is used, consider using standard protobuf code generation pattern:
+`protoc` command does all the work of handling paths and parsing `.proto` files.
+When `protoc` is invoked with `--rust_out=` option, it invokes `protoc-gen-rust` plugin.
+provided by this crate.
+
+When building with cargo, consider using `protoc-rust` or `protobuf-codegen-pure` crates.
+
+## How to use `protoc-gen-rust` if you have to
+
+(Note `protoc` can be invoked programmatically with
+[protoc crate](https://docs.rs/protoc))
+
+0) Install protobuf for `protoc` binary.
+
+On OS X [Homebrew](https://github.com/Homebrew/brew) can be used:
+
+```sh
+brew install protobuf
+```
+
+On Ubuntu, `protobuf-compiler` package can be installed:
+
+```sh
+apt-get install protobuf-compiler
+```
+
+Protobuf is needed only for code generation, `rust-protobuf` runtime
+does not use `protobuf` library.
+
+1) Install `protoc-gen-rust` program (which is `protoc` plugin)
+
+It can be installed either from source or with `cargo install protobuf` command.
+
+2) Add `protoc-gen-rust` to $PATH
+
+If you installed it with cargo, it should be
+
+```sh
+PATH="$HOME/.cargo/bin:$PATH"
+```
+
+3) Generate .rs files:
+
+```sh
+protoc --rust_out . foo.proto
+```
+
+This will generate .rs files in current directory.
+
+# Version 2
+
+This is documentation for version 2 of the crate.
+
+[Version 3 of the crate](https://docs.rs/protobuf-codegen/%3E=3.0.0-alpha)
+(currently in development) encapsulates both `protoc` and pure codegens in this crate.
+
+<!-- cargo-sync-readme end -->
diff --git a/2.27.1/cargo2android.json b/2.27.1/cargo2android.json
new file mode 100644
index 0000000..341300b
--- /dev/null
+++ b/2.27.1/cargo2android.json
@@ -0,0 +1,4 @@
+{
+ "run": true,
+ "tests": true
+} \ No newline at end of file
diff --git a/2.27.1/src/bin/protobuf-bin-gen-rust-do-not-use.rs b/2.27.1/src/bin/protobuf-bin-gen-rust-do-not-use.rs
new file mode 100644
index 0000000..a6f96ca
--- /dev/null
+++ b/2.27.1/src/bin/protobuf-bin-gen-rust-do-not-use.rs
@@ -0,0 +1,37 @@
+extern crate protobuf;
+extern crate protobuf_codegen;
+
+use std::fs::*;
+use std::io::Read;
+use std::path::Path;
+
+use protobuf::descriptor::*;
+use protobuf::Message;
+use protobuf_codegen::*;
+
+fn write_file(bin: &str) {
+ let mut is = File::open(&Path::new(bin)).unwrap();
+ let fds = FileDescriptorSet::parse_from_reader(&mut is as &mut dyn Read).unwrap();
+
+ let file_names: Vec<String> = fds
+ .get_file()
+ .iter()
+ .map(|f| f.get_name().to_string())
+ .collect();
+ gen_and_write(
+ fds.get_file(),
+ &file_names,
+ Path::new("."),
+ &Default::default(),
+ )
+ .expect("gen_and_write");
+}
+
+fn main() {
+ let args: Vec<String> = std::env::args().collect();
+ if args.len() != 2 {
+ panic!("must have exactly one argument");
+ }
+ let ref pb_bin = args[1];
+ write_file(&pb_bin);
+}
diff --git a/2.27.1/src/bin/protoc-gen-rust.rs b/2.27.1/src/bin/protoc-gen-rust.rs
new file mode 100644
index 0000000..97ac7d2
--- /dev/null
+++ b/2.27.1/src/bin/protoc-gen-rust.rs
@@ -0,0 +1,5 @@
+extern crate protobuf_codegen;
+
+fn main() {
+ protobuf_codegen::protoc_gen_rust_main();
+}
diff --git a/2.27.1/src/code_writer.rs b/2.27.1/src/code_writer.rs
new file mode 100644
index 0000000..50eaeb8
--- /dev/null
+++ b/2.27.1/src/code_writer.rs
@@ -0,0 +1,387 @@
+// TODO: used by grpc-rust, should move it into separate crate.
+#![doc(hidden)]
+
+use std::io::Write;
+
+use inside::protobuf_crate_path;
+use Customize;
+
+/// Field visibility.
+pub enum Visibility {
+ Public,
+ Default,
+}
+
+pub struct CodeWriter<'a> {
+ writer: &'a mut (dyn Write + 'a),
+ indent: String,
+}
+
+impl<'a> CodeWriter<'a> {
+ pub fn new(writer: &'a mut dyn Write) -> CodeWriter<'a> {
+ CodeWriter {
+ writer: writer,
+ indent: "".to_string(),
+ }
+ }
+
+ pub fn write_line<S: AsRef<str>>(&mut self, line: S) {
+ (if line.as_ref().is_empty() {
+ self.writer.write_all("\n".as_bytes())
+ } else {
+ let s: String = [self.indent.as_ref(), line.as_ref(), "\n"].concat();
+ self.writer.write_all(s.as_bytes())
+ })
+ .unwrap();
+ }
+
+ pub fn write_generated(&mut self) {
+ self.write_line("// This file is generated. Do not edit");
+ self.write_generated_common();
+ }
+
+ pub fn write_generated_by(&mut self, pkg: &str, version: &str) {
+ self.write_line(format!(
+ "// This file is generated by {pkg} {version}. Do not edit",
+ pkg = pkg,
+ version = version
+ ));
+ self.write_generated_common();
+ }
+
+ fn write_generated_common(&mut self) {
+ // https://secure.phabricator.com/T784
+ self.write_line("// @generated");
+
+ self.write_line("");
+ self.comment("https://github.com/rust-lang/rust-clippy/issues/702");
+ self.write_line("#![allow(unknown_lints)]");
+ self.write_line("#![allow(clippy::all)]");
+ self.write_line("");
+ self.write_line("#![allow(unused_attributes)]");
+ self.write_line("#![cfg_attr(rustfmt, rustfmt::skip)]");
+ self.write_line("");
+ self.write_line("#![allow(box_pointers)]");
+ self.write_line("#![allow(dead_code)]");
+ self.write_line("#![allow(missing_docs)]");
+ self.write_line("#![allow(non_camel_case_types)]");
+ self.write_line("#![allow(non_snake_case)]");
+ self.write_line("#![allow(non_upper_case_globals)]");
+ self.write_line("#![allow(trivial_casts)]");
+ self.write_line("#![allow(unused_imports)]");
+ self.write_line("#![allow(unused_results)]");
+ }
+
+ pub fn todo(&mut self, message: &str) {
+ self.write_line(format!("panic!(\"TODO: {}\");", message));
+ }
+
+ pub fn unimplemented(&mut self) {
+ self.write_line(format!("unimplemented!();"));
+ }
+
+ pub fn indented<F>(&mut self, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ cb(&mut CodeWriter {
+ writer: self.writer,
+ indent: format!("{} ", self.indent),
+ });
+ }
+
+ #[allow(dead_code)]
+ pub fn commented<F>(&mut self, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ cb(&mut CodeWriter {
+ writer: self.writer,
+ indent: format!("// {}", self.indent),
+ });
+ }
+
+ pub fn pub_const(&mut self, name: &str, field_type: &str, init: &str) {
+ self.write_line(&format!("pub const {}: {} = {};", name, field_type, init));
+ }
+
+ pub fn lazy_static(&mut self, name: &str, ty: &str, customize: &Customize) {
+ self.write_line(&format!(
+ "static {}: {}::rt::LazyV2<{}> = {}::rt::LazyV2::INIT;",
+ name,
+ protobuf_crate_path(customize),
+ ty,
+ protobuf_crate_path(customize),
+ ));
+ }
+
+ pub fn lazy_static_decl_get<F>(&mut self, name: &str, ty: &str, customize: &Customize, init: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.lazy_static(name, ty, customize);
+ self.write_line(&format!("{}.get(|| {{", name));
+ self.indented(|w| init(w));
+ self.write_line(&format!("}})"));
+ }
+
+ pub fn lazy_static_decl_get_simple(
+ &mut self,
+ name: &str,
+ ty: &str,
+ init: &str,
+ customize: &Customize,
+ ) {
+ self.lazy_static(name, ty, customize);
+ self.write_line(&format!("{}.get({})", name, init));
+ }
+
+ pub fn block<F>(&mut self, first_line: &str, last_line: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.write_line(first_line);
+ self.indented(cb);
+ self.write_line(last_line);
+ }
+
+ pub fn expr_block<F>(&mut self, prefix: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.block(&format!("{} {{", prefix), "}", cb);
+ }
+
+ pub fn stmt_block<S: AsRef<str>, F>(&mut self, prefix: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.block(&format!("{} {{", prefix.as_ref()), "};", cb);
+ }
+
+ pub fn unsafe_expr<F>(&mut self, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block("unsafe", cb);
+ }
+
+ pub fn impl_self_block<S: AsRef<str>, F>(&mut self, name: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("impl {}", name.as_ref()), cb);
+ }
+
+ pub fn impl_for_block<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, tr: S1, ty: S2, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.impl_args_for_block(&[], tr.as_ref(), ty.as_ref(), cb);
+ }
+
+ pub fn impl_args_for_block<F>(&mut self, args: &[&str], tr: &str, ty: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ let args_str = if args.is_empty() {
+ "".to_owned()
+ } else {
+ format!("<{}>", args.join(", "))
+ };
+ self.expr_block(&format!("impl{} {} for {}", args_str, tr, ty), cb);
+ }
+
+ pub fn unsafe_impl(&mut self, what: &str, for_what: &str) {
+ self.write_line(&format!("unsafe impl {} for {} {{}}", what, for_what));
+ }
+
+ pub fn pub_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("pub struct {}", name.as_ref()), cb);
+ }
+
+ pub fn def_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("struct {}", name.as_ref()), cb);
+ }
+
+ pub fn pub_enum<F>(&mut self, name: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("pub enum {}", name), cb);
+ }
+
+ pub fn pub_trait<F>(&mut self, name: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("pub trait {}", name), cb);
+ }
+
+ pub fn pub_trait_extend<F>(&mut self, name: &str, extend: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("pub trait {} : {}", name, extend), cb);
+ }
+
+ pub fn field_entry(&mut self, name: &str, value: &str) {
+ self.write_line(&format!("{}: {},", name, value));
+ }
+
+ pub fn field_decl(&mut self, name: &str, field_type: &str) {
+ self.write_line(&format!("{}: {},", name, field_type));
+ }
+
+ pub fn pub_field_decl(&mut self, name: &str, field_type: &str) {
+ self.write_line(&format!("pub {}: {},", name, field_type));
+ }
+
+ pub fn field_decl_vis(&mut self, vis: Visibility, name: &str, field_type: &str) {
+ match vis {
+ Visibility::Public => self.pub_field_decl(name, field_type),
+ Visibility::Default => self.field_decl(name, field_type),
+ }
+ }
+
+ pub fn derive(&mut self, derive: &[&str]) {
+ let v: Vec<String> = derive.iter().map(|&s| s.to_string()).collect();
+ self.write_line(&format!("#[derive({})]", v.join(",")));
+ }
+
+ pub fn allow(&mut self, what: &[&str]) {
+ let v: Vec<String> = what.iter().map(|&s| s.to_string()).collect();
+ self.write_line(&format!("#[allow({})]", v.join(",")));
+ }
+
+ pub fn comment(&mut self, comment: &str) {
+ if comment.is_empty() {
+ self.write_line("//");
+ } else {
+ self.write_line(&format!("// {}", comment));
+ }
+ }
+
+ pub fn fn_def(&mut self, sig: &str) {
+ self.write_line(&format!("fn {};", sig));
+ }
+
+ pub fn fn_block<F>(&mut self, public: bool, sig: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ if public {
+ self.expr_block(&format!("pub fn {}", sig), cb);
+ } else {
+ self.expr_block(&format!("fn {}", sig), cb);
+ }
+ }
+
+ pub fn pub_fn<F>(&mut self, sig: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.fn_block(true, sig, cb);
+ }
+
+ pub fn def_fn<F>(&mut self, sig: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.fn_block(false, sig, cb);
+ }
+
+ pub fn def_mod<F>(&mut self, name: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("mod {}", name), cb)
+ }
+
+ pub fn pub_mod<F>(&mut self, name: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("pub mod {}", name), cb)
+ }
+
+ pub fn while_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("while {}", cond.as_ref()), cb);
+ }
+
+ // if ... { ... }
+ pub fn if_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("if {}", cond.as_ref()), cb);
+ }
+
+ // if ... {} else { ... }
+ pub fn if_else_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.write_line(&format!("if {} {{", cond.as_ref()));
+ self.write_line("} else {");
+ self.indented(cb);
+ self.write_line("}");
+ }
+
+ // if let ... = ... { ... }
+ pub fn if_let_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.if_stmt(&format!("let {} = {}", decl, expr), cb);
+ }
+
+ // if let ... = ... { } else { ... }
+ pub fn if_let_else_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.if_else_stmt(&format!("let {} = {}", decl, expr), cb);
+ }
+
+ pub fn for_stmt<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, over: S1, varn: S2, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.stmt_block(&format!("for {} in {}", varn.as_ref(), over.as_ref()), cb)
+ }
+
+ pub fn match_block<S: AsRef<str>, F>(&mut self, value: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.stmt_block(&format!("match {}", value.as_ref()), cb);
+ }
+
+ pub fn match_expr<S: AsRef<str>, F>(&mut self, value: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.expr_block(&format!("match {}", value.as_ref()), cb);
+ }
+
+ pub fn case_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ self.block(&format!("{} => {{", cond.as_ref()), "},", cb);
+ }
+
+ pub fn case_expr<S1: AsRef<str>, S2: AsRef<str>>(&mut self, cond: S1, body: S2) {
+ self.write_line(&format!("{} => {},", cond.as_ref(), body.as_ref()));
+ }
+}
diff --git a/2.27.1/src/customize.rs b/2.27.1/src/customize.rs
new file mode 100644
index 0000000..b3415ab
--- /dev/null
+++ b/2.27.1/src/customize.rs
@@ -0,0 +1,237 @@
+use protobuf::descriptor::EnumOptions;
+use protobuf::descriptor::FieldOptions;
+use protobuf::descriptor::FileOptions;
+use protobuf::descriptor::MessageOptions;
+use protobuf::rustproto;
+
+/// Specifies style of generated code.
+#[derive(Default, Debug, Clone)]
+pub struct Customize {
+ /// Make oneof enum public.
+ pub expose_oneof: Option<bool>,
+ /// When true all fields are public, and accessors are not generated
+ pub expose_fields: Option<bool>,
+ /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated
+ pub generate_accessors: Option<bool>,
+ /// Use `bytes::Bytes` for `bytes` fields
+ pub carllerche_bytes_for_bytes: Option<bool>,
+ /// Use `bytes::Bytes` for `string` fields
+ pub carllerche_bytes_for_string: Option<bool>,
+ /// Implement serde_derive for messages
+ pub serde_derive: Option<bool>,
+ /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
+ pub serde_derive_cfg: Option<String>,
+ /// When `serde_derive` is set, use attribute rename_all
+ pub serde_rename_all: Option<String>,
+ /// Enable lite runtime
+ pub lite_runtime: Option<bool>,
+ /// Generate `mod.rs` in the output directory.
+ ///
+ /// This option allows inclusion of generated files from cargo output directory.
+ ///
+ /// This option will likely be on by default in rust-protobuf version 3.
+ pub gen_mod_rs: Option<bool>,
+ /// Used internally to generate protos bundled in protobuf crate
+ /// like `descriptor.proto`
+ pub inside_protobuf: Option<bool>,
+
+ // When adding more options please keep in sync with `parse_from_parameter` below.
+ /// Make sure `Customize` is always used with `..Default::default()`
+ /// for future compatibility.
+ pub _future_options: (),
+}
+
+#[derive(Debug)]
+pub enum CustomizeParseParameterError {
+ EqNotFound,
+ CannotParseBool,
+ UnknownOptionName(String),
+}
+
+pub type CustomizeParseParameterResult<T> = Result<T, CustomizeParseParameterError>;
+
+impl Customize {
+ /// Update fields of self with fields defined in other customize
+ pub fn update_with(&mut self, that: &Customize) {
+ if let Some(v) = that.expose_oneof {
+ self.expose_oneof = Some(v);
+ }
+ if let Some(v) = that.expose_fields {
+ self.expose_fields = Some(v);
+ }
+ if let Some(v) = that.generate_accessors {
+ self.generate_accessors = Some(v);
+ }
+ if let Some(v) = that.carllerche_bytes_for_bytes {
+ self.carllerche_bytes_for_bytes = Some(v);
+ }
+ if let Some(v) = that.carllerche_bytes_for_string {
+ self.carllerche_bytes_for_string = Some(v);
+ }
+ if let Some(v) = that.serde_derive {
+ self.serde_derive = Some(v);
+ }
+ if let Some(ref v) = that.serde_derive_cfg {
+ self.serde_derive_cfg = Some(v.clone());
+ }
+ if let Some(ref v) = that.serde_rename_all {
+ self.serde_rename_all = Some(v.clone());
+ }
+ if let Some(v) = that.lite_runtime {
+ self.lite_runtime = Some(v);
+ }
+ if let Some(v) = that.gen_mod_rs {
+ self.gen_mod_rs = Some(v);
+ }
+ if let Some(v) = that.inside_protobuf {
+ self.inside_protobuf = Some(v);
+ }
+ }
+
+ /// Update unset fields of self with fields from other customize
+ pub fn set_defaults_from(&mut self, other: &Customize) {
+ let mut tmp = other.clone();
+ tmp.update_with(self);
+ *self = tmp;
+ }
+
+ /// Parse customize options from a string passed via protoc flag.
+ pub fn parse_from_parameter(parameter: &str) -> CustomizeParseParameterResult<Customize> {
+ fn parse_bool(v: &str) -> CustomizeParseParameterResult<bool> {
+ v.parse()
+ .map_err(|_| CustomizeParseParameterError::CannotParseBool)
+ }
+
+ let mut r = Customize::default();
+ for nv in parameter.split_whitespace() {
+ let eq = match nv.find('=') {
+ Some(eq) => eq,
+ None => return Err(CustomizeParseParameterError::EqNotFound),
+ };
+
+ let n = &nv[..eq];
+ let v = &nv[eq + 1..];
+
+ if n == "expose_oneof" {
+ r.expose_oneof = Some(parse_bool(v)?);
+ } else if n == "expose_fields" {
+ r.expose_fields = Some(parse_bool(v)?);
+ } else if n == "generate_accessors" {
+ r.generate_accessors = Some(parse_bool(v)?);
+ } else if n == "carllerche_bytes_for_bytes" {
+ r.carllerche_bytes_for_bytes = Some(parse_bool(v)?);
+ } else if n == "carllerche_bytes_for_string" {
+ r.carllerche_bytes_for_string = Some(parse_bool(v)?);
+ } else if n == "serde_derive" {
+ r.serde_derive = Some(parse_bool(v)?);
+ } else if n == "serde_derive_cfg" {
+ r.serde_derive_cfg = Some(v.to_owned());
+ } else if n == "serde_rename_all" {
+ r.serde_rename_all = Some(v.to_owned());
+ } else if n == "lite_runtime" {
+ r.lite_runtime = Some(parse_bool(v)?);
+ } else if n == "gen_mod_rs" {
+ r.gen_mod_rs = Some(parse_bool(v)?);
+ } else if n == "inside_protobuf" {
+ r.inside_protobuf = Some(parse_bool(v)?);
+ } else {
+ return Err(CustomizeParseParameterError::UnknownOptionName(
+ n.to_owned(),
+ ));
+ }
+ }
+ Ok(r)
+ }
+}
+
+pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customize {
+ let expose_oneof = rustproto::exts::expose_oneof.get(source);
+ let expose_fields = rustproto::exts::expose_fields.get(source);
+ let generate_accessors = rustproto::exts::generate_accessors.get(source);
+ let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes.get(source);
+ let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string.get(source);
+ let serde_derive = rustproto::exts::serde_derive.get(source);
+ let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
+ let lite_runtime = None;
+ let gen_mod_rs = None;
+ let inside_protobuf = None;
+ let serde_rename_all = None;
+ Customize {
+ expose_oneof,
+ expose_fields,
+ generate_accessors,
+ carllerche_bytes_for_bytes,
+ carllerche_bytes_for_string,
+ serde_derive,
+ serde_derive_cfg,
+ serde_rename_all,
+ lite_runtime,
+ gen_mod_rs,
+ inside_protobuf,
+ _future_options: (),
+ }
+}
+
+pub fn customize_from_rustproto_for_enum(source: &EnumOptions) -> Customize {
+ let serde_rename_all = rustproto::exts::serde_rename_all.get(source);
+ let mut r = Customize::default();
+ r.serde_rename_all = serde_rename_all;
+ return r;
+}
+
+pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
+ let expose_oneof = None;
+ let expose_fields = rustproto::exts::expose_fields_field.get(source);
+ let generate_accessors = rustproto::exts::generate_accessors_field.get(source);
+ let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_field.get(source);
+ let carllerche_bytes_for_string =
+ rustproto::exts::carllerche_bytes_for_string_field.get(source);
+ let serde_rename_all = None;
+ let serde_derive = None;
+ let serde_derive_cfg = None;
+ let lite_runtime = None;
+ let gen_mod_rs = None;
+ let inside_protobuf = None;
+ Customize {
+ expose_oneof,
+ expose_fields,
+ generate_accessors,
+ carllerche_bytes_for_bytes,
+ carllerche_bytes_for_string,
+ serde_derive,
+ serde_derive_cfg,
+ serde_rename_all,
+ lite_runtime,
+ gen_mod_rs,
+ inside_protobuf,
+ _future_options: (),
+ }
+}
+
+pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
+ let expose_oneof = rustproto::exts::expose_oneof_all.get(source);
+ let expose_fields = rustproto::exts::expose_fields_all.get(source);
+ let generate_accessors = rustproto::exts::generate_accessors_all.get(source);
+ let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_all.get(source);
+ let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string_all.get(source);
+ let serde_derive = rustproto::exts::serde_derive_all.get(source);
+ let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
+ let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
+ let gen_mod_rs = None;
+ let inside_protobuf = None;
+ let serde_rename_all = None;
+ Customize {
+ expose_oneof,
+ expose_fields,
+ generate_accessors,
+ carllerche_bytes_for_bytes,
+ carllerche_bytes_for_string,
+ serde_derive,
+ serde_derive_cfg,
+ serde_rename_all,
+ lite_runtime,
+ inside_protobuf,
+ gen_mod_rs,
+ _future_options: (),
+ }
+}
diff --git a/2.27.1/src/enums.rs b/2.27.1/src/enums.rs
new file mode 100644
index 0000000..ec3444e
--- /dev/null
+++ b/2.27.1/src/enums.rs
@@ -0,0 +1,377 @@
+use std::collections::HashSet;
+
+use file_descriptor::file_descriptor_proto_expr;
+use inside::protobuf_crate_path;
+use protobuf::descriptor::*;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_types_values::type_name_to_rust_relative;
+use scope::EnumWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+use CodeWriter;
+
+use crate::customize::customize_from_rustproto_for_enum;
+use crate::Customize;
+
+#[derive(Clone)]
+pub struct EnumValueGen {
+ proto: EnumValueDescriptorProto,
+ enum_rust_name: String,
+ variant_rust_name: String,
+}
+
+impl EnumValueGen {
+ fn parse(
+ proto: &EnumValueDescriptorProto,
+ enum_rust_name: &str,
+ variant_rust_name: &str,
+ ) -> EnumValueGen {
+ EnumValueGen {
+ proto: proto.clone(),
+ enum_rust_name: enum_rust_name.to_string(),
+ variant_rust_name: variant_rust_name.to_string(),
+ }
+ }
+
+ // enum value
+ fn number(&self) -> i32 {
+ self.proto.get_number()
+ }
+
+ // name of enum variant in generated rust code
+ fn rust_name_inner(&self) -> String {
+ self.variant_rust_name.clone()
+ }
+
+ pub fn rust_name_outer(&self) -> String {
+ let mut r = String::new();
+ r.push_str(&self.enum_rust_name);
+ r.push_str("::");
+ r.push_str(&self.rust_name_inner());
+ r
+ }
+}
+
+pub(crate) struct EnumGen<'a> {
+ enum_with_scope: &'a EnumWithScope<'a>,
+ type_name: String,
+ lite_runtime: bool,
+ customize: Customize,
+}
+
+impl<'a> EnumGen<'a> {
+ pub fn new(
+ enum_with_scope: &'a EnumWithScope<'a>,
+ current_file: &FileDescriptorProto,
+ customize: &Customize,
+ root_scope: &RootScope,
+ ) -> EnumGen<'a> {
+ let rust_name = if enum_with_scope.get_scope().get_file_descriptor().get_name()
+ == current_file.get_name()
+ {
+ // field type is a message or enum declared in the same file
+ enum_with_scope.rust_name().to_string()
+ } else {
+ type_name_to_rust_relative(
+ &ProtobufAbsolutePath::from(enum_with_scope.name_absolute()),
+ current_file,
+ false,
+ root_scope,
+ customize,
+ )
+ .to_string()
+ };
+ let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+ enum_with_scope
+ .get_scope()
+ .get_file_descriptor()
+ .get_options()
+ .get_optimize_for()
+ == FileOptions_OptimizeMode::LITE_RUNTIME
+ });
+
+ let mut customize = customize.clone();
+ customize.update_with(&customize_from_rustproto_for_enum(
+ enum_with_scope.en.options.as_ref().unwrap_or_default(),
+ ));
+
+ EnumGen {
+ enum_with_scope,
+ type_name: rust_name,
+ lite_runtime,
+ customize,
+ }
+ }
+
+ fn allow_alias(&self) -> bool {
+ self.enum_with_scope.en.get_options().get_allow_alias()
+ }
+
+ fn values_all(&self) -> Vec<EnumValueGen> {
+ let mut r = Vec::new();
+ for p in self.enum_with_scope.values() {
+ r.push(EnumValueGen::parse(
+ &p.proto,
+ &self.type_name,
+ p.rust_name().get(),
+ ));
+ }
+ r
+ }
+
+ pub fn values_unique(&self) -> Vec<EnumValueGen> {
+ let mut used = HashSet::new();
+ let mut r = Vec::new();
+ for p in self.enum_with_scope.values() {
+ // skipping non-unique enums
+ // TODO: should support it
+ if !used.insert(p.proto.get_number()) {
+ continue;
+ }
+ r.push(EnumValueGen::parse(
+ p.proto,
+ &self.type_name,
+ p.rust_name().get(),
+ ));
+ }
+ r
+ }
+
+ // find enum value by name
+ pub fn value_by_name(&'a self, name: &str) -> EnumValueGen {
+ let v = self.enum_with_scope.value_by_name(name);
+ EnumValueGen::parse(v.proto, &self.type_name, v.rust_name().get())
+ }
+
+ pub fn write(&self, w: &mut CodeWriter) {
+ self.write_struct(w);
+ if self.allow_alias() {
+ w.write_line("");
+ self.write_impl_eq(w);
+ w.write_line("");
+ self.write_impl_hash(w);
+ }
+ w.write_line("");
+ self.write_impl_enum(w);
+ w.write_line("");
+ self.write_impl_copy(w);
+ w.write_line("");
+ self.write_impl_default(w);
+ w.write_line("");
+ self.write_impl_value(w);
+ }
+
+ fn write_struct(&self, w: &mut CodeWriter) {
+ let mut derive = Vec::new();
+ derive.push("Clone");
+ if !self.allow_alias() {
+ derive.push("PartialEq");
+ }
+ derive.push("Eq");
+ derive.push("Debug");
+ if !self.allow_alias() {
+ derive.push("Hash");
+ } else {
+ w.comment("Note: you cannot use pattern matching for enums with allow_alias option");
+ }
+ w.derive(&derive);
+ serde::write_serde_attr(
+ w,
+ &self.customize,
+ "derive(::serde::Serialize, ::serde::Deserialize)",
+ );
+ if let Some(ref ren) = self.customize.serde_rename_all {
+ let attr = format!("serde(rename_all = \"{}\")", ren);
+ serde::write_serde_attr(w, &self.customize, &attr);
+ }
+ let ref type_name = self.type_name;
+ w.expr_block(&format!("pub enum {}", type_name), |w| {
+ for value in self.values_all() {
+ if self.allow_alias() {
+ w.write_line(&format!(
+ "{}, // {}",
+ value.rust_name_inner(),
+ value.number()
+ ));
+ } else {
+ w.write_line(&format!(
+ "{} = {},",
+ value.rust_name_inner(),
+ value.number()
+ ));
+ }
+ }
+ });
+ }
+
+ fn write_fn_value(&self, w: &mut CodeWriter) {
+ w.def_fn("value(&self) -> i32", |w| {
+ if self.allow_alias() {
+ w.match_expr("*self", |w| {
+ for value in self.values_all() {
+ w.case_expr(value.rust_name_outer(), format!("{}", value.number()));
+ }
+ });
+ } else {
+ w.write_line("*self as i32")
+ }
+ });
+ }
+
+ fn write_impl_enum(&self, w: &mut CodeWriter) {
+ let ref type_name = self.type_name;
+ w.impl_for_block(
+ &format!("{}::ProtobufEnum", protobuf_crate_path(&self.customize)),
+ &format!("{}", type_name),
+ |w| {
+ self.write_fn_value(w);
+
+ w.write_line("");
+ let ref type_name = self.type_name;
+ w.def_fn(
+ &format!(
+ "from_i32(value: i32) -> ::std::option::Option<{}>",
+ type_name
+ ),
+ |w| {
+ w.match_expr("value", |w| {
+ let values = self.values_unique();
+ for value in values {
+ w.write_line(&format!(
+ "{} => ::std::option::Option::Some({}),",
+ value.number(),
+ value.rust_name_outer()
+ ));
+ }
+ w.write_line(&format!("_ => ::std::option::Option::None"));
+ });
+ },
+ );
+
+ w.write_line("");
+ w.def_fn(&format!("values() -> &'static [Self]"), |w| {
+ w.write_line(&format!("static values: &'static [{}] = &[", type_name));
+ w.indented(|w| {
+ for value in self.values_all() {
+ w.write_line(&format!("{},", value.rust_name_outer()));
+ }
+ });
+ w.write_line("];");
+ w.write_line("values");
+ });
+
+ if !self.lite_runtime {
+ w.write_line("");
+ w.def_fn(
+ &format!(
+ "enum_descriptor_static() -> &'static {}::reflect::EnumDescriptor",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.lazy_static_decl_get(
+ "descriptor",
+ &format!(
+ "{}::reflect::EnumDescriptor",
+ protobuf_crate_path(&self.customize)
+ ),
+ &self.customize,
+ |w| {
+ let ref type_name = self.type_name;
+ w.write_line(&format!(
+ "{}::reflect::EnumDescriptor::new_pb_name::<{}>(\"{}\", {})",
+ protobuf_crate_path(&self.customize),
+ type_name,
+ self.enum_with_scope.name_to_package(),
+ file_descriptor_proto_expr(&self.enum_with_scope.scope)
+ ));
+ },
+ );
+ },
+ );
+ }
+ },
+ );
+ }
+
+ fn write_impl_value(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!(
+ "{}::reflect::ProtobufValue",
+ protobuf_crate_path(&self.customize)
+ ),
+ &format!("{}", self.type_name),
+ |w| {
+ w.def_fn(
+ &format!(
+ "as_ref(&self) -> {}::reflect::ReflectValueRef",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line(&format!(
+ "{}::reflect::ReflectValueRef::Enum({}::ProtobufEnum::descriptor(self))",
+ protobuf_crate_path(&self.customize),
+ protobuf_crate_path(&self.customize)
+ ))
+ },
+ )
+ },
+ )
+ }
+
+ fn write_impl_copy(&self, w: &mut CodeWriter) {
+ w.impl_for_block("::std::marker::Copy", &self.type_name, |_w| {});
+ }
+
+ fn write_impl_eq(&self, w: &mut CodeWriter) {
+ assert!(self.allow_alias());
+ w.impl_for_block(
+ "::std::cmp::PartialEq",
+ &format!("{}", self.type_name),
+ |w| {
+ w.def_fn("eq(&self, other: &Self) -> bool", |w| {
+ w.write_line(&format!(
+ "{}::ProtobufEnum::value(self) == {}::ProtobufEnum::value(other)",
+ protobuf_crate_path(&self.customize),
+ protobuf_crate_path(&self.customize)
+ ));
+ });
+ },
+ );
+ }
+
+ fn write_impl_hash(&self, w: &mut CodeWriter) {
+ assert!(self.allow_alias());
+ w.impl_for_block("::std::hash::Hash", &format!("{}", self.type_name), |w| {
+ w.def_fn("hash<H : ::std::hash::Hasher>(&self, state: &mut H)", |w| {
+ w.write_line(&format!(
+ "state.write_i32({}::ProtobufEnum::value(self))",
+ protobuf_crate_path(&self.customize)
+ ));
+ });
+ });
+ }
+
+ fn write_impl_default(&self, w: &mut CodeWriter) {
+ let first_value = &self.enum_with_scope.values()[0];
+ if first_value.proto.get_number() != 0 {
+ // This warning is emitted only for proto2
+ // (because in proto3 first enum variant number is always 0).
+ // `Default` implemented unconditionally to simplify certain
+ // generic operations, e. g. reading a map.
+ // Also, note that even in proto2 some operations fallback to
+ // first enum value, e. g. `get_xxx` for unset field,
+ // so this implementation is not completely unreasonable.
+ w.comment("Note, `Default` is implemented although default value is not 0");
+ }
+ w.impl_for_block("::std::default::Default", &self.type_name, |w| {
+ w.def_fn("default() -> Self", |w| {
+ w.write_line(&format!(
+ "{}::{}",
+ &self.type_name,
+ &first_value.rust_name()
+ ))
+ });
+ });
+ }
+}
diff --git a/2.27.1/src/extensions.rs b/2.27.1/src/extensions.rs
new file mode 100644
index 0000000..def5948
--- /dev/null
+++ b/2.27.1/src/extensions.rs
@@ -0,0 +1,116 @@
+use field::rust_field_name_for_protobuf_field_name;
+use inside::protobuf_crate_path;
+use protobuf::descriptor::*;
+use protobuf_name::ProtobufAbsolutePath;
+use scope::RootScope;
+use Customize;
+
+use super::code_writer::CodeWriter;
+use super::rust_types_values::*;
+
+struct ExtGen<'a> {
+ file: &'a FileDescriptorProto,
+ root_scope: &'a RootScope<'a>,
+ field: &'a FieldDescriptorProto,
+ customize: Customize,
+}
+
+impl<'a> ExtGen<'a> {
+ fn extendee_rust_name(&self) -> String {
+ type_name_to_rust_relative(
+ &ProtobufAbsolutePath::from(self.field.get_extendee()),
+ self.file,
+ true,
+ self.root_scope,
+ &self.customize,
+ )
+ }
+
+ fn repeated(&self) -> bool {
+ match self.field.get_label() {
+ FieldDescriptorProto_Label::LABEL_REPEATED => true,
+ FieldDescriptorProto_Label::LABEL_OPTIONAL => false,
+ FieldDescriptorProto_Label::LABEL_REQUIRED => {
+ panic!("required ext field: {}", self.field.get_name())
+ }
+ }
+ }
+
+ fn return_type_gen(&self) -> ProtobufTypeGen {
+ if self.field.has_type_name() {
+ let rust_name_relative = type_name_to_rust_relative(
+ &ProtobufAbsolutePath::from(self.field.get_type_name()),
+ self.file,
+ true,
+ self.root_scope,
+ &self.customize,
+ );
+ match self.field.get_field_type() {
+ FieldDescriptorProto_Type::TYPE_MESSAGE => {
+ ProtobufTypeGen::Message(rust_name_relative)
+ }
+ FieldDescriptorProto_Type::TYPE_ENUM => ProtobufTypeGen::Enum(rust_name_relative),
+ t => panic!("unknown type: {:?}", t),
+ }
+ } else {
+ ProtobufTypeGen::Primitive(self.field.get_field_type(), PrimitiveTypeVariant::Default)
+ }
+ }
+
+ fn write(&self, w: &mut CodeWriter) {
+ let suffix = if self.repeated() {
+ "Repeated"
+ } else {
+ "Optional"
+ };
+ let field_type = format!(
+ "{}::ext::ExtField{}",
+ protobuf_crate_path(&self.customize),
+ suffix
+ );
+ w.pub_const(
+ rust_field_name_for_protobuf_field_name(self.field.get_name()).get(),
+ &format!(
+ "{}<{}, {}>",
+ field_type,
+ self.extendee_rust_name(),
+ self.return_type_gen().rust_type(&self.customize),
+ ),
+ &format!(
+ "{} {{ field_number: {}, phantom: ::std::marker::PhantomData }}",
+ field_type,
+ self.field.get_number()
+ ),
+ );
+ }
+}
+
+pub(crate) fn write_extensions(
+ file: &FileDescriptorProto,
+ root_scope: &RootScope,
+ w: &mut CodeWriter,
+ customize: &Customize,
+) {
+ if file.get_extension().is_empty() {
+ return;
+ }
+
+ w.write_line("");
+ w.write_line("/// Extension fields");
+ w.pub_mod("exts", |w| {
+ for field in file.get_extension() {
+ if field.get_field_type() == FieldDescriptorProto_Type::TYPE_GROUP {
+ continue;
+ }
+
+ w.write_line("");
+ ExtGen {
+ file: file,
+ root_scope: root_scope,
+ field: field,
+ customize: customize.clone(),
+ }
+ .write(w);
+ }
+ });
+}
diff --git a/2.27.1/src/field/mod.rs b/2.27.1/src/field/mod.rs
new file mode 100644
index 0000000..e4be944
--- /dev/null
+++ b/2.27.1/src/field/mod.rs
@@ -0,0 +1,2031 @@
+use std::marker;
+
+use float;
+use inside::protobuf_crate_path;
+use message::RustTypeMessage;
+use oneof::OneofField;
+use protobuf::descriptor::*;
+use protobuf::rt;
+use protobuf::rust;
+use protobuf::text_format;
+use protobuf::wire_format;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_name::RustIdent;
+use rust_name::RustIdentWithPath;
+use scope::FieldWithContext;
+use scope::MessageOrEnumWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use syntax::Syntax;
+
+use super::code_writer::CodeWriter;
+use super::customize::customize_from_rustproto_for_field;
+use super::customize::Customize;
+use super::enums::*;
+use super::rust_types_values::*;
+
+fn type_is_copy(field_type: FieldDescriptorProto_Type) -> bool {
+ match field_type {
+ FieldDescriptorProto_Type::TYPE_MESSAGE
+ | FieldDescriptorProto_Type::TYPE_STRING
+ | FieldDescriptorProto_Type::TYPE_BYTES => false,
+ _ => true,
+ }
+}
+
+trait FieldDescriptorProtoTypeExt {
+ fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String;
+ fn is_s_varint(&self) -> bool;
+}
+
+impl FieldDescriptorProtoTypeExt for FieldDescriptorProto_Type {
+ fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String {
+ match primitive_type_variant {
+ PrimitiveTypeVariant::Default => format!("{}.read_{}()", is, protobuf_name(*self)),
+ PrimitiveTypeVariant::Carllerche => {
+ let protobuf_name = match self {
+ &FieldDescriptorProto_Type::TYPE_STRING => "chars",
+ _ => protobuf_name(*self),
+ };
+ format!("{}.read_carllerche_{}()", is, protobuf_name)
+ }
+ }
+ }
+
+ /// True if self is signed integer with zigzag encoding
+ fn is_s_varint(&self) -> bool {
+ match *self {
+ FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true,
+ _ => false,
+ }
+ }
+}
+
+fn field_type_wire_type(field_type: FieldDescriptorProto_Type) -> wire_format::WireType {
+ use protobuf::wire_format::*;
+ match field_type {
+ FieldDescriptorProto_Type::TYPE_INT32 => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_INT64 => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_UINT32 => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_UINT64 => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_SINT32 => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_SINT64 => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_BOOL => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_ENUM => WireTypeVarint,
+ FieldDescriptorProto_Type::TYPE_FIXED32 => WireTypeFixed32,
+ FieldDescriptorProto_Type::TYPE_FIXED64 => WireTypeFixed64,
+ FieldDescriptorProto_Type::TYPE_SFIXED32 => WireTypeFixed32,
+ FieldDescriptorProto_Type::TYPE_SFIXED64 => WireTypeFixed64,
+ FieldDescriptorProto_Type::TYPE_FLOAT => WireTypeFixed32,
+ FieldDescriptorProto_Type::TYPE_DOUBLE => WireTypeFixed64,
+ FieldDescriptorProto_Type::TYPE_STRING => WireTypeLengthDelimited,
+ FieldDescriptorProto_Type::TYPE_BYTES => WireTypeLengthDelimited,
+ FieldDescriptorProto_Type::TYPE_MESSAGE => WireTypeLengthDelimited,
+ FieldDescriptorProto_Type::TYPE_GROUP => WireTypeLengthDelimited, // not true
+ }
+}
+
+fn type_protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str {
+ match field_type {
+ FieldDescriptorProto_Type::TYPE_INT32 => "int32",
+ FieldDescriptorProto_Type::TYPE_INT64 => "int64",
+ FieldDescriptorProto_Type::TYPE_UINT32 => "uint32",
+ FieldDescriptorProto_Type::TYPE_UINT64 => "uint64",
+ FieldDescriptorProto_Type::TYPE_SINT32 => "sint32",
+ FieldDescriptorProto_Type::TYPE_SINT64 => "sint64",
+ FieldDescriptorProto_Type::TYPE_BOOL => "bool",
+ FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32",
+ FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64",
+ FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32",
+ FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64",
+ FieldDescriptorProto_Type::TYPE_FLOAT => "float",
+ FieldDescriptorProto_Type::TYPE_DOUBLE => "double",
+ FieldDescriptorProto_Type::TYPE_STRING => "string",
+ FieldDescriptorProto_Type::TYPE_BYTES => "bytes",
+ FieldDescriptorProto_Type::TYPE_ENUM
+ | FieldDescriptorProto_Type::TYPE_MESSAGE
+ | FieldDescriptorProto_Type::TYPE_GROUP => panic!(),
+ }
+}
+
+fn field_type_protobuf_name<'a>(field: &'a FieldDescriptorProto) -> &'a str {
+ if field.has_type_name() {
+ field.get_type_name()
+ } else {
+ type_protobuf_name(field.get_field_type())
+ }
+}
+
+// size of value for type, None if variable
+fn field_type_size(field_type: FieldDescriptorProto_Type) -> Option<u32> {
+ match field_type {
+ FieldDescriptorProto_Type::TYPE_BOOL => Some(1),
+ t if field_type_wire_type(t) == wire_format::WireTypeFixed32 => Some(4),
+ t if field_type_wire_type(t) == wire_format::WireTypeFixed64 => Some(8),
+ _ => None,
+ }
+}
+
+#[derive(Clone, PartialEq, Eq)]
+pub enum SingularFieldFlag {
+ // proto2 or proto3 message
+ WithFlag { required: bool },
+ // proto3
+ WithoutFlag,
+}
+
+impl SingularFieldFlag {
+ pub fn is_required(&self) -> bool {
+ match *self {
+ SingularFieldFlag::WithFlag { required, .. } => required,
+ SingularFieldFlag::WithoutFlag => false,
+ }
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct SingularField<'a> {
+ pub flag: SingularFieldFlag,
+ pub elem: FieldElem<'a>,
+}
+
+impl<'a> SingularField<'a> {
+ fn rust_storage_type(&self) -> RustType {
+ match self.flag {
+ SingularFieldFlag::WithFlag { .. } => match self.elem.proto_type() {
+ FieldDescriptorProto_Type::TYPE_MESSAGE => {
+ RustType::SingularPtrField(Box::new(self.elem.rust_storage_type()))
+ }
+ FieldDescriptorProto_Type::TYPE_STRING | FieldDescriptorProto_Type::TYPE_BYTES
+ if self.elem.primitive_type_variant() == PrimitiveTypeVariant::Default =>
+ {
+ RustType::SingularField(Box::new(self.elem.rust_storage_type()))
+ }
+ _ => RustType::Option(Box::new(self.elem.rust_storage_type())),
+ },
+ SingularFieldFlag::WithoutFlag => self.elem.rust_storage_type(),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct RepeatedField<'a> {
+ pub elem: FieldElem<'a>,
+ pub packed: bool,
+}
+
+impl<'a> RepeatedField<'a> {
+ fn rust_type(&self) -> RustType {
+ if !self.elem.is_copy()
+ && self.elem.primitive_type_variant() != PrimitiveTypeVariant::Carllerche
+ {
+ RustType::RepeatedField(Box::new(self.elem.rust_storage_type()))
+ } else {
+ RustType::Vec(Box::new(self.elem.rust_storage_type()))
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct MapField<'a> {
+ _name: String,
+ key: FieldElem<'a>,
+ value: FieldElem<'a>,
+}
+
+#[derive(Clone)]
+pub(crate) enum FieldKind<'a> {
+ // optional or required
+ Singular(SingularField<'a>),
+ // repeated except map
+ Repeated(RepeatedField<'a>),
+ // map
+ Map(MapField<'a>),
+ // part of oneof
+ Oneof(OneofField<'a>),
+}
+
+impl<'a> FieldKind<'a> {
+ fn elem(&self) -> &FieldElem {
+ match self {
+ &FieldKind::Singular(ref s) => &s.elem,
+ &FieldKind::Repeated(ref r) => &r.elem,
+ &FieldKind::Oneof(ref o) => &o.elem,
+ &FieldKind::Map(..) => {
+ panic!("no single elem type for map field");
+ }
+ }
+ }
+
+ fn primitive_type_variant(&self) -> PrimitiveTypeVariant {
+ self.elem().primitive_type_variant()
+ }
+}
+
+// Representation of map entry: key type and value type
+#[derive(Clone, Debug)]
+pub struct EntryKeyValue<'a>(FieldElem<'a>, FieldElem<'a>);
+
+#[derive(Clone, Debug)]
+pub(crate) enum FieldElem<'a> {
+ Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant),
+ // name, file name, entry
+ Message(
+ String,
+ String,
+ Option<Box<EntryKeyValue<'a>>>,
+ marker::PhantomData<&'a ()>,
+ ),
+ // name, file name, default value
+ Enum(String, String, RustIdent),
+ Group,
+}
+
+impl<'a> FieldElem<'a> {
+ fn proto_type(&self) -> FieldDescriptorProto_Type {
+ match *self {
+ FieldElem::Primitive(t, ..) => t,
+ FieldElem::Group => FieldDescriptorProto_Type::TYPE_GROUP,
+ FieldElem::Message(..) => FieldDescriptorProto_Type::TYPE_MESSAGE,
+ FieldElem::Enum(..) => FieldDescriptorProto_Type::TYPE_ENUM,
+ }
+ }
+
+ fn is_copy(&self) -> bool {
+ type_is_copy(self.proto_type())
+ }
+
+ pub fn rust_storage_type(&self) -> RustType {
+ match *self {
+ FieldElem::Primitive(t, PrimitiveTypeVariant::Default) => rust_name(t),
+ FieldElem::Primitive(
+ FieldDescriptorProto_Type::TYPE_STRING,
+ PrimitiveTypeVariant::Carllerche,
+ ) => RustType::Chars,
+ FieldElem::Primitive(
+ FieldDescriptorProto_Type::TYPE_BYTES,
+ PrimitiveTypeVariant::Carllerche,
+ ) => RustType::Bytes,
+ FieldElem::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(),
+ FieldElem::Group => RustType::Group,
+ FieldElem::Message(ref name, ..) => {
+ RustType::Message(RustTypeMessage(RustIdentWithPath::new(name.clone())))
+ }
+ FieldElem::Enum(ref name, _, ref default_value) => {
+ RustType::Enum(name.clone(), default_value.clone())
+ }
+ }
+ }
+
+ fn protobuf_type_gen(&self) -> ProtobufTypeGen {
+ match *self {
+ FieldElem::Primitive(t, v) => ProtobufTypeGen::Primitive(t, v),
+ FieldElem::Message(ref name, ..) => ProtobufTypeGen::Message(name.clone()),
+ FieldElem::Enum(ref name, ..) => ProtobufTypeGen::Enum(name.clone()),
+ FieldElem::Group => unreachable!(),
+ }
+ }
+
+ /// implementation of ProtobufType trait
+ fn lib_protobuf_type(&self, customize: &Customize) -> String {
+ self.protobuf_type_gen().rust_type(customize)
+ }
+
+ fn primitive_type_variant(&self) -> PrimitiveTypeVariant {
+ match self {
+ &FieldElem::Primitive(_, v) => v,
+ _ => PrimitiveTypeVariant::Default,
+ }
+ }
+}
+
+fn field_elem<'a>(
+ field: &FieldWithContext,
+ root_scope: &'a RootScope<'a>,
+ parse_map: bool,
+ customize: &Customize,
+) -> (FieldElem<'a>, Option<EnumValueGen>) {
+ if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_GROUP {
+ (FieldElem::Group, None)
+ } else if field.field.has_type_name() {
+ let message_or_enum = root_scope
+ .find_message_or_enum(&ProtobufAbsolutePath::from(field.field.get_type_name()));
+ let file_name = message_or_enum
+ .get_scope()
+ .file_scope
+ .file_descriptor
+ .get_name()
+ .to_owned();
+ let rust_relative_name = type_name_to_rust_relative(
+ &ProtobufAbsolutePath::from(field.field.get_type_name()),
+ field.message.get_scope().file_scope.file_descriptor,
+ false,
+ root_scope,
+ customize,
+ );
+ match (field.field.get_field_type(), message_or_enum) {
+ (
+ FieldDescriptorProto_Type::TYPE_MESSAGE,
+ MessageOrEnumWithScope::Message(message_with_scope),
+ ) => {
+ let entry_key_value = if let (true, Some((key, value))) =
+ (parse_map, message_with_scope.map_entry())
+ {
+ Some(Box::new(EntryKeyValue(
+ field_elem(&key, root_scope, false, customize).0,
+ field_elem(&value, root_scope, false, customize).0,
+ )))
+ } else {
+ None
+ };
+ (
+ FieldElem::Message(
+ rust_relative_name,
+ file_name,
+ entry_key_value,
+ marker::PhantomData,
+ ),
+ None,
+ )
+ }
+ (
+ FieldDescriptorProto_Type::TYPE_ENUM,
+ MessageOrEnumWithScope::Enum(enum_with_scope),
+ ) => {
+ let e = EnumGen::new(
+ &enum_with_scope,
+ field.message.get_scope().get_file_descriptor(),
+ customize,
+ root_scope,
+ );
+ let ev = if field.field.has_default_value() {
+ e.value_by_name(field.field.get_default_value()).clone()
+ } else {
+ e.values_unique().into_iter().next().unwrap()
+ };
+ (
+ FieldElem::Enum(
+ rust_relative_name,
+ file_name,
+ RustIdent::from(enum_with_scope.values()[0].rust_name().to_owned()),
+ ),
+ Some(ev),
+ )
+ }
+ _ => panic!("unknown named type: {:?}", field.field.get_field_type()),
+ }
+ } else if field.field.has_field_type() {
+ let carllerche_for_bytes = customize.carllerche_bytes_for_bytes.unwrap_or(false);
+ let carllerche_for_string = customize.carllerche_bytes_for_string.unwrap_or(false);
+
+ let elem = match field.field.get_field_type() {
+ FieldDescriptorProto_Type::TYPE_STRING if carllerche_for_string => {
+ FieldElem::Primitive(
+ FieldDescriptorProto_Type::TYPE_STRING,
+ PrimitiveTypeVariant::Carllerche,
+ )
+ }
+ FieldDescriptorProto_Type::TYPE_BYTES if carllerche_for_bytes => FieldElem::Primitive(
+ FieldDescriptorProto_Type::TYPE_BYTES,
+ PrimitiveTypeVariant::Carllerche,
+ ),
+ t => FieldElem::Primitive(t, PrimitiveTypeVariant::Default),
+ };
+
+ (elem, None)
+ } else {
+ panic!(
+ "neither type_name, nor field_type specified for field: {}",
+ field.field.get_name()
+ );
+ }
+}
+
+pub enum AccessorStyle {
+ Lambda,
+ HasGet,
+}
+
+pub struct AccessorFn {
+ name: String,
+ type_params: Vec<String>,
+ pub style: AccessorStyle,
+}
+
+impl AccessorFn {
+ pub fn sig(&self) -> String {
+ let mut s = self.name.clone();
+ s.push_str("::<_");
+ for p in &self.type_params {
+ s.push_str(", ");
+ s.push_str(&p);
+ }
+ s.push_str(">");
+ s
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct FieldGen<'a> {
+ _root_scope: &'a RootScope<'a>,
+ syntax: Syntax,
+ pub proto_field: FieldWithContext<'a>,
+ // field name in generated code
+ pub rust_name: RustIdent,
+ pub proto_type: FieldDescriptorProto_Type,
+ wire_type: wire_format::WireType,
+ enum_default_value: Option<EnumValueGen>,
+ pub kind: FieldKind<'a>,
+ pub expose_field: bool,
+ pub generate_accessors: bool,
+ pub(crate) customize: Customize,
+}
+
+impl<'a> FieldGen<'a> {
+ pub fn parse(
+ field: FieldWithContext<'a>,
+ root_scope: &'a RootScope<'a>,
+ customize: &Customize,
+ ) -> FieldGen<'a> {
+ let mut customize = customize.clone();
+ customize.update_with(&customize_from_rustproto_for_field(
+ &field.field.get_options(),
+ ));
+
+ let (elem, enum_default_value) = field_elem(&field, root_scope, true, &customize);
+
+ let generate_accessors = customize.generate_accessors.unwrap_or(true);
+
+ let syntax = field.message.scope.file_scope.syntax();
+
+ let field_may_have_custom_default_value = syntax == Syntax::PROTO2
+ && field.field.get_label() != FieldDescriptorProto_Label::LABEL_REPEATED
+ && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE;
+
+ let default_expose_field = !field_may_have_custom_default_value;
+
+ let expose_field = customize.expose_fields.unwrap_or(default_expose_field);
+
+ let kind = if field.field.get_label() == FieldDescriptorProto_Label::LABEL_REPEATED {
+ match (elem, true) {
+ // map field
+ (FieldElem::Message(name, _, Some(key_value), _), true) => {
+ FieldKind::Map(MapField {
+ _name: name,
+ key: key_value.0.clone(),
+ value: key_value.1.clone(),
+ })
+ }
+ // regular repeated field
+ (elem, _) => FieldKind::Repeated(RepeatedField {
+ elem,
+ packed: field.field.get_options().get_packed(),
+ }),
+ }
+ } else if let Some(oneof) = field.oneof() {
+ FieldKind::Oneof(OneofField::parse(&oneof, &field, elem, root_scope))
+ } else {
+ let flag = if field.message.scope.file_scope.syntax() == Syntax::PROTO3
+ && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE
+ {
+ SingularFieldFlag::WithoutFlag
+ } else {
+ SingularFieldFlag::WithFlag {
+ required: field.field.get_label() == FieldDescriptorProto_Label::LABEL_REQUIRED,
+ }
+ };
+ FieldKind::Singular(SingularField { elem, flag })
+ };
+
+ FieldGen {
+ _root_scope: root_scope,
+ syntax: field.message.get_scope().file_scope.syntax(),
+ rust_name: field.rust_name(),
+ proto_type: field.field.get_field_type(),
+ wire_type: field_type_wire_type(field.field.get_field_type()),
+ enum_default_value,
+ proto_field: field.clone(),
+ kind,
+ expose_field,
+ generate_accessors,
+ customize,
+ }
+ }
+
+ fn tag_size(&self) -> u32 {
+ rt::tag_size(self.proto_field.number())
+ }
+
+ pub fn is_oneof(&self) -> bool {
+ match self.kind {
+ FieldKind::Oneof(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn oneof(&self) -> &OneofField {
+ match self.kind {
+ FieldKind::Oneof(ref oneof) => &oneof,
+ _ => panic!("not a oneof field: {}", self.reconstruct_def()),
+ }
+ }
+
+ fn is_singular(&self) -> bool {
+ match self.kind {
+ FieldKind::Singular(..) => true,
+ _ => false,
+ }
+ }
+
+ fn is_repeated_not_map(&self) -> bool {
+ match self.kind {
+ FieldKind::Repeated(..) => true,
+ _ => false,
+ }
+ }
+
+ fn is_repeated_or_map(&self) -> bool {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => true,
+ _ => false,
+ }
+ }
+
+ fn is_repeated_packed(&self) -> bool {
+ match self.kind {
+ FieldKind::Repeated(RepeatedField { packed: true, .. }) => true,
+ _ => false,
+ }
+ }
+
+ #[allow(dead_code)]
+ fn repeated(&self) -> &RepeatedField {
+ match self.kind {
+ FieldKind::Repeated(ref repeated) => &repeated,
+ _ => panic!("not a repeated field: {}", self.reconstruct_def()),
+ }
+ }
+
+ fn singular(&self) -> &SingularField {
+ match self.kind {
+ FieldKind::Singular(ref singular) => &singular,
+ _ => panic!("not a singular field: {}", self.reconstruct_def()),
+ }
+ }
+
+ fn map(&self) -> &MapField {
+ match self.kind {
+ FieldKind::Map(ref map) => &map,
+ _ => panic!("not a map field: {}", self.reconstruct_def()),
+ }
+ }
+
+ fn variant_path(&self) -> String {
+ // TODO: should reuse code from OneofVariantGen
+ format!(
+ "{}::{}",
+ self.oneof().oneof_type_name.to_code(&self.customize),
+ self.rust_name
+ )
+ }
+
+ // TODO: drop it
+ pub fn elem(&self) -> &FieldElem {
+ match self.kind {
+ FieldKind::Singular(SingularField { ref elem, .. }) => &elem,
+ FieldKind::Repeated(RepeatedField { ref elem, .. }) => &elem,
+ FieldKind::Oneof(OneofField { ref elem, .. }) => &elem,
+ FieldKind::Map(..) => unreachable!(),
+ }
+ }
+
+ // type of field in struct
+ pub fn full_storage_type(&self) -> RustType {
+ match self.kind {
+ FieldKind::Repeated(ref repeated) => repeated.rust_type(),
+ FieldKind::Map(MapField {
+ ref key, ref value, ..
+ }) => RustType::HashMap(
+ Box::new(key.rust_storage_type()),
+ Box::new(value.rust_storage_type()),
+ ),
+ FieldKind::Singular(ref singular) => singular.rust_storage_type(),
+ FieldKind::Oneof(..) => unreachable!(),
+ }
+ }
+
+ // type of `v` in `for v in field`
+ fn full_storage_iter_elem_type(&self) -> RustType {
+ if let FieldKind::Oneof(ref oneof) = self.kind {
+ oneof.elem.rust_storage_type()
+ } else {
+ self.full_storage_type().iter_elem_type()
+ }
+ }
+
+ // suffix `xxx` as in `os.write_xxx_no_tag(..)`
+ fn os_write_fn_suffix(&self) -> &str {
+ protobuf_name(self.proto_type)
+ }
+
+ // type of `v` in `os.write_xxx_no_tag(v)`
+ fn os_write_fn_param_type(&self) -> RustType {
+ match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)),
+ FieldDescriptorProto_Type::TYPE_BYTES => {
+ RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::Int(false, 8)))))
+ }
+ FieldDescriptorProto_Type::TYPE_ENUM => RustType::Int(true, 32),
+ t => rust_name(t),
+ }
+ }
+
+ // for field `foo`, type of param of `fn set_foo(..)`
+ fn set_xxx_param_type(&self) -> RustType {
+ match self.kind {
+ FieldKind::Singular(SingularField { ref elem, .. })
+ | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(),
+ FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(),
+ }
+ }
+
+ // for field `foo`, return type if `fn take_foo(..)`
+ fn take_xxx_return_type(&self) -> RustType {
+ self.set_xxx_param_type()
+ }
+
+ // for field `foo`, return type of `fn mut_foo(..)`
+ fn mut_xxx_return_type(&self) -> RustType {
+ RustType::Ref(Box::new(match self.kind {
+ FieldKind::Singular(SingularField { ref elem, .. })
+ | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(),
+ FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(),
+ }))
+ }
+
+ // for field `foo`, return type of `fn get_foo(..)`
+ fn get_xxx_return_type(&self) -> RustType {
+ match self.kind {
+ FieldKind::Singular(SingularField { ref elem, .. })
+ | FieldKind::Oneof(OneofField { ref elem, .. }) => match elem.is_copy() {
+ true => elem.rust_storage_type(),
+ false => elem.rust_storage_type().ref_type(),
+ },
+ FieldKind::Repeated(RepeatedField { ref elem, .. }) => RustType::Ref(Box::new(
+ RustType::Slice(Box::new(elem.rust_storage_type())),
+ )),
+ FieldKind::Map(..) => RustType::Ref(Box::new(self.full_storage_type())),
+ }
+ }
+
+ // fixed size type?
+ fn is_fixed(&self) -> bool {
+ field_type_size(self.proto_type).is_some()
+ }
+
+ // must use zigzag encoding?
+ fn is_zigzag(&self) -> bool {
+ match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true,
+ _ => false,
+ }
+ }
+
+ // data is enum
+ fn is_enum(&self) -> bool {
+ match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_ENUM => true,
+ _ => false,
+ }
+ }
+
+ // elem data is not stored in heap
+ pub fn elem_type_is_copy(&self) -> bool {
+ type_is_copy(self.proto_type)
+ }
+
+ fn defaut_value_from_proto_float(&self) -> String {
+ assert!(self.proto_field.field.has_default_value());
+
+ let type_name = match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_FLOAT => "f32",
+ FieldDescriptorProto_Type::TYPE_DOUBLE => "f64",
+ _ => unreachable!(),
+ };
+ let proto_default = self.proto_field.field.get_default_value();
+
+ let f = float::parse_protobuf_float(proto_default)
+ .expect(&format!("failed to parse float: {:?}", proto_default));
+
+ if f.is_nan() {
+ format!("::std::{}::NAN", type_name)
+ } else if f.is_infinite() {
+ if f > 0.0 {
+ format!("::std::{}::INFINITY", type_name)
+ } else {
+ format!("::std::{}::NEG_INFINITY", type_name)
+ }
+ } else {
+ format!("{:?}{}", f, type_name)
+ }
+ }
+
+ fn default_value_from_proto(&self) -> Option<String> {
+ assert!(self.is_singular() || self.is_oneof());
+ if self.enum_default_value.is_some() {
+ Some(self.enum_default_value.as_ref().unwrap().rust_name_outer())
+ } else if self.proto_field.field.has_default_value() {
+ let proto_default = self.proto_field.field.get_default_value();
+ Some(match self.proto_type {
+ // For numeric types, contains the original text representation of the value
+ FieldDescriptorProto_Type::TYPE_DOUBLE | FieldDescriptorProto_Type::TYPE_FLOAT => {
+ self.defaut_value_from_proto_float()
+ }
+ FieldDescriptorProto_Type::TYPE_INT32
+ | FieldDescriptorProto_Type::TYPE_SINT32
+ | FieldDescriptorProto_Type::TYPE_SFIXED32 => format!("{}i32", proto_default),
+ FieldDescriptorProto_Type::TYPE_UINT32
+ | FieldDescriptorProto_Type::TYPE_FIXED32 => format!("{}u32", proto_default),
+ FieldDescriptorProto_Type::TYPE_INT64
+ | FieldDescriptorProto_Type::TYPE_SINT64
+ | FieldDescriptorProto_Type::TYPE_SFIXED64 => format!("{}i64", proto_default),
+ FieldDescriptorProto_Type::TYPE_UINT64
+ | FieldDescriptorProto_Type::TYPE_FIXED64 => format!("{}u64", proto_default),
+
+ // For booleans, "true" or "false"
+ FieldDescriptorProto_Type::TYPE_BOOL => format!("{}", proto_default),
+ // For strings, contains the default text contents (not escaped in any way)
+ FieldDescriptorProto_Type::TYPE_STRING => rust::quote_escape_str(proto_default),
+ // For bytes, contains the C escaped value. All bytes >= 128 are escaped
+ FieldDescriptorProto_Type::TYPE_BYTES => {
+ rust::quote_escape_bytes(&text_format::unescape_string(proto_default))
+ }
+ // TODO: resolve outer message prefix
+ FieldDescriptorProto_Type::TYPE_GROUP | FieldDescriptorProto_Type::TYPE_ENUM => {
+ unreachable!()
+ }
+ FieldDescriptorProto_Type::TYPE_MESSAGE => panic!(
+ "default value is not implemented for type: {:?}",
+ self.proto_type
+ ),
+ })
+ } else {
+ None
+ }
+ }
+
+ fn default_value_from_proto_typed(&self) -> Option<RustValueTyped> {
+ self.default_value_from_proto().map(|v| {
+ let default_value_type = match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)),
+ FieldDescriptorProto_Type::TYPE_BYTES => {
+ RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::u8()))))
+ }
+ _ => self.full_storage_iter_elem_type(),
+ };
+
+ RustValueTyped {
+ value: v,
+ rust_type: default_value_type,
+ }
+ })
+ }
+
+ // default value to be returned from fn get_xxx
+ fn get_xxx_default_value_rust(&self) -> String {
+ assert!(self.is_singular() || self.is_oneof());
+ self.default_value_from_proto()
+ .unwrap_or_else(|| self.get_xxx_return_type().default_value(&self.customize))
+ }
+
+ // default to be assigned to field
+ fn element_default_value_rust(&self) -> RustValueTyped {
+ assert!(
+ self.is_singular() || self.is_oneof(),
+ "field is not singular: {}",
+ self.reconstruct_def()
+ );
+ self.default_value_from_proto_typed().unwrap_or_else(|| {
+ self.elem()
+ .rust_storage_type()
+ .default_value_typed(&self.customize)
+ })
+ }
+
+ pub fn reconstruct_def(&self) -> String {
+ let prefix = match (self.proto_field.field.get_label(), self.syntax) {
+ (FieldDescriptorProto_Label::LABEL_REPEATED, _) => "repeated ",
+ (_, Syntax::PROTO3) => "",
+ (FieldDescriptorProto_Label::LABEL_OPTIONAL, _) => "optional ",
+ (FieldDescriptorProto_Label::LABEL_REQUIRED, _) => "required ",
+ };
+ format!(
+ "{}{} {} = {}",
+ prefix,
+ field_type_protobuf_name(&self.proto_field.field),
+ self.proto_field.name(),
+ self.proto_field.number()
+ )
+ }
+
+ pub fn accessor_fn(&self) -> AccessorFn {
+ match self.kind {
+ FieldKind::Repeated(RepeatedField { ref elem, .. }) => {
+ let coll = match self.full_storage_type() {
+ RustType::Vec(..) => "vec",
+ RustType::RepeatedField(..) => "repeated_field",
+ _ => unreachable!(),
+ };
+ let name = format!("make_{}_accessor", coll);
+ AccessorFn {
+ name: name,
+ type_params: vec![elem.lib_protobuf_type(&self.customize)],
+ style: AccessorStyle::Lambda,
+ }
+ }
+ FieldKind::Map(MapField {
+ ref key, ref value, ..
+ }) => AccessorFn {
+ name: "make_map_accessor".to_owned(),
+ type_params: vec![
+ key.lib_protobuf_type(&self.customize),
+ value.lib_protobuf_type(&self.customize),
+ ],
+ style: AccessorStyle::Lambda,
+ },
+ FieldKind::Singular(SingularField {
+ ref elem,
+ flag: SingularFieldFlag::WithoutFlag,
+ }) => {
+ if let &FieldElem::Message(ref name, ..) = elem {
+ // TODO: old style, needed because of default instance
+
+ AccessorFn {
+ name: "make_singular_message_accessor".to_owned(),
+ type_params: vec![name.clone()],
+ style: AccessorStyle::HasGet,
+ }
+ } else {
+ AccessorFn {
+ name: "make_simple_field_accessor".to_owned(),
+ type_params: vec![elem.lib_protobuf_type(&self.customize)],
+ style: AccessorStyle::Lambda,
+ }
+ }
+ }
+ FieldKind::Singular(SingularField {
+ ref elem,
+ flag: SingularFieldFlag::WithFlag { .. },
+ }) => {
+ let coll = match self.full_storage_type() {
+ RustType::Option(..) => "option",
+ RustType::SingularField(..) => "singular_field",
+ RustType::SingularPtrField(..) => "singular_ptr_field",
+ _ => unreachable!(),
+ };
+ let name = format!("make_{}_accessor", coll);
+ AccessorFn {
+ name: name,
+ type_params: vec![elem.lib_protobuf_type(&self.customize)],
+ style: AccessorStyle::Lambda,
+ }
+ }
+ FieldKind::Oneof(OneofField { ref elem, .. }) => {
+ // TODO: uses old style
+
+ let suffix = match &self.elem().rust_storage_type() {
+ t if t.is_primitive() => t.to_code(&self.customize),
+ &RustType::String | &RustType::Chars => "string".to_string(),
+ &RustType::Vec(ref t) if t.is_u8() => "bytes".to_string(),
+ &RustType::Bytes => "bytes".to_string(),
+ &RustType::Enum(..) => "enum".to_string(),
+ &RustType::Message(..) => "message".to_string(),
+ t => panic!("unexpected field type: {:?}", t),
+ };
+
+ let name = format!("make_singular_{}_accessor", suffix);
+
+ let mut type_params = Vec::new();
+ match elem {
+ &FieldElem::Message(ref name, ..) | &FieldElem::Enum(ref name, ..) => {
+ type_params.push(name.to_owned());
+ }
+ _ => (),
+ }
+
+ AccessorFn {
+ name: name,
+ type_params: type_params,
+ style: AccessorStyle::HasGet,
+ }
+ }
+ }
+ }
+
+ pub fn write_clear(&self, w: &mut CodeWriter) {
+ if self.is_oneof() {
+ w.write_line(&format!(
+ "self.{} = ::std::option::Option::None;",
+ self.oneof().oneof_rust_field_name
+ ));
+ } else {
+ let clear_expr = self
+ .full_storage_type()
+ .clear(&self.self_field(), &self.customize);
+ w.write_line(&format!("{};", clear_expr));
+ }
+ }
+
+ // expression that returns size of data is variable
+ fn element_size(&self, var: &str, var_type: &RustType) -> String {
+ assert!(!self.is_repeated_packed());
+
+ match field_type_size(self.proto_type) {
+ Some(data_size) => format!("{}", data_size + self.tag_size()),
+ None => match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_MESSAGE => panic!("not a single-liner"),
+ FieldDescriptorProto_Type::TYPE_BYTES => format!(
+ "{}::rt::bytes_size({}, &{})",
+ protobuf_crate_path(&self.customize),
+ self.proto_field.number(),
+ var
+ ),
+ FieldDescriptorProto_Type::TYPE_STRING => format!(
+ "{}::rt::string_size({}, &{})",
+ protobuf_crate_path(&self.customize),
+ self.proto_field.number(),
+ var
+ ),
+ FieldDescriptorProto_Type::TYPE_ENUM => {
+ let param_type = match var_type {
+ &RustType::Ref(ref t) => (**t).clone(),
+ t => t.clone(),
+ };
+ format!(
+ "{}::rt::enum_size({}, {})",
+ protobuf_crate_path(&self.customize),
+ self.proto_field.number(),
+ var_type.into_target(&param_type, var, &self.customize)
+ )
+ }
+ _ => {
+ let param_type = match var_type {
+ &RustType::Ref(ref t) => (**t).clone(),
+ t => t.clone(),
+ };
+ if self.proto_type.is_s_varint() {
+ format!(
+ "{}::rt::value_varint_zigzag_size({}, {})",
+ protobuf_crate_path(&self.customize),
+ self.proto_field.number(),
+ var_type.into_target(&param_type, var, &self.customize)
+ )
+ } else {
+ format!(
+ "{}::rt::value_size({}, {}, {}::wire_format::{:?})",
+ protobuf_crate_path(&self.customize),
+ self.proto_field.number(),
+ var_type.into_target(&param_type, var, &self.customize),
+ protobuf_crate_path(&self.customize),
+ self.wire_type,
+ )
+ }
+ }
+ },
+ }
+ }
+
+ // output code that writes single element to stream
+ pub fn write_write_element(&self, w: &mut CodeWriter, os: &str, var: &str, ty: &RustType) {
+ if let FieldKind::Repeated(RepeatedField { packed: true, .. }) = self.kind {
+ unreachable!();
+ };
+
+ match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_MESSAGE => {
+ w.write_line(&format!(
+ "{}.write_tag({}, {}::wire_format::{:?})?;",
+ os,
+ self.proto_field.number(),
+ protobuf_crate_path(&self.customize),
+ wire_format::WireTypeLengthDelimited
+ ));
+ w.write_line(&format!(
+ "{}.write_raw_varint32({}.get_cached_size())?;",
+ os, var
+ ));
+ w.write_line(&format!("{}.write_to_with_cached_sizes({})?;", var, os));
+ }
+ _ => {
+ let param_type = self.os_write_fn_param_type();
+ let os_write_fn_suffix = self.os_write_fn_suffix();
+ let number = self.proto_field.number();
+ w.write_line(&format!(
+ "{}.write_{}({}, {})?;",
+ os,
+ os_write_fn_suffix,
+ number,
+ ty.into_target(&param_type, var, &self.customize)
+ ));
+ }
+ }
+ }
+
+ fn self_field(&self) -> String {
+ format!("self.{}", self.rust_name)
+ }
+
+ fn self_field_is_some(&self) -> String {
+ assert!(self.is_singular());
+ format!("{}.is_some()", self.self_field())
+ }
+
+ fn self_field_is_not_empty(&self) -> String {
+ assert!(self.is_repeated_or_map());
+ format!("!{}.is_empty()", self.self_field())
+ }
+
+ fn self_field_is_none(&self) -> String {
+ assert!(self.is_singular());
+ format!("{}.is_none()", self.self_field())
+ }
+
+ // type of expression returned by `as_option()`
+ fn as_option_type(&self) -> RustType {
+ assert!(self.is_singular());
+ match self.full_storage_type() {
+ RustType::Option(ref e) if e.is_copy() => RustType::Option(e.clone()),
+ RustType::Option(e) => RustType::Option(Box::new(e.ref_type())),
+ RustType::SingularField(ty) | RustType::SingularPtrField(ty) => {
+ RustType::Option(Box::new(RustType::Ref(ty)))
+ }
+ x => panic!("cannot convert {:?} to option", x),
+ }
+ }
+
+ // field data viewed as Option
+ fn self_field_as_option(&self) -> RustValueTyped {
+ assert!(self.is_singular());
+
+ let suffix = match self.full_storage_type() {
+ RustType::Option(ref e) if e.is_copy() => "",
+ _ => ".as_ref()",
+ };
+
+ self.as_option_type()
+ .value(format!("{}{}", self.self_field(), suffix))
+ }
+
+ fn write_if_let_self_field_is_some<F>(&self, w: &mut CodeWriter, cb: F)
+ where
+ F: Fn(&str, &RustType, &mut CodeWriter),
+ {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => panic!("field is not singular"),
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithFlag { .. },
+ ref elem,
+ }) => {
+ let var = "v";
+ let ref_prefix = match elem.rust_storage_type().is_copy() {
+ true => "",
+ false => "ref ",
+ };
+ let as_option = self.self_field_as_option();
+ w.if_let_stmt(
+ &format!("Some({}{})", ref_prefix, var),
+ &as_option.value,
+ |w| {
+ let v_type = as_option.rust_type.elem_type();
+ cb(var, &v_type, w);
+ },
+ );
+ }
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ref elem,
+ }) => match *elem {
+ FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..)
+ | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => {
+ w.if_stmt(format!("!{}.is_empty()", self.self_field()), |w| {
+ cb(&self.self_field(), &self.full_storage_type(), w);
+ });
+ }
+ _ => {
+ w.if_stmt(
+ format!(
+ "{} != {}",
+ self.self_field(),
+ self.full_storage_type().default_value(&self.customize)
+ ),
+ |w| {
+ cb(&self.self_field(), &self.full_storage_type(), w);
+ },
+ );
+ }
+ },
+ FieldKind::Oneof(..) => unreachable!(),
+ }
+ }
+
+ fn write_if_self_field_is_not_empty<F>(&self, w: &mut CodeWriter, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ assert!(self.is_repeated_or_map());
+ let self_field_is_not_empty = self.self_field_is_not_empty();
+ w.if_stmt(self_field_is_not_empty, cb);
+ }
+
+ pub fn write_if_self_field_is_none<F>(&self, w: &mut CodeWriter, cb: F)
+ where
+ F: Fn(&mut CodeWriter),
+ {
+ let self_field_is_none = self.self_field_is_none();
+ w.if_stmt(self_field_is_none, cb)
+ }
+
+ // repeated or singular
+ pub fn write_for_self_field<F>(&self, w: &mut CodeWriter, varn: &str, cb: F)
+ where
+ F: Fn(&mut CodeWriter, &RustType),
+ {
+ match self.kind {
+ FieldKind::Oneof(OneofField {
+ ref elem,
+ ref oneof_type_name,
+ ..
+ }) => {
+ let cond = format!(
+ "Some({}::{}(ref {}))",
+ oneof_type_name.to_code(&self.customize),
+ self.rust_name,
+ varn
+ );
+ w.if_let_stmt(&cond, &self.self_field_oneof(), |w| {
+ cb(w, &elem.rust_storage_type())
+ })
+ }
+ _ => {
+ let v_type = self.full_storage_iter_elem_type();
+ let self_field = self.self_field();
+ w.for_stmt(&format!("&{}", self_field), varn, |w| cb(w, &v_type));
+ }
+ }
+ }
+
+ fn write_self_field_assign(&self, w: &mut CodeWriter, value: &str) {
+ let self_field = self.self_field();
+ w.write_line(&format!("{} = {};", self_field, value));
+ }
+
+ fn write_self_field_assign_some(&self, w: &mut CodeWriter, value: &str) {
+ let full_storage_type = self.full_storage_type();
+ match self.singular() {
+ &SingularField {
+ flag: SingularFieldFlag::WithFlag { .. },
+ ..
+ } => {
+ self.write_self_field_assign(
+ w,
+ &full_storage_type.wrap_value(value, &self.customize),
+ );
+ }
+ &SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ..
+ } => {
+ self.write_self_field_assign(w, value);
+ }
+ }
+ }
+
+ fn write_self_field_assign_value(&self, w: &mut CodeWriter, value: &str, ty: &RustType) {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => {
+ let converted = ty.into_target(&self.full_storage_type(), value, &self.customize);
+ self.write_self_field_assign(w, &converted);
+ }
+ FieldKind::Singular(SingularField { ref elem, ref flag }) => {
+ let converted = ty.into_target(&elem.rust_storage_type(), value, &self.customize);
+ let wrapped = if *flag == SingularFieldFlag::WithoutFlag {
+ converted
+ } else {
+ self.full_storage_type()
+ .wrap_value(&converted, &self.customize)
+ };
+ self.write_self_field_assign(w, &wrapped);
+ }
+ FieldKind::Oneof(..) => unreachable!(),
+ }
+ }
+
+ fn write_self_field_assign_default(&self, w: &mut CodeWriter) {
+ assert!(self.is_singular());
+ if self.is_oneof() {
+ let self_field_oneof = self.self_field_oneof();
+ w.write_line(format!(
+ "{} = ::std::option::Option::Some({}({}))",
+ self_field_oneof,
+ self.variant_path(),
+ // TODO: default from .proto is not needed here (?)
+ self.element_default_value_rust()
+ .into_type(self.full_storage_iter_elem_type(), &self.customize)
+ .value
+ ));
+ } else {
+ // Note it is different from C++ protobuf, where field is initialized
+ // with default value
+ match self.full_storage_type() {
+ RustType::SingularField(..) | RustType::SingularPtrField(..) => {
+ let self_field = self.self_field();
+ w.write_line(&format!("{}.set_default();", self_field));
+ }
+ _ => {
+ self.write_self_field_assign_some(
+ w,
+ &self
+ .elem()
+ .rust_storage_type()
+ .default_value_typed(&self.customize)
+ .into_type(self.elem().rust_storage_type(), &self.customize)
+ .value,
+ );
+ }
+ }
+ }
+ }
+
+ fn self_field_vec_packed_fixed_data_size(&self) -> String {
+ assert!(self.is_fixed());
+ format!(
+ "({}.len() * {}) as u32",
+ self.self_field(),
+ field_type_size(self.proto_type).unwrap()
+ )
+ }
+
+ fn self_field_vec_packed_varint_data_size(&self) -> String {
+ assert!(!self.is_fixed());
+ let fn_name = if self.is_enum() {
+ "vec_packed_enum_data_size".to_string()
+ } else {
+ let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" };
+ format!("vec_packed_varint{}_data_size", zigzag_suffix)
+ };
+ format!(
+ "{}::rt::{}(&{})",
+ protobuf_crate_path(&self.customize),
+ fn_name,
+ self.self_field()
+ )
+ }
+
+ fn self_field_vec_packed_data_size(&self) -> String {
+ assert!(self.is_repeated_not_map());
+ if self.is_fixed() {
+ self.self_field_vec_packed_fixed_data_size()
+ } else {
+ self.self_field_vec_packed_varint_data_size()
+ }
+ }
+
+ fn self_field_vec_packed_fixed_size(&self) -> String {
+ // zero is filtered outside
+ format!(
+ "{} + {}::rt::compute_raw_varint32_size({}) + {}",
+ self.tag_size(),
+ protobuf_crate_path(&self.customize),
+ self.self_field_vec_packed_fixed_data_size(),
+ self.self_field_vec_packed_fixed_data_size()
+ )
+ }
+
+ fn self_field_vec_packed_varint_size(&self) -> String {
+ // zero is filtered outside
+ assert!(!self.is_fixed());
+ let fn_name = if self.is_enum() {
+ "vec_packed_enum_size".to_string()
+ } else {
+ let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" };
+ format!("vec_packed_varint{}_size", zigzag_suffix)
+ };
+ format!(
+ "{}::rt::{}({}, &{})",
+ protobuf_crate_path(&self.customize),
+ fn_name,
+ self.proto_field.number(),
+ self.self_field()
+ )
+ }
+
+ fn self_field_oneof(&self) -> String {
+ format!("self.{}", self.oneof().oneof_rust_field_name)
+ }
+
+ pub fn clear_field_func(&self) -> String {
+ format!("clear_{}", self.rust_name)
+ }
+
+ // Write `merge_from` part for this singular or repeated field
+ // of type message, string or bytes
+ fn write_merge_from_field_message_string_bytes(&self, w: &mut CodeWriter) {
+ let singular_or_repeated = match self.kind {
+ FieldKind::Repeated(..) => "repeated",
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithFlag { .. },
+ ..
+ }) => "singular",
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ..
+ }) => "singular_proto3",
+ FieldKind::Map(..) | FieldKind::Oneof(..) => unreachable!(),
+ };
+ let carllerche = match self.kind.primitive_type_variant() {
+ PrimitiveTypeVariant::Carllerche => "carllerche_",
+ PrimitiveTypeVariant::Default => "",
+ };
+ let type_name_for_fn = protobuf_name(self.proto_type);
+ w.write_line(&format!(
+ "{}::rt::read_{}_{}{}_into(wire_type, is, &mut self.{})?;",
+ protobuf_crate_path(&self.customize),
+ singular_or_repeated,
+ carllerche,
+ type_name_for_fn,
+ self.rust_name
+ ));
+ }
+
+ fn write_error_unexpected_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) {
+ w.write_line(&format!(
+ "return ::std::result::Result::Err({}::rt::unexpected_wire_type({}));",
+ protobuf_crate_path(&self.customize),
+ wire_type_var
+ ));
+ }
+
+ fn write_assert_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) {
+ w.if_stmt(
+ &format!(
+ "{} != {}::wire_format::{:?}",
+ wire_type_var,
+ protobuf_crate_path(&self.customize),
+ self.wire_type
+ ),
+ |w| {
+ self.write_error_unexpected_wire_type(wire_type_var, w);
+ },
+ );
+ }
+
+ // Write `merge_from` part for this oneof field
+ fn write_merge_from_oneof(&self, f: &OneofField, wire_type_var: &str, w: &mut CodeWriter) {
+ self.write_assert_wire_type(wire_type_var, w);
+
+ let typed = RustValueTyped {
+ value: format!(
+ "{}?",
+ self.proto_type.read("is", f.elem.primitive_type_variant())
+ ),
+ rust_type: self.full_storage_iter_elem_type(),
+ };
+
+ let maybe_boxed = if f.boxed {
+ typed.boxed(&self.customize)
+ } else {
+ typed
+ };
+
+ w.write_line(&format!(
+ "self.{} = ::std::option::Option::Some({}({}));",
+ self.oneof().oneof_rust_field_name,
+ self.variant_path(),
+ maybe_boxed.value
+ )); // TODO: into_type
+ }
+
+ // Write `merge_from` part for this map field
+ fn write_merge_from_map(&self, w: &mut CodeWriter) {
+ let &MapField {
+ ref key, ref value, ..
+ } = self.map();
+ w.write_line(&format!(
+ "{}::rt::read_map_into::<{}, {}>(wire_type, is, &mut {})?;",
+ protobuf_crate_path(&self.customize),
+ key.lib_protobuf_type(&self.customize),
+ value.lib_protobuf_type(&self.customize),
+ self.self_field()
+ ));
+ }
+
+ // Write `merge_from` part for this singular field
+ fn write_merge_from_singular(&self, wire_type_var: &str, w: &mut CodeWriter) {
+ let field = match self.kind {
+ FieldKind::Singular(ref field) => field,
+ _ => panic!(),
+ };
+
+ match field.elem {
+ FieldElem::Message(..)
+ | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..)
+ | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => {
+ self.write_merge_from_field_message_string_bytes(w);
+ }
+ FieldElem::Enum(..) => {
+ let version = match field.flag {
+ SingularFieldFlag::WithFlag { .. } => "proto2",
+ SingularFieldFlag::WithoutFlag => "proto3",
+ };
+ w.write_line(&format!(
+ "{}::rt::read_{}_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?",
+ protobuf_crate_path(&self.customize),
+ version,
+ wire_type_var,
+ self.rust_name,
+ self.proto_field.number()
+ ));
+ }
+ _ => {
+ let read_proc = format!(
+ "{}?",
+ self.proto_type.read("is", PrimitiveTypeVariant::Default)
+ );
+
+ self.write_assert_wire_type(wire_type_var, w);
+ w.write_line(&format!("let tmp = {};", read_proc));
+ self.write_self_field_assign_some(w, "tmp");
+ }
+ }
+ }
+
+ // Write `merge_from` part for this repeated field
+ fn write_merge_from_repeated(&self, wire_type_var: &str, w: &mut CodeWriter) {
+ let field = match self.kind {
+ FieldKind::Repeated(ref field) => field,
+ _ => panic!(),
+ };
+
+ match field.elem {
+ FieldElem::Message(..)
+ | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..)
+ | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => {
+ self.write_merge_from_field_message_string_bytes(w);
+ }
+ FieldElem::Enum(..) => {
+ w.write_line(&format!(
+ "{}::rt::read_repeated_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?",
+ protobuf_crate_path(&self.customize),
+ wire_type_var,
+ self.rust_name,
+ self.proto_field.number()
+ ));
+ }
+ _ => {
+ w.write_line(&format!(
+ "{}::rt::read_repeated_{}_into({}, is, &mut self.{})?;",
+ protobuf_crate_path(&self.customize),
+ protobuf_name(self.proto_type),
+ wire_type_var,
+ self.rust_name
+ ));
+ }
+ }
+ }
+
+ // Write `merge_from` part for this field
+ pub fn write_merge_from_field(&self, wire_type_var: &str, w: &mut CodeWriter) {
+ match self.kind {
+ FieldKind::Oneof(ref f) => self.write_merge_from_oneof(&f, wire_type_var, w),
+ FieldKind::Map(..) => self.write_merge_from_map(w),
+ FieldKind::Singular(..) => self.write_merge_from_singular(wire_type_var, w),
+ FieldKind::Repeated(..) => self.write_merge_from_repeated(wire_type_var, w),
+ }
+ }
+
+ fn self_field_vec_packed_size(&self) -> String {
+ match self.kind {
+ FieldKind::Repeated(RepeatedField { packed: true, .. }) => {
+ // zero is filtered outside
+ if self.is_fixed() {
+ self.self_field_vec_packed_fixed_size()
+ } else {
+ self.self_field_vec_packed_varint_size()
+ }
+ }
+ _ => {
+ panic!("not packed");
+ }
+ }
+ }
+
+ pub fn write_element_size(
+ &self,
+ w: &mut CodeWriter,
+ item_var: &str,
+ item_var_type: &RustType,
+ sum_var: &str,
+ ) {
+ assert!(!self.is_repeated_packed());
+
+ match self.proto_type {
+ FieldDescriptorProto_Type::TYPE_MESSAGE => {
+ w.write_line(&format!("let len = {}.compute_size();", item_var));
+ let tag_size = self.tag_size();
+ w.write_line(&format!(
+ "{} += {} + {}::rt::compute_raw_varint32_size(len) + len;",
+ sum_var,
+ tag_size,
+ protobuf_crate_path(&self.customize)
+ ));
+ }
+ _ => {
+ w.write_line(&format!(
+ "{} += {};",
+ sum_var,
+ self.element_size(item_var, item_var_type)
+ ));
+ }
+ }
+ }
+
+ pub fn write_message_write_field(&self, w: &mut CodeWriter) {
+ match self.kind {
+ FieldKind::Singular(..) => {
+ self.write_if_let_self_field_is_some(w, |v, v_type, w| {
+ self.write_write_element(w, "os", v, v_type);
+ });
+ }
+ FieldKind::Repeated(RepeatedField { packed: false, .. }) => {
+ self.write_for_self_field(w, "v", |w, v_type| {
+ self.write_write_element(w, "os", "v", v_type);
+ });
+ }
+ FieldKind::Repeated(RepeatedField { packed: true, .. }) => {
+ self.write_if_self_field_is_not_empty(w, |w| {
+ let number = self.proto_field.number();
+ w.write_line(&format!(
+ "os.write_tag({}, {}::wire_format::{:?})?;",
+ number,
+ protobuf_crate_path(&self.customize),
+ wire_format::WireTypeLengthDelimited
+ ));
+ w.comment("TODO: Data size is computed again, it should be cached");
+ let data_size_expr = self.self_field_vec_packed_data_size();
+ w.write_line(&format!("os.write_raw_varint32({})?;", data_size_expr));
+ self.write_for_self_field(w, "v", |w, v_type| {
+ let param_type = self.os_write_fn_param_type();
+ let os_write_fn_suffix = self.os_write_fn_suffix();
+ w.write_line(&format!(
+ "os.write_{}_no_tag({})?;",
+ os_write_fn_suffix,
+ v_type.into_target(&param_type, "v", &self.customize)
+ ));
+ });
+ });
+ }
+ FieldKind::Map(MapField {
+ ref key, ref value, ..
+ }) => {
+ w.write_line(&format!(
+ "{}::rt::write_map_with_cached_sizes::<{}, {}>({}, &{}, os)?;",
+ protobuf_crate_path(&self.customize),
+ key.lib_protobuf_type(&self.customize),
+ value.lib_protobuf_type(&self.customize),
+ self.proto_field.number(),
+ self.self_field()
+ ));
+ }
+ FieldKind::Oneof(..) => unreachable!(),
+ };
+ }
+
+ pub fn write_message_compute_field_size(&self, sum_var: &str, w: &mut CodeWriter) {
+ match self.kind {
+ FieldKind::Singular(..) => {
+ self.write_if_let_self_field_is_some(w, |v, v_type, w| {
+ match field_type_size(self.proto_type) {
+ Some(s) => {
+ let tag_size = self.tag_size();
+ w.write_line(&format!("{} += {};", sum_var, (s + tag_size) as isize));
+ }
+ None => {
+ self.write_element_size(w, v, v_type, sum_var);
+ }
+ };
+ });
+ }
+ FieldKind::Repeated(RepeatedField { packed: false, .. }) => {
+ match field_type_size(self.proto_type) {
+ Some(s) => {
+ let tag_size = self.tag_size();
+ let self_field = self.self_field();
+ w.write_line(&format!(
+ "{} += {} * {}.len() as u32;",
+ sum_var,
+ (s + tag_size) as isize,
+ self_field
+ ));
+ }
+ None => {
+ self.write_for_self_field(w, "value", |w, value_type| {
+ self.write_element_size(w, "value", value_type, sum_var);
+ });
+ }
+ };
+ }
+ FieldKind::Map(MapField {
+ ref key, ref value, ..
+ }) => {
+ w.write_line(&format!(
+ "{} += {}::rt::compute_map_size::<{}, {}>({}, &{});",
+ sum_var,
+ protobuf_crate_path(&self.customize),
+ key.lib_protobuf_type(&self.customize),
+ value.lib_protobuf_type(&self.customize),
+ self.proto_field.number(),
+ self.self_field()
+ ));
+ }
+ FieldKind::Repeated(RepeatedField { packed: true, .. }) => {
+ self.write_if_self_field_is_not_empty(w, |w| {
+ let size_expr = self.self_field_vec_packed_size();
+ w.write_line(&format!("{} += {};", sum_var, size_expr));
+ });
+ }
+ FieldKind::Oneof(..) => unreachable!(),
+ }
+ }
+
+ fn write_message_field_get_singular(&self, w: &mut CodeWriter) {
+ let get_xxx_return_type = self.get_xxx_return_type();
+
+ if self.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE {
+ let self_field = self.self_field();
+ let ref rust_type_message = match self.elem().rust_storage_type() {
+ RustType::Message(m) => m,
+ _ => unreachable!(),
+ };
+ w.write_line(&format!(
+ "{}.as_ref().unwrap_or_else(|| {})",
+ self_field,
+ rust_type_message.default_instance(&self.customize)
+ ));
+ } else {
+ let get_xxx_default_value_rust = self.get_xxx_default_value_rust();
+ let self_field = self.self_field();
+ match self.singular() {
+ &SingularField {
+ flag: SingularFieldFlag::WithFlag { .. },
+ ..
+ } => {
+ if get_xxx_return_type.is_ref() {
+ let as_option = self.self_field_as_option();
+ w.match_expr(&as_option.value, |w| {
+ let v_type = as_option.rust_type.elem_type();
+ let r_type = self.get_xxx_return_type();
+ w.case_expr(
+ "Some(v)",
+ v_type.into_target(&r_type, "v", &self.customize),
+ );
+ let get_xxx_default_value_rust = self.get_xxx_default_value_rust();
+ w.case_expr("None", get_xxx_default_value_rust);
+ });
+ } else {
+ w.write_line(&format!(
+ "{}.unwrap_or({})",
+ self_field, get_xxx_default_value_rust
+ ));
+ }
+ }
+ &SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ..
+ } => {
+ w.write_line(self.full_storage_type().into_target(
+ &get_xxx_return_type,
+ &self_field,
+ &self.customize,
+ ));
+ }
+ }
+ }
+ }
+
+ fn write_message_field_get(&self, w: &mut CodeWriter) {
+ let get_xxx_return_type = self.get_xxx_return_type();
+ let fn_def = format!(
+ "get_{}(&self) -> {}",
+ self.rust_name,
+ get_xxx_return_type.to_code(&self.customize)
+ );
+
+ w.pub_fn(&fn_def, |w| match self.kind {
+ FieldKind::Oneof(OneofField { ref elem, .. }) => {
+ let self_field_oneof = self.self_field_oneof();
+ w.match_expr(self_field_oneof, |w| {
+ let (refv, vtype) = if !self.elem_type_is_copy() {
+ ("ref v", elem.rust_storage_type().ref_type())
+ } else {
+ ("v", elem.rust_storage_type())
+ };
+ w.case_expr(
+ format!(
+ "::std::option::Option::Some({}({}))",
+ self.variant_path(),
+ refv
+ ),
+ vtype.into_target(&get_xxx_return_type, "v", &self.customize),
+ );
+ w.case_expr("_", self.get_xxx_default_value_rust());
+ })
+ }
+ FieldKind::Singular(..) => {
+ self.write_message_field_get_singular(w);
+ }
+ FieldKind::Repeated(..) | FieldKind::Map(..) => {
+ let self_field = self.self_field();
+ w.write_line(&format!("&{}", self_field));
+ }
+ });
+ }
+
+ fn has_has(&self) -> bool {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => false,
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithFlag { .. },
+ ..
+ }) => true,
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ..
+ }) => false,
+ FieldKind::Oneof(..) => true,
+ }
+ }
+
+ fn has_mut(&self) -> bool {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => true,
+ // TODO: string should be public, and mut is not needed
+ FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(),
+ }
+ }
+
+ fn has_take(&self) -> bool {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => true,
+ // TODO: string should be public, and mut is not needed
+ FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(),
+ }
+ }
+
+ fn has_name(&self) -> String {
+ format!("has_{}", self.rust_name)
+ }
+
+ fn write_message_field_has(&self, w: &mut CodeWriter) {
+ w.pub_fn(&format!("{}(&self) -> bool", self.has_name()), |w| {
+ if !self.is_oneof() {
+ let self_field_is_some = self.self_field_is_some();
+ w.write_line(self_field_is_some);
+ } else {
+ let self_field_oneof = self.self_field_oneof();
+ w.match_expr(self_field_oneof, |w| {
+ w.case_expr(
+ format!("::std::option::Option::Some({}(..))", self.variant_path()),
+ "true",
+ );
+ w.case_expr("_", "false");
+ });
+ }
+ });
+ }
+
+ fn write_message_field_set(&self, w: &mut CodeWriter) {
+ let set_xxx_param_type = self.set_xxx_param_type();
+ w.comment("Param is passed by value, moved");
+ let ref name = self.rust_name;
+ w.pub_fn(
+ &format!(
+ "set_{}(&mut self, v: {})",
+ name,
+ set_xxx_param_type.to_code(&self.customize)
+ ),
+ |w| {
+ if !self.is_oneof() {
+ self.write_self_field_assign_value(w, "v", &set_xxx_param_type);
+ } else {
+ let self_field_oneof = self.self_field_oneof();
+ let v = set_xxx_param_type.into_target(
+ &self.oneof().rust_type(),
+ "v",
+ &self.customize,
+ );
+ w.write_line(&format!(
+ "{} = ::std::option::Option::Some({}({}))",
+ self_field_oneof,
+ self.variant_path(),
+ v
+ ));
+ }
+ },
+ );
+ }
+
+ fn write_message_field_mut(&self, w: &mut CodeWriter) {
+ let mut_xxx_return_type = self.mut_xxx_return_type();
+ w.comment("Mutable pointer to the field.");
+ if self.is_singular() {
+ w.comment("If field is not initialized, it is initialized with default value first.");
+ }
+ let fn_def = match mut_xxx_return_type {
+ RustType::Ref(ref param) => format!(
+ "mut_{}(&mut self) -> &mut {}",
+ self.rust_name,
+ param.to_code(&self.customize)
+ ),
+ _ => panic!(
+ "not a ref: {}",
+ mut_xxx_return_type.to_code(&self.customize)
+ ),
+ };
+ w.pub_fn(&fn_def, |w| {
+ match self.kind {
+ FieldKind::Repeated(..) | FieldKind::Map(..) => {
+ let self_field = self.self_field();
+ w.write_line(&format!("&mut {}", self_field));
+ }
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithFlag { .. },
+ ..
+ }) => {
+ self.write_if_self_field_is_none(w, |w| {
+ self.write_self_field_assign_default(w);
+ });
+ let self_field = self.self_field();
+ w.write_line(&format!("{}.as_mut().unwrap()", self_field));
+ }
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ..
+ }) => w.write_line(&format!("&mut {}", self.self_field())),
+ FieldKind::Oneof(..) => {
+ let self_field_oneof = self.self_field_oneof();
+
+ // if oneof does not contain current field
+ w.if_let_else_stmt(
+ &format!("::std::option::Option::Some({}(_))", self.variant_path())[..],
+ &self_field_oneof[..],
+ |w| {
+ // initialize it with default value
+ w.write_line(&format!(
+ "{} = ::std::option::Option::Some({}({}));",
+ self_field_oneof,
+ self.variant_path(),
+ self.element_default_value_rust()
+ .into_type(self.oneof().rust_type(), &self.customize)
+ .value
+ ));
+ },
+ );
+
+ // extract field
+ w.match_expr(self_field_oneof, |w| {
+ w.case_expr(
+ format!(
+ "::std::option::Option::Some({}(ref mut v))",
+ self.variant_path()
+ ),
+ "v",
+ );
+ w.case_expr("_", "panic!()");
+ });
+ }
+ }
+ });
+ }
+
+ fn write_message_field_take_oneof(&self, w: &mut CodeWriter) {
+ let take_xxx_return_type = self.take_xxx_return_type();
+
+ // TODO: replace with if let
+ w.write_line(&format!("if self.{}() {{", self.has_name()));
+ w.indented(|w| {
+ let self_field_oneof = self.self_field_oneof();
+ w.match_expr(format!("{}.take()", self_field_oneof), |w| {
+ let value_in_some = self.oneof().rust_type().value("v".to_owned());
+ let converted =
+ value_in_some.into_type(self.take_xxx_return_type(), &self.customize);
+ w.case_expr(
+ format!("::std::option::Option::Some({}(v))", self.variant_path()),
+ &converted.value,
+ );
+ w.case_expr("_", "panic!()");
+ });
+ });
+ w.write_line("} else {");
+ w.indented(|w| {
+ w.write_line(
+ self.elem()
+ .rust_storage_type()
+ .default_value_typed(&self.customize)
+ .into_type(take_xxx_return_type.clone(), &self.customize)
+ .value,
+ );
+ });
+ w.write_line("}");
+ }
+
+ fn write_message_field_take(&self, w: &mut CodeWriter) {
+ let take_xxx_return_type = self.take_xxx_return_type();
+ w.comment("Take field");
+ w.pub_fn(
+ &format!(
+ "take_{}(&mut self) -> {}",
+ self.rust_name,
+ take_xxx_return_type.to_code(&self.customize)
+ ),
+ |w| match self.kind {
+ FieldKind::Oneof(..) => {
+ self.write_message_field_take_oneof(w);
+ }
+ FieldKind::Repeated(..) | FieldKind::Map(..) => {
+ w.write_line(&format!(
+ "::std::mem::replace(&mut self.{}, {})",
+ self.rust_name,
+ take_xxx_return_type.default_value(&self.customize)
+ ));
+ }
+ FieldKind::Singular(SingularField {
+ ref elem,
+ flag: SingularFieldFlag::WithFlag { .. },
+ }) => {
+ if !elem.is_copy() {
+ w.write_line(&format!(
+ "{}.take().unwrap_or_else(|| {})",
+ self.self_field(),
+ elem.rust_storage_type().default_value(&self.customize)
+ ));
+ } else {
+ w.write_line(&format!(
+ "{}.take().unwrap_or({})",
+ self.self_field(),
+ self.element_default_value_rust().value
+ ));
+ }
+ }
+ FieldKind::Singular(SingularField {
+ flag: SingularFieldFlag::WithoutFlag,
+ ..
+ }) => w.write_line(&format!(
+ "::std::mem::replace(&mut {}, {})",
+ self.self_field(),
+ self.full_storage_type().default_value(&self.customize)
+ )),
+ },
+ );
+ }
+
+ pub fn write_message_single_field_accessors(&self, w: &mut CodeWriter) {
+ // TODO: do not generate `get` when !proto2 and !generate_accessors`
+ w.write_line("");
+ self.write_message_field_get(w);
+
+ if !self.generate_accessors {
+ return;
+ }
+
+ let clear_field_func = self.clear_field_func();
+ w.pub_fn(&format!("{}(&mut self)", clear_field_func), |w| {
+ self.write_clear(w);
+ });
+
+ if self.has_has() {
+ w.write_line("");
+ self.write_message_field_has(w);
+ }
+
+ w.write_line("");
+ self.write_message_field_set(w);
+
+ if self.has_mut() {
+ w.write_line("");
+ self.write_message_field_mut(w);
+ }
+
+ if self.has_take() {
+ w.write_line("");
+ self.write_message_field_take(w);
+ }
+ }
+}
+
+pub(crate) fn rust_field_name_for_protobuf_field_name(name: &str) -> RustIdent {
+ if rust::is_rust_keyword(name) {
+ RustIdent::new(&format!("field_{}", name))
+ } else {
+ RustIdent::new(name)
+ }
+}
diff --git a/2.27.1/src/file.rs b/2.27.1/src/file.rs
new file mode 100644
index 0000000..413e1bc
--- /dev/null
+++ b/2.27.1/src/file.rs
@@ -0,0 +1,87 @@
+use crate::rust;
+use crate::rust_name::RustIdent;
+use crate::strx;
+
+// Copy-pasted from libsyntax.
+fn ident_start(c: char) -> bool {
+ (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
+}
+
+// Copy-pasted from libsyntax.
+fn ident_continue(c: char) -> bool {
+ (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'
+}
+
+pub(crate) fn proto_path_to_rust_mod(path: &str) -> RustIdent {
+ let without_dir = strx::remove_to(path, std::path::is_separator);
+ let without_suffix = strx::remove_suffix(without_dir, ".proto");
+
+ let name = without_suffix
+ .chars()
+ .enumerate()
+ .map(|(i, c)| {
+ let valid = if i == 0 {
+ ident_start(c)
+ } else {
+ ident_continue(c)
+ };
+ if valid {
+ c
+ } else {
+ '_'
+ }
+ })
+ .collect::<String>();
+
+ let name = if rust::is_rust_keyword(&name) {
+ format!("{}_pb", name)
+ } else {
+ name
+ };
+ RustIdent::from(name)
+}
+
+#[cfg(test)]
+mod test {
+
+ use super::proto_path_to_rust_mod;
+ use crate::rust_name::RustIdent;
+
+ #[test]
+ fn test_mod_path_proto_ext() {
+ assert_eq!(
+ RustIdent::from("proto"),
+ proto_path_to_rust_mod("proto.proto")
+ );
+ }
+
+ #[test]
+ fn test_mod_path_unknown_ext() {
+ assert_eq!(
+ RustIdent::from("proto_proto3"),
+ proto_path_to_rust_mod("proto.proto3")
+ );
+ }
+
+ #[test]
+ fn test_mod_path_empty_ext() {
+ assert_eq!(RustIdent::from("proto"), proto_path_to_rust_mod("proto"));
+ }
+
+ #[test]
+ fn test_mod_path_dir() {
+ assert_eq!(
+ RustIdent::from("baz"),
+ proto_path_to_rust_mod("foo/bar/baz.proto"),
+ )
+ }
+
+ #[cfg(target_os = "windows")]
+ #[test]
+ fn test_mod_path_dir_backslashes() {
+ assert_eq!(
+ RustIdent::from("baz"),
+ proto_path_to_rust_mod("foo\\bar\\baz.proto"),
+ )
+ }
+}
diff --git a/2.27.1/src/file_and_mod.rs b/2.27.1/src/file_and_mod.rs
new file mode 100644
index 0000000..4f4e8c6
--- /dev/null
+++ b/2.27.1/src/file_and_mod.rs
@@ -0,0 +1,9 @@
+use rust_name::RustRelativePath;
+use Customize;
+
+#[allow(dead_code)]
+pub(crate) struct FileAndMod {
+ pub file: String,
+ pub relative_mod: RustRelativePath,
+ pub customize: Customize,
+}
diff --git a/2.27.1/src/file_descriptor.rs b/2.27.1/src/file_descriptor.rs
new file mode 100644
index 0000000..dde8603
--- /dev/null
+++ b/2.27.1/src/file_descriptor.rs
@@ -0,0 +1,5 @@
+use crate::scope::Scope;
+
+pub(crate) fn file_descriptor_proto_expr(_scope: &Scope) -> String {
+ format!("file_descriptor_proto()")
+}
diff --git a/2.27.1/src/float.rs b/2.27.1/src/float.rs
new file mode 100644
index 0000000..78ca622
--- /dev/null
+++ b/2.27.1/src/float.rs
@@ -0,0 +1,67 @@
+use std::f64;
+
+#[derive(Debug)]
+pub enum ProtobufFloatParseError {
+ EmptyString,
+ CannotParseFloat,
+}
+
+pub type ProtobufFloatParseResult<T> = Result<T, ProtobufFloatParseError>;
+
+pub const PROTOBUF_NAN: &str = "nan";
+pub const PROTOBUF_INF: &str = "inf";
+
+/// Format float as in protobuf `.proto` files
+pub fn format_protobuf_float(f: f64) -> String {
+ if f.is_nan() {
+ PROTOBUF_NAN.to_owned()
+ } else if f.is_infinite() {
+ if f > 0.0 {
+ format!("{}", PROTOBUF_INF)
+ } else {
+ format!("-{}", PROTOBUF_INF)
+ }
+ } else {
+ let i = f as i64;
+ if i as f64 == f {
+ // Older rust versions did print float without `.0` suffix
+ format!("{:?}.0", i)
+ } else {
+ // TODO: make sure doesn't lose precision
+ format!("{:?}", f)
+ }
+ }
+}
+
+/// Parse float from `.proto` format
+pub fn parse_protobuf_float(s: &str) -> ProtobufFloatParseResult<f64> {
+ if s.is_empty() {
+ return Err(ProtobufFloatParseError::EmptyString);
+ }
+ if s == PROTOBUF_NAN {
+ return Ok(f64::NAN);
+ }
+ if s == PROTOBUF_INF || s == format!("+{}", PROTOBUF_INF) {
+ return Ok(f64::INFINITY);
+ }
+ if s == format!("-{}", PROTOBUF_INF) {
+ return Ok(f64::NEG_INFINITY);
+ }
+ match s.parse() {
+ Ok(f) => Ok(f),
+ Err(_) => Err(ProtobufFloatParseError::CannotParseFloat),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_format_protobuf_float() {
+ assert_eq!("10.0", format_protobuf_float(10.0));
+ assert_eq!("-10.0", format_protobuf_float(-10.0));
+ assert_eq!("10.5", format_protobuf_float(10.5));
+ assert_eq!("-10.5", format_protobuf_float(-10.5));
+ }
+}
diff --git a/2.27.1/src/inside.rs b/2.27.1/src/inside.rs
new file mode 100644
index 0000000..bbdcfdb
--- /dev/null
+++ b/2.27.1/src/inside.rs
@@ -0,0 +1,10 @@
+use Customize;
+
+/// Path to `protobuf` crate, different when `.proto` file is
+/// used inside or outside of protobuf crate.
+pub(crate) fn protobuf_crate_path(customize: &Customize) -> &str {
+ match customize.inside_protobuf {
+ Some(true) => "crate",
+ _ => "::protobuf",
+ }
+}
diff --git a/2.27.1/src/lib.rs b/2.27.1/src/lib.rs
new file mode 100644
index 0000000..826e18b
--- /dev/null
+++ b/2.27.1/src/lib.rs
@@ -0,0 +1,387 @@
+//! # Protobuf code generator
+//!
+//! This crate contains protobuf code generator implementation
+//! and a `protoc-gen-rust` `protoc` plugin.
+//!
+//! This crate:
+//! * provides `protoc-gen-rust` plugin for `protoc` command
+//! * implement protobuf codegen
+//!
+//! This crate is not meant to be used directly, in fact, it does not provide any public API
+//! (except for `protoc-gen-rust` binary).
+//!
+//! Code can be generated with either:
+//! * `protoc-gen-rust` plugin for `protoc` or
+//! * [`protoc-rust`](https://docs.rs/protoc) crate
+//! (code generator which depends on `protoc` binary for parsing of `.proto` files)
+//! * [`protobuf-codegen-pure`](https://docs.rs/protobuf-codegen-pure) crate,
+//! similar API to `protoc-rust`, but uses pure rust parser of `.proto` files.
+//!
+//! # `protoc-gen-rust` plugin for `protoc`
+//!
+//! When non-cargo build system is used, consider using standard protobuf code generation pattern:
+//! `protoc` command does all the work of handling paths and parsing `.proto` files.
+//! When `protoc` is invoked with `--rust_out=` option, it invokes `protoc-gen-rust` plugin.
+//! provided by this crate.
+//!
+//! When building with cargo, consider using `protoc-rust` or `protobuf-codegen-pure` crates.
+//!
+//! ## How to use `protoc-gen-rust` if you have to
+//!
+//! (Note `protoc` can be invoked programmatically with
+//! [protoc crate](https://docs.rs/protoc))
+//!
+//! 0) Install protobuf for `protoc` binary.
+//!
+//! On OS X [Homebrew](https://github.com/Homebrew/brew) can be used:
+//!
+//! ```sh
+//! brew install protobuf
+//! ```
+//!
+//! On Ubuntu, `protobuf-compiler` package can be installed:
+//!
+//! ```sh
+//! apt-get install protobuf-compiler
+//! ```
+//!
+//! Protobuf is needed only for code generation, `rust-protobuf` runtime
+//! does not use `protobuf` library.
+//!
+//! 1) Install `protoc-gen-rust` program (which is `protoc` plugin)
+//!
+//! It can be installed either from source or with `cargo install protobuf` command.
+//!
+//! 2) Add `protoc-gen-rust` to $PATH
+//!
+//! If you installed it with cargo, it should be
+//!
+//! ```sh
+//! PATH="$HOME/.cargo/bin:$PATH"
+//! ```
+//!
+//! 3) Generate .rs files:
+//!
+//! ```sh
+//! protoc --rust_out . foo.proto
+//! ```
+//!
+//! This will generate .rs files in current directory.
+//!
+//! # Version 2
+//!
+//! This is documentation for version 2 of the crate.
+//!
+//! [Version 3 of the crate](https://docs.rs/protobuf-codegen/%3E=3.0.0-alpha)
+//! (currently in development) encapsulates both `protoc` and pure codegens in this crate.
+
+#![deny(rustdoc::broken_intra_doc_links)]
+#![deny(missing_docs)]
+
+extern crate protobuf;
+
+use std::collections::hash_map::HashMap;
+use std::fmt::Write as FmtWrite;
+use std::fs::File;
+use std::io;
+use std::io::Write;
+use std::path::Path;
+
+use protobuf::compiler_plugin;
+use protobuf::descriptor::*;
+use protobuf::Message;
+
+mod customize;
+mod enums;
+mod extensions;
+mod field;
+mod file;
+mod file_and_mod;
+mod file_descriptor;
+#[doc(hidden)]
+pub mod float;
+mod inside;
+mod message;
+mod oneof;
+mod protobuf_name;
+mod rust_name;
+mod rust_types_values;
+mod serde;
+mod well_known_types;
+
+pub(crate) mod rust;
+pub(crate) mod scope;
+pub(crate) mod strx;
+pub(crate) mod syntax;
+
+use customize::customize_from_rustproto_for_file;
+#[doc(hidden)]
+pub use customize::Customize;
+
+pub mod code_writer;
+
+use inside::protobuf_crate_path;
+#[doc(hidden)]
+pub use protobuf_name::ProtobufAbsolutePath;
+#[doc(hidden)]
+pub use protobuf_name::ProtobufIdent;
+#[doc(hidden)]
+pub use protobuf_name::ProtobufRelativePath;
+use scope::FileScope;
+use scope::RootScope;
+
+use self::code_writer::CodeWriter;
+use self::enums::*;
+use self::extensions::*;
+use self::message::*;
+use crate::file::proto_path_to_rust_mod;
+
+fn escape_byte(s: &mut String, b: u8) {
+ if b == b'\n' {
+ write!(s, "\\n").unwrap();
+ } else if b == b'\r' {
+ write!(s, "\\r").unwrap();
+ } else if b == b'\t' {
+ write!(s, "\\t").unwrap();
+ } else if b == b'\\' || b == b'"' {
+ write!(s, "\\{}", b as char).unwrap();
+ } else if b == b'\0' {
+ write!(s, "\\0").unwrap();
+ // ASCII printable except space
+ } else if b > 0x20 && b < 0x7f {
+ write!(s, "{}", b as char).unwrap();
+ } else {
+ write!(s, "\\x{:02x}", b).unwrap();
+ }
+}
+
+fn write_file_descriptor_data(
+ file: &FileDescriptorProto,
+ customize: &Customize,
+ w: &mut CodeWriter,
+) {
+ let fdp_bytes = file.write_to_bytes().unwrap();
+ w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
+ w.indented(|w| {
+ const MAX_LINE_LEN: usize = 72;
+
+ let mut s = String::new();
+ for &b in &fdp_bytes {
+ let prev_len = s.len();
+ escape_byte(&mut s, b);
+ let truncate = s.len() > MAX_LINE_LEN;
+ if truncate {
+ s.truncate(prev_len);
+ }
+ if truncate || s.len() == MAX_LINE_LEN {
+ write!(s, "\\").unwrap();
+ w.write_line(&s);
+ s.clear();
+ }
+ if truncate {
+ escape_byte(&mut s, b);
+ }
+ }
+ if !s.is_empty() {
+ write!(s, "\\").unwrap();
+ w.write_line(&s);
+ s.clear();
+ }
+ });
+ w.write_line("\";");
+ w.write_line("");
+ w.lazy_static(
+ "file_descriptor_proto_lazy",
+ &format!(
+ "{}::descriptor::FileDescriptorProto",
+ protobuf_crate_path(customize)
+ ),
+ customize,
+ );
+ w.write_line("");
+ w.def_fn(
+ &format!(
+ "parse_descriptor_proto() -> {}::descriptor::FileDescriptorProto",
+ protobuf_crate_path(customize)
+ ),
+ |w| {
+ w.write_line(&format!(
+ "{}::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()",
+ protobuf_crate_path(customize)
+ ));
+ },
+ );
+ w.write_line("");
+ w.pub_fn(
+ &format!(
+ "file_descriptor_proto() -> &'static {}::descriptor::FileDescriptorProto",
+ protobuf_crate_path(customize)
+ ),
+ |w| {
+ w.block("file_descriptor_proto_lazy.get(|| {", "})", |w| {
+ w.write_line("parse_descriptor_proto()");
+ });
+ },
+ );
+}
+
+struct GenFileResult {
+ compiler_plugin_result: compiler_plugin::GenResult,
+ mod_name: String,
+}
+
+fn gen_file(
+ file: &FileDescriptorProto,
+ _files_map: &HashMap<&str, &FileDescriptorProto>,
+ root_scope: &RootScope,
+ customize: &Customize,
+) -> GenFileResult {
+ // TODO: use it
+ let mut customize = customize.clone();
+ // options specified in invocation have precedence over options specified in file
+ customize.update_with(&customize_from_rustproto_for_file(file.get_options()));
+
+ let scope = FileScope {
+ file_descriptor: file,
+ }
+ .to_scope();
+ let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+ file.get_options().get_optimize_for() == FileOptions_OptimizeMode::LITE_RUNTIME
+ });
+
+ let mut v = Vec::new();
+
+ {
+ let mut w = CodeWriter::new(&mut v);
+
+ w.write_generated_by("rust-protobuf", "2.27.1");
+ w.write_line(&format!("//! Generated file from `{}`", file.get_name()));
+ if customize.inside_protobuf != Some(true) {
+ w.write_line("");
+ w.write_line("/// Generated files are compatible only with the same version");
+ w.write_line("/// of protobuf runtime.");
+ w.commented(|w| {
+ w.write_line(&format!(
+ "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
+ protobuf_crate_path(&customize),
+ protobuf::VERSION_IDENT
+ ));
+ })
+ }
+
+ for message in &scope.get_messages() {
+ // ignore map entries, because they are not used in map fields
+ if message.map_entry().is_none() {
+ w.write_line("");
+ MessageGen::new(message, &root_scope, &customize).write(&mut w);
+ }
+ }
+ for enum_type in &scope.get_enums() {
+ w.write_line("");
+ EnumGen::new(enum_type, file, &customize, root_scope).write(&mut w);
+ }
+
+ write_extensions(file, &root_scope, &mut w, &customize);
+
+ if !lite_runtime {
+ w.write_line("");
+ write_file_descriptor_data(file, &customize, &mut w);
+ }
+ }
+
+ GenFileResult {
+ compiler_plugin_result: compiler_plugin::GenResult {
+ name: format!("{}.rs", proto_path_to_rust_mod(file.get_name())),
+ content: v,
+ },
+ mod_name: proto_path_to_rust_mod(file.get_name()).into_string(),
+ }
+}
+
+fn gen_mod_rs(mods: &[String]) -> compiler_plugin::GenResult {
+ let mut v = Vec::new();
+ let mut w = CodeWriter::new(&mut v);
+ w.comment("@generated");
+ w.write_line("");
+ for m in mods {
+ w.write_line(&format!("pub mod {};", m));
+ }
+ drop(w);
+ compiler_plugin::GenResult {
+ name: "mod.rs".to_owned(),
+ content: v,
+ }
+}
+
+// This function is also used externally by cargo plugin
+// https://github.com/plietar/rust-protobuf-build
+// So be careful changing its signature.
+#[doc(hidden)]
+pub fn gen(
+ file_descriptors: &[FileDescriptorProto],
+ files_to_generate: &[String],
+ customize: &Customize,
+) -> Vec<compiler_plugin::GenResult> {
+ let root_scope = RootScope {
+ file_descriptors: file_descriptors,
+ };
+
+ let mut results: Vec<compiler_plugin::GenResult> = Vec::new();
+ let files_map: HashMap<&str, &FileDescriptorProto> =
+ file_descriptors.iter().map(|f| (f.get_name(), f)).collect();
+
+ let all_file_names: Vec<&str> = file_descriptors.iter().map(|f| f.get_name()).collect();
+
+ let mut mods = Vec::new();
+
+ for file_name in files_to_generate {
+ let file = files_map.get(&file_name[..]).expect(&format!(
+ "file not found in file descriptors: {:?}, files: {:?}",
+ file_name, all_file_names
+ ));
+
+ let gen_file_result = gen_file(file, &files_map, &root_scope, customize);
+ results.push(gen_file_result.compiler_plugin_result);
+ mods.push(gen_file_result.mod_name);
+ }
+
+ if customize.gen_mod_rs.unwrap_or(false) {
+ results.push(gen_mod_rs(&mods));
+ }
+
+ results
+}
+
+#[doc(hidden)]
+pub fn gen_and_write(
+ file_descriptors: &[FileDescriptorProto],
+ files_to_generate: &[String],
+ out_dir: &Path,
+ customize: &Customize,
+) -> io::Result<()> {
+ let results = gen(file_descriptors, files_to_generate, customize);
+
+ for r in &results {
+ let mut file_path = out_dir.to_owned();
+ file_path.push(&r.name);
+ let mut file_writer = File::create(&file_path)?;
+ file_writer.write_all(&r.content)?;
+ file_writer.flush()?;
+ }
+
+ Ok(())
+}
+
+#[doc(hidden)]
+pub fn protoc_gen_rust_main() {
+ compiler_plugin::plugin_main_2(|r| {
+ let customize = Customize::parse_from_parameter(r.parameter).expect("parse options");
+ gen(r.file_descriptors, r.files_to_generate, &customize)
+ });
+}
+
+/// Used in protobuf-codegen-identical-test
+#[doc(hidden)]
+pub fn proto_name_to_rs(name: &str) -> String {
+ format!("{}.rs", proto_path_to_rust_mod(name))
+}
diff --git a/2.27.1/src/message.rs b/2.27.1/src/message.rs
new file mode 100644
index 0000000..fbe9ed4
--- /dev/null
+++ b/2.27.1/src/message.rs
@@ -0,0 +1,626 @@
+use std::fmt;
+
+use file_descriptor::file_descriptor_proto_expr;
+use inside::protobuf_crate_path;
+use oneof::OneofGen;
+use oneof::OneofVariantGen;
+use protobuf::descriptor::*;
+use rust_name::RustIdentWithPath;
+use scope::MessageWithScope;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+
+use super::code_writer::*;
+use super::customize::customize_from_rustproto_for_message;
+use super::customize::Customize;
+use super::enums::*;
+use super::field::*;
+use super::rust_types_values::*;
+
+/// Protobuf message Rust type name
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct RustTypeMessage(pub RustIdentWithPath);
+
+impl fmt::Display for RustTypeMessage {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
+impl RustTypeMessage {
+ /// Code which emits default instance.
+ pub fn default_instance(&self, customize: &Customize) -> String {
+ format!(
+ "<{} as {}::Message>::default_instance()",
+ self.0,
+ protobuf_crate_path(customize)
+ )
+ }
+}
+
+/// Message info for codegen
+pub(crate) struct MessageGen<'a> {
+ pub message: &'a MessageWithScope<'a>,
+ pub root_scope: &'a RootScope<'a>,
+ type_name: RustIdentWithPath,
+ pub fields: Vec<FieldGen<'a>>,
+ pub lite_runtime: bool,
+ customize: Customize,
+}
+
+impl<'a> MessageGen<'a> {
+ pub fn new(
+ message: &'a MessageWithScope<'a>,
+ root_scope: &'a RootScope<'a>,
+ customize: &Customize,
+ ) -> MessageGen<'a> {
+ let mut customize = customize.clone();
+ customize.update_with(&customize_from_rustproto_for_message(
+ message.message.get_options(),
+ ));
+
+ let fields: Vec<_> = message
+ .fields()
+ .into_iter()
+ .map(|field| FieldGen::parse(field, root_scope, &customize))
+ .collect();
+ let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
+ message
+ .get_file_descriptor()
+ .get_options()
+ .get_optimize_for()
+ == FileOptions_OptimizeMode::LITE_RUNTIME
+ });
+ MessageGen {
+ message,
+ root_scope,
+ type_name: message.rust_name().into(),
+ fields,
+ lite_runtime,
+ customize,
+ }
+ }
+
+ fn expose_oneof(&self) -> bool {
+ self.customize.expose_oneof.unwrap_or(true)
+ }
+
+ fn oneofs(&'a self) -> Vec<OneofGen<'a>> {
+ self.message
+ .oneofs()
+ .into_iter()
+ .map(|oneof| OneofGen::parse(self, oneof, &self.customize))
+ .collect()
+ }
+
+ fn required_fields(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| match f.kind {
+ FieldKind::Singular(ref singular) => singular.flag.is_required(),
+ _ => false,
+ })
+ .collect()
+ }
+
+ fn message_fields(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| f.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE)
+ .collect()
+ }
+
+ fn fields_except_oneof(&'a self) -> Vec<&'a FieldGen> {
+ self.fields.iter().filter(|f| !f.is_oneof()).collect()
+ }
+
+ fn fields_except_group(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| f.proto_type != FieldDescriptorProto_Type::TYPE_GROUP)
+ .collect()
+ }
+
+ fn fields_except_oneof_and_group(&'a self) -> Vec<&'a FieldGen> {
+ self.fields
+ .iter()
+ .filter(|f| !f.is_oneof() && f.proto_type != FieldDescriptorProto_Type::TYPE_GROUP)
+ .collect()
+ }
+
+ fn write_match_each_oneof_variant<F>(&self, w: &mut CodeWriter, cb: F)
+ where
+ F: Fn(&mut CodeWriter, &OneofVariantGen, &str, &RustType),
+ {
+ for oneof in self.oneofs() {
+ w.if_let_stmt(
+ "::std::option::Option::Some(ref v)",
+ &format!("self.{}", oneof.oneof.field_name())[..],
+ |w| {
+ w.match_block("v", |w| {
+ for variant in oneof.variants_except_group() {
+ let ref field = variant.field;
+ let (refv, vtype) = if !field.elem_type_is_copy() {
+ ("ref v", field.elem().rust_storage_type().ref_type())
+ } else {
+ ("v", field.elem().rust_storage_type())
+ };
+ w.case_block(format!("&{}({})", variant.path(), refv), |w| {
+ cb(w, &variant, "v", &vtype);
+ });
+ }
+ });
+ },
+ );
+ }
+ }
+
+ fn write_write_to_with_cached_sizes(&self, w: &mut CodeWriter) {
+ let sig = format!(
+ "write_to_with_cached_sizes(&self, os: &mut {}::CodedOutputStream<'_>) -> {}::ProtobufResult<()>",
+ protobuf_crate_path(&self.customize),
+ protobuf_crate_path(&self.customize),
+ );
+ w.def_fn(&sig, |w| {
+ // To have access to its methods but not polute the name space.
+ for f in self.fields_except_oneof_and_group() {
+ f.write_message_write_field(w);
+ }
+ self.write_match_each_oneof_variant(w, |w, variant, v, v_type| {
+ variant.field.write_write_element(w, "os", v, v_type);
+ });
+ w.write_line("os.write_unknown_fields(self.get_unknown_fields())?;");
+ w.write_line("::std::result::Result::Ok(())");
+ });
+ }
+
+ fn write_get_cached_size(&self, w: &mut CodeWriter) {
+ w.def_fn("get_cached_size(&self) -> u32", |w| {
+ w.write_line("self.cached_size.get()");
+ });
+ }
+
+ fn write_default_instance(&self, w: &mut CodeWriter) {
+ w.def_fn(
+ &format!("default_instance() -> &'static {}", self.type_name),
+ |w| {
+ w.lazy_static_decl_get_simple(
+ "instance",
+ &self.type_name.to_string(),
+ &format!("{}::new", self.type_name),
+ &self.customize,
+ );
+ },
+ );
+ }
+
+ fn write_compute_size(&self, w: &mut CodeWriter) {
+ // Append sizes of messages in the tree to the specified vector.
+ // First appended element is size of self, and then nested message sizes.
+ // in serialization order are appended recursively.");
+ w.comment("Compute sizes of nested messages");
+ // there are unused variables in oneof
+ w.allow(&["unused_variables"]);
+ w.def_fn("compute_size(&self) -> u32", |w| {
+ // To have access to its methods but not polute the name space.
+ w.write_line("let mut my_size = 0;");
+ for field in self.fields_except_oneof_and_group() {
+ field.write_message_compute_field_size("my_size", w);
+ }
+ self.write_match_each_oneof_variant(w, |w, variant, v, vtype| {
+ variant.field.write_element_size(w, v, vtype, "my_size");
+ });
+ w.write_line(&format!(
+ "my_size += {}::rt::unknown_fields_size(self.get_unknown_fields());",
+ protobuf_crate_path(&self.customize)
+ ));
+ w.write_line("self.cached_size.set(my_size);");
+ w.write_line("my_size");
+ });
+ }
+
+ fn write_field_accessors(&self, w: &mut CodeWriter) {
+ for f in self.fields_except_group() {
+ w.write_line("");
+ let reconstruct_def = f.reconstruct_def();
+ w.comment(&(reconstruct_def + ";"));
+ w.write_line("");
+ f.write_message_single_field_accessors(w);
+ }
+ }
+
+ fn write_impl_self(&self, w: &mut CodeWriter) {
+ w.impl_self_block(&self.type_name.to_string(), |w| {
+ // TODO: new should probably be a part of Message trait
+ w.pub_fn(&format!("new() -> {}", self.type_name), |w| {
+ w.write_line("::std::default::Default::default()");
+ });
+
+ self.write_field_accessors(w);
+ });
+ }
+
+ fn write_unknown_fields(&self, w: &mut CodeWriter) {
+ w.def_fn(
+ &format!(
+ "get_unknown_fields(&self) -> &{}::UnknownFields",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line("&self.unknown_fields");
+ },
+ );
+ w.write_line("");
+ w.def_fn(
+ &format!(
+ "mut_unknown_fields(&mut self) -> &mut {}::UnknownFields",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line("&mut self.unknown_fields");
+ },
+ );
+ }
+
+ fn write_merge_from(&self, w: &mut CodeWriter) {
+ let sig = format!(
+ "merge_from(&mut self, is: &mut {}::CodedInputStream<'_>) -> {}::ProtobufResult<()>",
+ protobuf_crate_path(&self.customize),
+ protobuf_crate_path(&self.customize),
+ );
+ w.def_fn(&sig, |w| {
+ w.while_block("!is.eof()?", |w| {
+ w.write_line(&format!("let (field_number, wire_type) = is.read_tag_unpack()?;"));
+ w.match_block("field_number", |w| {
+ for f in &self.fields_except_group() {
+ let number = f.proto_field.number();
+ w.case_block(number.to_string(), |w| {
+ f.write_merge_from_field("wire_type", w);
+ });
+ }
+ w.case_block("_", |w| {
+ w.write_line(&format!("{}::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;", protobuf_crate_path(&self.customize)));
+ });
+ });
+ });
+ w.write_line("::std::result::Result::Ok(())");
+ });
+ }
+
+ fn write_descriptor_field(&self, fields_var: &str, field: &FieldGen, w: &mut CodeWriter) {
+ let accessor_fn = field.accessor_fn();
+ w.write_line(&format!(
+ "{}.push({}::reflect::accessor::{}(",
+ fields_var,
+ protobuf_crate_path(&self.customize),
+ accessor_fn.sig()
+ ));
+ w.indented(|w| {
+ w.write_line(&format!("\"{}\",", field.proto_field.name()));
+ match accessor_fn.style {
+ AccessorStyle::Lambda => {
+ w.write_line(&format!(
+ "|m: &{}| {{ &m.{} }},",
+ self.type_name, field.rust_name
+ ));
+ w.write_line(&format!(
+ "|m: &mut {}| {{ &mut m.{} }},",
+ self.type_name, field.rust_name
+ ));
+ }
+ AccessorStyle::HasGet => {
+ w.write_line(&format!("{}::has_{},", self.type_name, field.rust_name));
+ w.write_line(&format!("{}::get_{},", self.type_name, field.rust_name));
+ }
+ }
+ });
+ w.write_line("));");
+ }
+
+ fn write_descriptor_static(&self, w: &mut CodeWriter) {
+ w.def_fn(
+ &format!(
+ "descriptor_static() -> &'static {}::reflect::MessageDescriptor",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.lazy_static_decl_get(
+ "descriptor",
+ &format!(
+ "{}::reflect::MessageDescriptor",
+ protobuf_crate_path(&self.customize)
+ ),
+ &self.customize,
+ |w| {
+ let fields = self.fields_except_group();
+ if fields.is_empty() {
+ w.write_line(&format!("let fields = ::std::vec::Vec::new();"));
+ } else {
+ w.write_line(&format!("let mut fields = ::std::vec::Vec::new();"));
+ }
+ for field in fields {
+ self.write_descriptor_field("fields", field, w);
+ }
+ w.write_line(&format!(
+ "{}::reflect::MessageDescriptor::new_pb_name::<{}>(",
+ protobuf_crate_path(&self.customize),
+ self.type_name
+ ));
+ w.indented(|w| {
+ w.write_line(&format!("\"{}\",", self.message.name_to_package()));
+ w.write_line("fields,");
+ w.write_line(&file_descriptor_proto_expr(&self.message.scope));
+ });
+ w.write_line(")");
+ },
+ );
+ },
+ );
+ }
+
+ fn write_is_initialized(&self, w: &mut CodeWriter) {
+ w.def_fn(&format!("is_initialized(&self) -> bool"), |w| {
+ // TODO: use single loop
+
+ for f in self.required_fields() {
+ f.write_if_self_field_is_none(w, |w| {
+ w.write_line("return false;");
+ });
+ }
+
+ for f in self.message_fields() {
+ if let FieldKind::Map(..) = f.kind {
+ // TODO: check values
+ continue;
+ }
+
+ // TODO:
+ // if message is declared in this file and has no message fields,
+ // we could skip the check here
+ f.write_for_self_field(w, "v", |w, _t| {
+ w.if_stmt("!v.is_initialized()", |w| {
+ w.write_line("return false;");
+ });
+ });
+ }
+ w.write_line("true");
+ });
+ }
+
+ fn write_impl_message(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!("{}::Message", protobuf_crate_path(&self.customize)),
+ &self.type_name.to_string(), |w| {
+ self.write_is_initialized(w);
+ w.write_line("");
+ self.write_merge_from(w);
+ w.write_line("");
+ self.write_compute_size(w);
+ w.write_line("");
+ self.write_write_to_with_cached_sizes(w);
+ w.write_line("");
+ self.write_get_cached_size(w);
+ w.write_line("");
+ self.write_unknown_fields(w);
+ w.write_line("");
+ w.def_fn("as_any(&self) -> &dyn (::std::any::Any)", |w| {
+ w.write_line("self as &dyn (::std::any::Any)");
+ });
+ w.def_fn("as_any_mut(&mut self) -> &mut dyn (::std::any::Any)", |w| {
+ w.write_line("self as &mut dyn (::std::any::Any)");
+ });
+ w.def_fn(
+ "into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)>",
+ |w| {
+ w.write_line("self");
+ },
+ );
+ w.write_line("");
+ w.def_fn(
+ &format!("descriptor(&self) -> &'static {}::reflect::MessageDescriptor", protobuf_crate_path(&self.customize)),
+ |w| {
+ w.write_line("Self::descriptor_static()");
+ },
+ );
+ w.write_line("");
+ w.def_fn(&format!("new() -> {}", self.type_name), |w| {
+ w.write_line(&format!("{}::new()", self.type_name));
+ });
+ if !self.lite_runtime {
+ w.write_line("");
+ self.write_descriptor_static(w);
+ }
+ w.write_line("");
+ self.write_default_instance(w);
+ });
+ }
+
+ fn write_impl_value(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!(
+ "{}::reflect::ProtobufValue",
+ protobuf_crate_path(&self.customize)
+ ),
+ &self.type_name.to_string(),
+ |w| {
+ w.def_fn(
+ &format!(
+ "as_ref(&self) -> {}::reflect::ReflectValueRef",
+ protobuf_crate_path(&self.customize)
+ ),
+ |w| {
+ w.write_line(&format!(
+ "{}::reflect::ReflectValueRef::Message(self)",
+ protobuf_crate_path(&self.customize)
+ ))
+ },
+ )
+ },
+ )
+ }
+
+ fn write_impl_show(&self, w: &mut CodeWriter) {
+ w.impl_for_block("::std::fmt::Debug", &self.type_name.to_string(), |w| {
+ w.def_fn(
+ "fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result",
+ |w| {
+ w.write_line(&format!(
+ "{}::text_format::fmt(self, f)",
+ protobuf_crate_path(&self.customize)
+ ));
+ },
+ );
+ });
+ }
+
+ fn write_impl_clear(&self, w: &mut CodeWriter) {
+ w.impl_for_block(
+ &format!("{}::Clear", protobuf_crate_path(&self.customize)),
+ &format!("{}", self.type_name),
+ |w| {
+ w.def_fn("clear(&mut self)", |w| {
+ for f in self.fields_except_group() {
+ f.write_clear(w);
+ }
+ w.write_line("self.unknown_fields.clear();");
+ });
+ },
+ );
+ }
+
+ #[allow(dead_code)]
+ fn supports_derive_partial_eq(&self) -> bool {
+ // There's stack overflow in the compiler when struct has too many fields
+ // https://github.com/rust-lang/rust/issues/40119
+ self.fields.len() <= 500
+ }
+
+ fn write_struct(&self, w: &mut CodeWriter) {
+ let mut derive = vec!["PartialEq", "Clone", "Default"];
+ if self.lite_runtime {
+ derive.push("Debug");
+ }
+ w.derive(&derive);
+ serde::write_serde_attr(
+ w,
+ &self.customize,
+ "derive(::serde::Serialize, ::serde::Deserialize)",
+ );
+ w.pub_struct(&self.type_name.to_string(), |w| {
+ if !self.fields_except_oneof().is_empty() {
+ w.comment("message fields");
+ for field in self.fields_except_oneof() {
+ if field.proto_type == FieldDescriptorProto_Type::TYPE_GROUP {
+ w.comment(&format!("{}: <group>", &field.rust_name));
+ } else {
+ let vis = if field.expose_field {
+ Visibility::Public
+ } else {
+ match field.kind {
+ FieldKind::Repeated(..) => Visibility::Default,
+ FieldKind::Singular(SingularField { ref flag, .. }) => {
+ match *flag {
+ SingularFieldFlag::WithFlag { .. } => Visibility::Default,
+ SingularFieldFlag::WithoutFlag => Visibility::Public,
+ }
+ }
+ FieldKind::Map(..) => Visibility::Public,
+ FieldKind::Oneof(..) => unreachable!(),
+ }
+ };
+ w.field_decl_vis(
+ vis,
+ &field.rust_name.get(),
+ &field.full_storage_type().to_code(&self.customize),
+ );
+ }
+ }
+ }
+ if !self.oneofs().is_empty() {
+ w.comment("message oneof groups");
+ for oneof in self.oneofs() {
+ let vis = match self.expose_oneof() {
+ true => Visibility::Public,
+ false => Visibility::Default,
+ };
+ w.field_decl_vis(
+ vis,
+ oneof.oneof.field_name().get(),
+ &oneof.full_storage_type().to_code(&self.customize),
+ );
+ }
+ }
+ w.comment("special fields");
+ serde::write_serde_attr(w, &self.customize, "serde(skip)");
+ w.pub_field_decl(
+ "unknown_fields",
+ &format!("{}::UnknownFields", protobuf_crate_path(&self.customize)),
+ );
+ serde::write_serde_attr(w, &self.customize, "serde(skip)");
+ w.pub_field_decl(
+ "cached_size",
+ &format!("{}::CachedSize", protobuf_crate_path(&self.customize)),
+ );
+ });
+ }
+
+ fn write_impl_default_for_amp(&self, w: &mut CodeWriter) {
+ w.impl_args_for_block(
+ &["'a"],
+ "::std::default::Default",
+ &format!("&'a {}", self.type_name),
+ |w| {
+ w.def_fn(&format!("default() -> &'a {}", self.type_name), |w| {
+ w.write_line(&format!(
+ "<{} as {}::Message>::default_instance()",
+ self.type_name,
+ protobuf_crate_path(&self.customize),
+ ));
+ });
+ },
+ );
+ }
+
+ pub fn write(&self, w: &mut CodeWriter) {
+ self.write_struct(w);
+
+ w.write_line("");
+ self.write_impl_default_for_amp(w);
+
+ for oneof in self.oneofs() {
+ w.write_line("");
+ oneof.write_enum(w);
+ }
+
+ w.write_line("");
+ self.write_impl_self(w);
+ w.write_line("");
+ self.write_impl_message(w);
+ w.write_line("");
+ self.write_impl_clear(w);
+ if !self.lite_runtime {
+ w.write_line("");
+ self.write_impl_show(w);
+ }
+ w.write_line("");
+ self.write_impl_value(w);
+
+ let mut nested_prefix = self.type_name.to_string();
+ nested_prefix.push_str("_");
+
+ for nested in &self.message.to_scope().get_messages() {
+ // ignore map entries, because they are not used in map fields
+ if nested.map_entry().is_none() {
+ w.write_line("");
+ MessageGen::new(nested, self.root_scope, &self.customize).write(w);
+ }
+ }
+
+ for enum_type in &self.message.to_scope().get_enums() {
+ w.write_line("");
+ let current_file = self.message.get_scope().get_file_descriptor();
+ EnumGen::new(enum_type, current_file, &self.customize, self.root_scope).write(w);
+ }
+ }
+}
diff --git a/2.27.1/src/oneof.rs b/2.27.1/src/oneof.rs
new file mode 100644
index 0000000..44201ea
--- /dev/null
+++ b/2.27.1/src/oneof.rs
@@ -0,0 +1,198 @@
+//! Oneof-related codegen functions.
+
+use std::collections::HashSet;
+
+use code_writer::CodeWriter;
+use field::FieldElem;
+use field::FieldGen;
+use message::MessageGen;
+use protobuf::descriptor::FieldDescriptorProto_Type;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_name::RustIdent;
+use rust_types_values::RustType;
+use scope::FieldWithContext;
+use scope::OneofVariantWithContext;
+use scope::OneofWithContext;
+use scope::RootScope;
+use scope::WithScope;
+use serde;
+use Customize;
+
+// oneof one { ... }
+#[derive(Clone)]
+pub(crate) struct OneofField<'a> {
+ pub elem: FieldElem<'a>,
+ pub oneof_rust_field_name: RustIdent,
+ pub oneof_type_name: RustType,
+ pub boxed: bool,
+}
+
+impl<'a> OneofField<'a> {
+ // Detecting recursion: if oneof fields contains a self-reference
+ // or another message which has a reference to self,
+ // put oneof variant into a box.
+ fn need_boxed(field: &FieldWithContext, root_scope: &RootScope, owner_name: &str) -> bool {
+ let mut visited_messages = HashSet::new();
+ let mut fields = vec![field.clone()];
+ while let Some(field) = fields.pop() {
+ if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_MESSAGE {
+ let message_name = ProtobufAbsolutePath::from(field.field.get_type_name());
+ if !visited_messages.insert(message_name.clone()) {
+ continue;
+ }
+ if message_name.path == owner_name {
+ return true;
+ }
+ let message = root_scope.find_message(&message_name);
+ fields.extend(message.fields().into_iter().filter(|f| f.is_oneof()));
+ }
+ }
+ false
+ }
+
+ pub fn parse(
+ oneof: &OneofWithContext<'a>,
+ field: &FieldWithContext<'a>,
+ elem: FieldElem<'a>,
+ root_scope: &RootScope,
+ ) -> OneofField<'a> {
+ let boxed = OneofField::need_boxed(field, root_scope, &oneof.message.name_absolute().path);
+
+ OneofField {
+ elem,
+ boxed,
+ oneof_rust_field_name: oneof.field_name().into(),
+ oneof_type_name: RustType::Oneof(oneof.rust_name().to_string()),
+ }
+ }
+
+ pub fn rust_type(&self) -> RustType {
+ let t = self.elem.rust_storage_type();
+
+ if self.boxed {
+ RustType::Uniq(Box::new(t))
+ } else {
+ t
+ }
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofVariantGen<'a> {
+ _oneof: &'a OneofGen<'a>,
+ _variant: OneofVariantWithContext<'a>,
+ oneof_field: OneofField<'a>,
+ pub field: FieldGen<'a>,
+ path: String,
+ _customize: Customize,
+}
+
+impl<'a> OneofVariantGen<'a> {
+ fn parse(
+ oneof: &'a OneofGen<'a>,
+ variant: OneofVariantWithContext<'a>,
+ field: &'a FieldGen,
+ _root_scope: &RootScope,
+ customize: Customize,
+ ) -> OneofVariantGen<'a> {
+ OneofVariantGen {
+ _oneof: oneof,
+ _variant: variant.clone(),
+ field: field.clone(),
+ path: format!(
+ "{}::{}",
+ oneof.type_name.to_code(&field.customize),
+ field.rust_name
+ ),
+ oneof_field: OneofField::parse(
+ variant.oneof,
+ &field.proto_field,
+ field.oneof().elem.clone(),
+ oneof.message.root_scope,
+ ),
+ _customize: customize,
+ }
+ }
+
+ fn rust_type(&self) -> RustType {
+ self.oneof_field.rust_type()
+ }
+
+ pub fn path(&self) -> String {
+ self.path.clone()
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofGen<'a> {
+ // Message containing this oneof
+ message: &'a MessageGen<'a>,
+ pub oneof: OneofWithContext<'a>,
+ type_name: RustType,
+ customize: Customize,
+}
+
+impl<'a> OneofGen<'a> {
+ pub fn parse(
+ message: &'a MessageGen,
+ oneof: OneofWithContext<'a>,
+ customize: &Customize,
+ ) -> OneofGen<'a> {
+ let rust_name = oneof.rust_name();
+ OneofGen {
+ message,
+ oneof,
+ type_name: RustType::Oneof(rust_name.to_string()),
+ customize: customize.clone(),
+ }
+ }
+
+ pub fn variants_except_group(&'a self) -> Vec<OneofVariantGen<'a>> {
+ self.oneof
+ .variants()
+ .into_iter()
+ .filter_map(|v| {
+ let field = self
+ .message
+ .fields
+ .iter()
+ .filter(|f| f.proto_field.name() == v.field.get_name())
+ .next()
+ .expect(&format!("field not found by name: {}", v.field.get_name()));
+ match field.proto_type {
+ FieldDescriptorProto_Type::TYPE_GROUP => None,
+ _ => Some(OneofVariantGen::parse(
+ self,
+ v,
+ field,
+ self.message.root_scope,
+ self.customize.clone(),
+ )),
+ }
+ })
+ .collect()
+ }
+
+ pub fn full_storage_type(&self) -> RustType {
+ RustType::Option(Box::new(self.type_name.clone()))
+ }
+
+ pub fn write_enum(&self, w: &mut CodeWriter) {
+ let derive = vec!["Clone", "PartialEq", "Debug"];
+ w.derive(&derive);
+ serde::write_serde_attr(
+ w,
+ &self.customize,
+ "derive(::serde::Serialize, ::serde::Deserialize)",
+ );
+ w.pub_enum(&self.type_name.to_code(&self.customize), |w| {
+ for variant in self.variants_except_group() {
+ w.write_line(&format!(
+ "{}({}),",
+ variant.field.rust_name,
+ &variant.rust_type().to_code(&self.customize)
+ ));
+ }
+ });
+ }
+}
diff --git a/2.27.1/src/protobuf_name.rs b/2.27.1/src/protobuf_name.rs
new file mode 100644
index 0000000..c40a69c
--- /dev/null
+++ b/2.27.1/src/protobuf_name.rs
@@ -0,0 +1,374 @@
+use std::fmt;
+
+/// Identifier in `.proto` file
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub struct ProtobufIdent(String);
+
+impl ProtobufIdent {
+ /// New ident from a string.
+ #[allow(dead_code)]
+ pub fn new(s: &str) -> ProtobufIdent {
+ assert!(!s.is_empty());
+ assert!(!s.contains("/"));
+ assert!(!s.contains("."));
+ assert!(!s.contains(":"));
+ ProtobufIdent(s.to_owned())
+ }
+
+ /// Get as a string.
+ pub fn get(&self) -> &str {
+ &self.0
+ }
+}
+
+impl From<&'_ str> for ProtobufIdent {
+ fn from(s: &str) -> Self {
+ ProtobufIdent::new(s)
+ }
+}
+
+impl From<String> for ProtobufIdent {
+ fn from(s: String) -> Self {
+ ProtobufIdent::new(&s)
+ }
+}
+
+impl fmt::Display for ProtobufIdent {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.get(), f)
+ }
+}
+
+/// Relative protobuf identifier path.
+#[derive(Debug, Eq, PartialEq, Clone)]
+pub struct ProtobufRelativePath {
+ /// The path
+ pub path: String,
+}
+
+#[allow(dead_code)]
+impl ProtobufRelativePath {
+ /// Empty relative path.
+ pub fn empty() -> ProtobufRelativePath {
+ ProtobufRelativePath::new(String::new())
+ }
+
+ /// New path from a string.
+ pub fn new(path: String) -> ProtobufRelativePath {
+ assert!(!path.starts_with("."));
+
+ ProtobufRelativePath { path }
+ }
+
+ /// From path components.
+ pub fn from_components<I: IntoIterator<Item = ProtobufIdent>>(i: I) -> ProtobufRelativePath {
+ let v: Vec<String> = i.into_iter().map(|c| c.get().to_owned()).collect();
+ ProtobufRelativePath::from(v.join("."))
+ }
+
+ /// Get the string.
+ pub fn get(&self) -> &str {
+ &self.path
+ }
+
+ /// The path is empty.
+ pub fn is_empty(&self) -> bool {
+ self.path.is_empty()
+ }
+
+ /// As absolute path from root namespace.
+ pub fn into_absolute(self) -> ProtobufAbsolutePath {
+ if self.is_empty() {
+ ProtobufAbsolutePath::root()
+ } else {
+ ProtobufAbsolutePath::from(format!(".{}", self))
+ }
+ }
+
+ fn _last_part(&self) -> Option<&str> {
+ match self.path.rfind('.') {
+ Some(pos) => Some(&self.path[pos + 1..]),
+ None => {
+ if self.path.is_empty() {
+ None
+ } else {
+ Some(&self.path)
+ }
+ }
+ }
+ }
+
+ fn parent(&self) -> Option<ProtobufRelativePath> {
+ match self.path.rfind('.') {
+ Some(pos) => Some(ProtobufRelativePath::new(self.path[..pos].to_owned())),
+ None => {
+ if self.path.is_empty() {
+ None
+ } else {
+ Some(ProtobufRelativePath::empty())
+ }
+ }
+ }
+ }
+
+ /// Self path and parent paths.
+ pub fn self_and_parents(&self) -> Vec<ProtobufRelativePath> {
+ let mut tmp = self.clone();
+
+ let mut r = Vec::new();
+
+ r.push(self.clone());
+
+ while let Some(parent) = tmp.parent() {
+ r.push(parent.clone());
+ tmp = parent;
+ }
+
+ r
+ }
+
+ /// Append path component.
+ pub fn append(&self, simple: &ProtobufRelativePath) -> ProtobufRelativePath {
+ if self.path.is_empty() {
+ ProtobufRelativePath::from(simple.get())
+ } else {
+ ProtobufRelativePath::new(format!("{}.{}", self.path, simple))
+ }
+ }
+
+ /// Append identifier to the path.
+ pub fn append_ident(&self, simple: &ProtobufIdent) -> ProtobufRelativePath {
+ self.append(&ProtobufRelativePath::from(simple.clone()))
+ }
+
+ /// Get first component path and remaining.
+ pub fn split_first_rem(&self) -> Option<(ProtobufIdent, ProtobufRelativePath)> {
+ if self.is_empty() {
+ None
+ } else {
+ Some(match self.path.find('.') {
+ Some(dot) => (
+ ProtobufIdent::from(&self.path[..dot]),
+ ProtobufRelativePath::new(self.path[dot + 1..].to_owned()),
+ ),
+ None => (
+ ProtobufIdent::from(self.path.clone()),
+ ProtobufRelativePath::empty(),
+ ),
+ })
+ }
+ }
+}
+
+impl From<&'_ str> for ProtobufRelativePath {
+ fn from(s: &str) -> ProtobufRelativePath {
+ ProtobufRelativePath::from(s.to_owned())
+ }
+}
+
+impl From<String> for ProtobufRelativePath {
+ fn from(s: String) -> ProtobufRelativePath {
+ ProtobufRelativePath::new(s)
+ }
+}
+
+impl From<ProtobufIdent> for ProtobufRelativePath {
+ fn from(s: ProtobufIdent) -> ProtobufRelativePath {
+ ProtobufRelativePath::from(s.get())
+ }
+}
+
+impl From<Vec<ProtobufIdent>> for ProtobufRelativePath {
+ fn from(s: Vec<ProtobufIdent>) -> ProtobufRelativePath {
+ ProtobufRelativePath::from_components(s.into_iter())
+ }
+}
+
+impl fmt::Display for ProtobufRelativePath {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.path, f)
+ }
+}
+
+#[cfg(test)]
+mod relative_path_test {
+ use super::*;
+
+ #[test]
+ fn parent() {
+ assert_eq!(None, ProtobufRelativePath::empty().parent());
+ assert_eq!(
+ Some(ProtobufRelativePath::empty()),
+ ProtobufRelativePath::new("aaa".to_owned()).parent()
+ );
+ assert_eq!(
+ Some(ProtobufRelativePath::new("abc".to_owned())),
+ ProtobufRelativePath::new("abc.def".to_owned()).parent()
+ );
+ assert_eq!(
+ Some(ProtobufRelativePath::new("abc.def".to_owned())),
+ ProtobufRelativePath::new("abc.def.gh".to_owned()).parent()
+ );
+ }
+
+ #[test]
+ fn last_part() {
+ assert_eq!(None, ProtobufRelativePath::empty()._last_part());
+ assert_eq!(
+ Some("aaa"),
+ ProtobufRelativePath::new("aaa".to_owned())._last_part()
+ );
+ assert_eq!(
+ Some("def"),
+ ProtobufRelativePath::new("abc.def".to_owned())._last_part()
+ );
+ assert_eq!(
+ Some("gh"),
+ ProtobufRelativePath::new("abc.def.gh".to_owned())._last_part()
+ );
+ }
+}
+
+/// Absolute protobuf path (e. g. package).
+///
+/// This is not filesystem path.
+#[derive(Clone, Eq, PartialEq, Debug, Hash)]
+pub struct ProtobufAbsolutePath {
+ /// The path.
+ pub path: String,
+}
+
+impl ProtobufAbsolutePath {
+ fn root() -> ProtobufAbsolutePath {
+ ProtobufAbsolutePath::new(String::new())
+ }
+
+ /// From string.
+ pub fn new(path: String) -> ProtobufAbsolutePath {
+ assert!(path.is_empty() || path.starts_with("."), "{}", path);
+ assert!(!path.ends_with("."), "{}", path);
+ ProtobufAbsolutePath { path }
+ }
+
+ /// The path is empty.
+ pub fn is_empty(&self) -> bool {
+ self.path.is_empty()
+ }
+
+ /// From a path without leading dot.
+ ///
+ /// (Protobuf paths start with dot).
+ pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
+ if path.is_empty() {
+ ProtobufAbsolutePath::root()
+ } else {
+ assert!(!path.starts_with("."));
+ assert!(!path.ends_with("."));
+ ProtobufAbsolutePath::new(format!(".{}", path))
+ }
+ }
+
+ /// Parse absolute path.
+ #[allow(dead_code)]
+ pub fn from_package_path(path: Option<&str>) -> ProtobufAbsolutePath {
+ match path {
+ None => ProtobufAbsolutePath::root(),
+ Some(path) => ProtobufAbsolutePath::from_path_without_dot(path),
+ }
+ }
+
+ /// Construct abs path from a string which may start with a dot.
+ pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
+ if path.starts_with(".") {
+ ProtobufAbsolutePath::new(path.to_owned())
+ } else {
+ ProtobufAbsolutePath::from_path_without_dot(path)
+ }
+ }
+
+ /// Push identifier to the path.
+ pub fn push_simple(&mut self, simple: ProtobufIdent) {
+ self.path.push('.');
+ self.path.push_str(simple.get());
+ }
+
+ /// Push relative path.
+ pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
+ if !relative.is_empty() {
+ self.path.push('.');
+ self.path.push_str(&relative.path);
+ }
+ }
+
+ /// Try remove a prefix.
+ pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
+ if self.path.starts_with(&prefix.path) {
+ let rem = &self.path[prefix.path.len()..];
+ if rem.is_empty() {
+ return Some(ProtobufRelativePath::empty());
+ }
+ if rem.starts_with('.') {
+ return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
+ }
+ }
+ None
+ }
+}
+
+impl From<&'_ str> for ProtobufAbsolutePath {
+ fn from(s: &str) -> Self {
+ ProtobufAbsolutePath::new(s.to_owned())
+ }
+}
+
+impl From<String> for ProtobufAbsolutePath {
+ fn from(s: String) -> Self {
+ ProtobufAbsolutePath::new(s)
+ }
+}
+
+impl fmt::Display for ProtobufAbsolutePath {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.path, f)
+ }
+}
+
+#[cfg(test)]
+mod absolute_path_test {
+ use super::*;
+
+ #[test]
+ fn absolute_path_push_simple() {
+ let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
+ foo.push_simple(ProtobufIdent::from("bar"));
+ assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);
+
+ let mut foo = ProtobufAbsolutePath::root();
+ foo.push_simple(ProtobufIdent::from("bar"));
+ assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
+ }
+
+ #[test]
+ fn absolute_path_remove_prefix() {
+ assert_eq!(
+ Some(ProtobufRelativePath::empty()),
+ ProtobufAbsolutePath::new(".foo".to_owned())
+ .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
+ );
+ assert_eq!(
+ Some(ProtobufRelativePath::new("bar".to_owned())),
+ ProtobufAbsolutePath::new(".foo.bar".to_owned())
+ .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
+ );
+ assert_eq!(
+ Some(ProtobufRelativePath::new("baz.qux".to_owned())),
+ ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
+ .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
+ );
+ assert_eq!(
+ None,
+ ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
+ .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
+ );
+ }
+}
diff --git a/2.27.1/src/rust.rs b/2.27.1/src/rust.rs
new file mode 100644
index 0000000..263cba0
--- /dev/null
+++ b/2.27.1/src/rust.rs
@@ -0,0 +1,62 @@
+#[cfg_attr(rustfmt, rustfmt_skip)]
+static RUST_KEYWORDS: &'static [&'static str] = &[
+ "as",
+ "async",
+ "await",
+ "break",
+ "crate",
+ "dyn",
+ "else",
+ "enum",
+ "extern",
+ "false",
+ "fn",
+ "for",
+ "if",
+ "impl",
+ "in",
+ "let",
+ "loop",
+ "match",
+ "mod",
+ "move",
+ "mut",
+ "pub",
+ "ref",
+ "return",
+ "static",
+ "self",
+ "Self",
+ "struct",
+ "super",
+ "true",
+ "trait",
+ "type",
+ "unsafe",
+ "use",
+ "while",
+ "continue",
+ "box",
+ "const",
+ "where",
+ "virtual",
+ "proc",
+ "alignof",
+ "become",
+ "offsetof",
+ "priv",
+ "pure",
+ "sizeof",
+ "typeof",
+ "unsized",
+ "yield",
+ "do",
+ "abstract",
+ "final",
+ "override",
+ "macro",
+];
+
+pub fn is_rust_keyword(ident: &str) -> bool {
+ RUST_KEYWORDS.contains(&ident)
+}
diff --git a/2.27.1/src/rust_name.rs b/2.27.1/src/rust_name.rs
new file mode 100644
index 0000000..234925b
--- /dev/null
+++ b/2.27.1/src/rust_name.rs
@@ -0,0 +1,273 @@
+use std::fmt;
+use std::iter;
+
+/// Valid Rust identifier
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustIdent(String);
+
+#[allow(dead_code)]
+impl RustIdent {
+ pub fn new(s: &str) -> RustIdent {
+ assert!(!s.is_empty());
+ assert!(!s.contains("/"), "{}", s);
+ assert!(!s.contains("."), "{}", s);
+ assert!(!s.contains(":"), "{}", s);
+ RustIdent(s.to_owned())
+ }
+
+ pub fn super_ident() -> RustIdent {
+ RustIdent::new("super")
+ }
+
+ pub fn get(&self) -> &str {
+ &self.0
+ }
+
+ pub fn into_string(self) -> String {
+ self.0
+ }
+
+ pub fn to_path(&self) -> RustIdentWithPath {
+ RustIdentWithPath::from(&self.0)
+ }
+}
+
+impl fmt::Display for RustIdent {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.get(), f)
+ }
+}
+
+impl From<&'_ str> for RustIdent {
+ fn from(s: &str) -> Self {
+ RustIdent::new(s)
+ }
+}
+
+impl From<String> for RustIdent {
+ fn from(s: String) -> Self {
+ RustIdent::new(&s)
+ }
+}
+
+impl Into<String> for RustIdent {
+ fn into(self) -> String {
+ self.0
+ }
+}
+
+#[derive(Default, Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustRelativePath {
+ path: Vec<RustIdent>,
+}
+
+#[allow(dead_code)]
+impl RustRelativePath {
+ pub fn into_path(self) -> RustPath {
+ RustPath {
+ absolute: false,
+ path: self,
+ }
+ }
+
+ pub fn empty() -> RustRelativePath {
+ RustRelativePath { path: Vec::new() }
+ }
+
+ pub fn from_components<I: IntoIterator<Item = RustIdent>>(i: I) -> RustRelativePath {
+ RustRelativePath {
+ path: i.into_iter().collect(),
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.path.is_empty()
+ }
+
+ pub fn first(&self) -> Option<RustIdent> {
+ self.path.iter().cloned().next()
+ }
+
+ pub fn remove_first(&mut self) -> Option<RustIdent> {
+ if self.path.is_empty() {
+ None
+ } else {
+ Some(self.path.remove(0))
+ }
+ }
+
+ pub fn prepend_ident(&mut self, ident: RustIdent) {
+ self.path.insert(0, ident);
+ }
+
+ pub fn append(mut self, path: RustRelativePath) -> RustRelativePath {
+ for c in path.path {
+ self.path.push(c);
+ }
+ self
+ }
+
+ pub fn push_ident(&mut self, ident: RustIdent) {
+ self.path.push(ident);
+ }
+
+ pub fn _append_ident(mut self, ident: RustIdent) -> RustRelativePath {
+ self.push_ident(ident);
+ self
+ }
+
+ pub fn to_reverse(&self) -> RustRelativePath {
+ RustRelativePath::from_components(
+ iter::repeat(RustIdent::super_ident()).take(self.path.len()),
+ )
+ }
+}
+
+#[derive(Default, Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustPath {
+ absolute: bool,
+ path: RustRelativePath,
+}
+
+impl fmt::Display for RustRelativePath {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ for (i, c) in self.path.iter().enumerate() {
+ if i != 0 {
+ write!(f, "::")?;
+ }
+ write!(f, "{}", c)?;
+ }
+ Ok(())
+ }
+}
+
+impl From<&'_ str> for RustRelativePath {
+ fn from(s: &str) -> Self {
+ RustRelativePath {
+ path: s.split("::").map(RustIdent::from).collect(),
+ }
+ }
+}
+
+#[allow(dead_code)]
+impl RustPath {
+ pub fn is_absolute(&self) -> bool {
+ self.absolute
+ }
+
+ pub fn is_empty(&self) -> bool {
+ assert!(!self.absolute);
+ self.path.is_empty()
+ }
+
+ pub fn with_ident(self, ident: RustIdent) -> RustIdentWithPath {
+ RustIdentWithPath { path: self, ident }
+ }
+
+ pub fn first(&self) -> Option<RustIdent> {
+ assert!(!self.absolute);
+ self.path.first()
+ }
+
+ pub fn remove_first(&mut self) -> Option<RustIdent> {
+ assert!(!self.absolute);
+ self.path.remove_first()
+ }
+
+ pub fn to_reverse(&self) -> RustPath {
+ assert!(!self.absolute);
+ RustPath {
+ absolute: false,
+ path: self.path.to_reverse(),
+ }
+ }
+
+ pub fn prepend_ident(&mut self, ident: RustIdent) {
+ assert!(!self.absolute);
+ self.path.prepend_ident(ident);
+ }
+
+ pub fn append(self, path: RustPath) -> RustPath {
+ if path.absolute {
+ path
+ } else {
+ RustPath {
+ absolute: self.absolute,
+ path: self.path.append(path.path),
+ }
+ }
+ }
+
+ pub fn append_ident(mut self, ident: RustIdent) -> RustPath {
+ self.path.path.push(ident);
+ self
+ }
+
+ pub fn append_with_ident(self, path: RustIdentWithPath) -> RustIdentWithPath {
+ self.append(path.path).with_ident(path.ident)
+ }
+}
+
+impl From<&'_ str> for RustPath {
+ fn from(s: &str) -> Self {
+ let (s, absolute) = if s.starts_with("::") {
+ (&s[2..], true)
+ } else {
+ (s, false)
+ };
+ RustPath {
+ absolute,
+ path: RustRelativePath::from(s),
+ }
+ }
+}
+
+impl From<String> for RustPath {
+ fn from(s: String) -> Self {
+ RustPath::from(&s[..])
+ }
+}
+
+impl fmt::Display for RustPath {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.absolute {
+ write!(f, "::")?;
+ }
+ write!(f, "{}", self.path)
+ }
+}
+
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub(crate) struct RustIdentWithPath {
+ pub path: RustPath,
+ pub ident: RustIdent,
+}
+
+#[allow(dead_code)]
+impl RustIdentWithPath {
+ pub fn new(s: String) -> RustIdentWithPath {
+ let mut path = RustPath::from(s);
+ let ident = path.path.path.pop().unwrap();
+ RustIdentWithPath { path, ident }
+ }
+
+ pub fn prepend_ident(&mut self, ident: RustIdent) {
+ self.path.prepend_ident(ident)
+ }
+
+ pub fn to_path(&self) -> RustPath {
+ self.path.clone().append_ident(self.ident.clone())
+ }
+}
+
+impl<S: Into<String>> From<S> for RustIdentWithPath {
+ fn from(s: S) -> Self {
+ RustIdentWithPath::new(s.into())
+ }
+}
+
+impl fmt::Display for RustIdentWithPath {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.to_path(), f)
+ }
+}
diff --git a/2.27.1/src/rust_types_values.rs b/2.27.1/src/rust_types_values.rs
new file mode 100644
index 0000000..e9b017d
--- /dev/null
+++ b/2.27.1/src/rust_types_values.rs
@@ -0,0 +1,593 @@
+use std::cmp;
+
+use inside::protobuf_crate_path;
+use message::RustTypeMessage;
+use protobuf::descriptor::*;
+use protobuf_name::ProtobufAbsolutePath;
+use rust_name::RustIdent;
+use scope::RootScope;
+use scope::WithScope;
+use strx::capitalize;
+use Customize;
+
+use super::well_known_types::is_well_known_type_full;
+
+// Represent subset of rust types used in generated code
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) enum RustType {
+ // integer: signed?, size in bits
+ Int(bool, u32),
+ // param is size in bits
+ Float(u32),
+ Bool,
+ Vec(Box<RustType>),
+ HashMap(Box<RustType>, Box<RustType>),
+ String,
+ // [T], not &[T]
+ Slice(Box<RustType>),
+ // str, not &str
+ Str,
+ Option(Box<RustType>),
+ SingularField(Box<RustType>),
+ SingularPtrField(Box<RustType>),
+ RepeatedField(Box<RustType>),
+ // Box<T>
+ Uniq(Box<RustType>),
+ // &T
+ Ref(Box<RustType>),
+ // protobuf message
+ Message(RustTypeMessage),
+ // protobuf enum, not any enum
+ Enum(String, RustIdent),
+ // oneof enum
+ Oneof(String),
+ // bytes::Bytes
+ Bytes,
+ // chars::Chars
+ Chars,
+ // group
+ Group,
+}
+
+impl RustType {
+ #[inline]
+ pub(crate) fn to_code(&self, customize: &Customize) -> String {
+ match *self {
+ RustType::Int(true, bits) => format!("i{}", bits),
+ RustType::Int(false, bits) => format!("u{}", bits),
+ RustType::Float(bits) => format!("f{}", bits),
+ RustType::Bool => format!("bool"),
+ RustType::Vec(ref param) => format!("::std::vec::Vec<{}>", param.to_code(customize)),
+ RustType::HashMap(ref key, ref value) => format!(
+ "::std::collections::HashMap<{}, {}>",
+ key.to_code(customize),
+ value.to_code(customize)
+ ),
+ RustType::String => format!("::std::string::String"),
+ RustType::Slice(ref param) => format!("[{}]", param.to_code(customize)),
+ RustType::Str => format!("str"),
+ RustType::Option(ref param) => {
+ format!("::std::option::Option<{}>", param.to_code(customize))
+ }
+ RustType::SingularField(ref param) => format!(
+ "{}::SingularField<{}>",
+ protobuf_crate_path(customize),
+ param.to_code(customize)
+ ),
+ RustType::SingularPtrField(ref param) => format!(
+ "{}::SingularPtrField<{}>",
+ protobuf_crate_path(customize),
+ param.to_code(customize)
+ ),
+ RustType::RepeatedField(ref param) => format!(
+ "{}::RepeatedField<{}>",
+ protobuf_crate_path(customize),
+ param.to_code(customize)
+ ),
+ RustType::Uniq(ref param) => format!("::std::boxed::Box<{}>", param.to_code(customize)),
+ RustType::Ref(ref param) => format!("&{}", param.to_code(customize)),
+ RustType::Message(ref name) => format!("{}", name),
+ RustType::Enum(ref name, _) | RustType::Oneof(ref name) => format!("{}", name),
+ RustType::Group => format!("<group>"),
+ RustType::Bytes => format!("::bytes::Bytes"),
+ RustType::Chars => format!("{}::Chars", protobuf_crate_path(customize)),
+ }
+ }
+}
+
+impl RustType {
+ pub fn u8() -> RustType {
+ RustType::Int(false, 8)
+ }
+
+ /// Type is rust primitive?
+ pub fn is_primitive(&self) -> bool {
+ match *self {
+ RustType::Int(..) | RustType::Float(..) | RustType::Bool => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_u8(&self) -> bool {
+ match *self {
+ RustType::Int(false, 8) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_copy(&self) -> bool {
+ if self.is_primitive() {
+ true
+ } else if let RustType::Enum(..) = *self {
+ true
+ } else {
+ false
+ }
+ }
+
+ fn is_str(&self) -> bool {
+ match *self {
+ RustType::Str => true,
+ _ => false,
+ }
+ }
+
+ fn is_string(&self) -> bool {
+ match *self {
+ RustType::String => true,
+ _ => false,
+ }
+ }
+
+ fn is_slice(&self) -> Option<&RustType> {
+ match *self {
+ RustType::Slice(ref v) => Some(&**v),
+ _ => None,
+ }
+ }
+
+ fn is_slice_u8(&self) -> bool {
+ match self.is_slice() {
+ Some(t) => t.is_u8(),
+ None => false,
+ }
+ }
+
+ fn is_message(&self) -> bool {
+ match *self {
+ RustType::Message(..) => true,
+ _ => false,
+ }
+ }
+
+ fn is_enum(&self) -> bool {
+ match *self {
+ RustType::Enum(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_ref(&self) -> bool {
+ match *self {
+ RustType::Ref(..) => true,
+ _ => false,
+ }
+ }
+
+ // default value for type
+ pub fn default_value(&self, customize: &Customize) -> String {
+ match *self {
+ RustType::Ref(ref t) if t.is_str() => "\"\"".to_string(),
+ RustType::Ref(ref t) if t.is_slice().is_some() => "&[]".to_string(),
+ RustType::Int(..) => "0".to_string(),
+ RustType::Float(..) => "0.".to_string(),
+ RustType::Bool => "false".to_string(),
+ RustType::Vec(..) => "::std::vec::Vec::new()".to_string(),
+ RustType::HashMap(..) => "::std::collections::HashMap::new()".to_string(),
+ RustType::String => "::std::string::String::new()".to_string(),
+ RustType::Bytes => "::bytes::Bytes::new()".to_string(),
+ RustType::Chars => format!("{}::Chars::new()", protobuf_crate_path(customize)),
+ RustType::Option(..) => "::std::option::Option::None".to_string(),
+ RustType::SingularField(..) => {
+ format!("{}::SingularField::none()", protobuf_crate_path(customize))
+ }
+ RustType::SingularPtrField(..) => format!(
+ "{}::SingularPtrField::none()",
+ protobuf_crate_path(customize)
+ ),
+ RustType::RepeatedField(..) => {
+ format!("{}::RepeatedField::new()", protobuf_crate_path(customize))
+ }
+ RustType::Message(ref name) => format!("{}::new()", name),
+ RustType::Ref(ref m) if m.is_message() => match **m {
+ RustType::Message(ref name) => name.default_instance(customize),
+ _ => unreachable!(),
+ },
+ // Note: default value of enum type may not be equal to default value of field
+ RustType::Enum(ref name, ref default) => format!("{}::{}", name, default),
+ _ => panic!("cannot create default value for: {:?}", *self),
+ }
+ }
+
+ pub fn default_value_typed(self, customize: &Customize) -> RustValueTyped {
+ RustValueTyped {
+ value: self.default_value(customize),
+ rust_type: self,
+ }
+ }
+
+ /// Emit a code to clear a variable `v`
+ pub fn clear(&self, v: &str, customize: &Customize) -> String {
+ match *self {
+ RustType::Option(..) => format!("{} = ::std::option::Option::None", v),
+ RustType::Vec(..)
+ | RustType::Bytes
+ | RustType::String
+ | RustType::RepeatedField(..)
+ | RustType::SingularField(..)
+ | RustType::SingularPtrField(..)
+ | RustType::HashMap(..) => format!("{}.clear()", v),
+ RustType::Chars => format!(
+ "{}::Clear::clear(&mut {})",
+ protobuf_crate_path(customize),
+ v
+ ),
+ RustType::Bool | RustType::Float(..) | RustType::Int(..) | RustType::Enum(..) => {
+ format!("{} = {}", v, self.default_value(customize))
+ }
+ ref ty => panic!("cannot clear type: {:?}", ty),
+ }
+ }
+
+ // wrap value in storage type
+ pub fn wrap_value(&self, value: &str, customize: &Customize) -> String {
+ match *self {
+ RustType::Option(..) => format!("::std::option::Option::Some({})", value),
+ RustType::SingularField(..) => format!(
+ "{}::SingularField::some({})",
+ protobuf_crate_path(customize),
+ value
+ ),
+ RustType::SingularPtrField(..) => format!(
+ "{}::SingularPtrField::some({})",
+ protobuf_crate_path(customize),
+ value
+ ),
+ _ => panic!("not a wrapper type: {:?}", *self),
+ }
+ }
+
+ // expression to convert `v` of type `self` to type `target`
+ pub fn into_target(&self, target: &RustType, v: &str, customize: &Customize) -> String {
+ self.try_into_target(target, v, customize)
+ .expect(&format!("failed to convert {:?} into {:?}", self, target))
+ }
+
+ fn try_into_target(
+ &self,
+ target: &RustType,
+ v: &str,
+ customize: &Customize,
+ ) -> Result<String, ()> {
+ match (self, target) {
+ (x, y) if x == y => return Ok(format!("{}", v)),
+ (&RustType::Ref(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
+ (x, &RustType::Uniq(ref y)) if *x == **y => {
+ return Ok(format!("::std::boxed::Box::new({})", v))
+ }
+ (&RustType::Uniq(ref x), y) if **x == *y => return Ok(format!("*{}", v)),
+ (&RustType::String, &RustType::Ref(ref t)) if **t == RustType::Str => {
+ return Ok(format!("&{}", v))
+ }
+ (&RustType::Chars, &RustType::Ref(ref t)) if **t == RustType::Str => {
+ return Ok(format!("&{}", v))
+ }
+ (&RustType::Ref(ref t1), &RustType::Ref(ref t2)) if t1.is_string() && t2.is_str() => {
+ return Ok(format!("&{}", v))
+ }
+ (&RustType::Ref(ref t1), &RustType::String)
+ if match **t1 {
+ RustType::Str => true,
+ _ => false,
+ } =>
+ {
+ return Ok(format!("{}.to_owned()", v))
+ }
+ (&RustType::Ref(ref t1), &RustType::Chars)
+ if match **t1 {
+ RustType::Str => true,
+ _ => false,
+ // TODO: from_static
+ } =>
+ {
+ return Ok(format!(
+ "<{}::Chars as ::std::convert::From<_>>::from({}.to_owned())",
+ protobuf_crate_path(customize),
+ v
+ ))
+ }
+ (&RustType::Ref(ref t1), &RustType::Vec(ref t2))
+ if match (&**t1, &**t2) {
+ (&RustType::Slice(ref x), ref y) => **x == **y,
+ _ => false,
+ } =>
+ {
+ return Ok(format!("{}.to_vec()", v))
+ }
+ (&RustType::Ref(ref t1), &RustType::Bytes) if t1.is_slice_u8() => {
+ return Ok(format!(
+ "<::bytes::Bytes as ::std::convert::From<_>>::from({}.to_vec())",
+ v
+ ))
+ }
+ (&RustType::Vec(ref x), &RustType::Ref(ref t))
+ if match **t {
+ RustType::Slice(ref y) => x == y,
+ _ => false,
+ } =>
+ {
+ return Ok(format!("&{}", v))
+ }
+ (&RustType::Bytes, &RustType::Ref(ref t))
+ if match **t {
+ RustType::Slice(ref y) => **y == RustType::u8(),
+ _ => false,
+ } =>
+ {
+ return Ok(format!("&{}", v))
+ }
+ (&RustType::Ref(ref t1), &RustType::Ref(ref t2))
+ if match (&**t1, &**t2) {
+ (&RustType::Vec(ref x), &RustType::Slice(ref y)) => x == y,
+ _ => false,
+ } =>
+ {
+ return Ok(format!("&{}", v))
+ }
+ (&RustType::Enum(..), &RustType::Int(true, 32)) => {
+ return Ok(format!(
+ "{}::ProtobufEnum::value(&{})",
+ protobuf_crate_path(customize),
+ v
+ ))
+ }
+ (&RustType::Ref(ref t), &RustType::Int(true, 32)) if t.is_enum() => {
+ return Ok(format!(
+ "{}::ProtobufEnum::value({})",
+ protobuf_crate_path(customize),
+ v
+ ))
+ }
+ _ => (),
+ };
+
+ if let &RustType::Ref(ref s) = self {
+ if let Ok(conv) = s.try_into_target(target, v, customize) {
+ return Ok(conv);
+ }
+ }
+
+ Err(())
+ }
+
+ /// Type to view data of this type
+ pub fn ref_type(&self) -> RustType {
+ RustType::Ref(Box::new(match self {
+ &RustType::String | &RustType::Chars => RustType::Str,
+ &RustType::Vec(ref p) | &RustType::RepeatedField(ref p) => RustType::Slice(p.clone()),
+ &RustType::Bytes => RustType::Slice(Box::new(RustType::u8())),
+ &RustType::Message(ref p) => RustType::Message(p.clone()),
+ x => panic!("no ref type for {:?}", x),
+ }))
+ }
+
+ pub fn elem_type(&self) -> RustType {
+ match self {
+ &RustType::Option(ref ty) => (**ty).clone(),
+ x => panic!("cannot get elem type of {:?}", x),
+ }
+ }
+
+ // type of `v` in `for v in xxx`
+ pub fn iter_elem_type(&self) -> RustType {
+ match self {
+ &RustType::Vec(ref ty)
+ | &RustType::Option(ref ty)
+ | &RustType::RepeatedField(ref ty)
+ | &RustType::SingularField(ref ty)
+ | &RustType::SingularPtrField(ref ty) => RustType::Ref(ty.clone()),
+ x => panic!("cannot iterate {:?}", x),
+ }
+ }
+
+ pub fn value(self, value: String) -> RustValueTyped {
+ RustValueTyped {
+ value: value,
+ rust_type: self,
+ }
+ }
+}
+
+/// Representation of an expression in code generator: text and type
+pub(crate) struct RustValueTyped {
+ pub value: String,
+ pub rust_type: RustType,
+}
+
+impl RustValueTyped {
+ pub fn into_type(&self, target: RustType, customize: &Customize) -> RustValueTyped {
+ let target_value = self.rust_type.into_target(&target, &self.value, customize);
+ RustValueTyped {
+ value: target_value,
+ rust_type: target,
+ }
+ }
+
+ pub fn boxed(self, customize: &Customize) -> RustValueTyped {
+ self.into_type(RustType::Uniq(Box::new(self.rust_type.clone())), customize)
+ }
+}
+
+// protobuf type name for protobuf base type
+pub fn protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str {
+ match field_type {
+ FieldDescriptorProto_Type::TYPE_DOUBLE => "double",
+ FieldDescriptorProto_Type::TYPE_FLOAT => "float",
+ FieldDescriptorProto_Type::TYPE_INT32 => "int32",
+ FieldDescriptorProto_Type::TYPE_INT64 => "int64",
+ FieldDescriptorProto_Type::TYPE_UINT32 => "uint32",
+ FieldDescriptorProto_Type::TYPE_UINT64 => "uint64",
+ FieldDescriptorProto_Type::TYPE_SINT32 => "sint32",
+ FieldDescriptorProto_Type::TYPE_SINT64 => "sint64",
+ FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32",
+ FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64",
+ FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32",
+ FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64",
+ FieldDescriptorProto_Type::TYPE_BOOL => "bool",
+ FieldDescriptorProto_Type::TYPE_STRING => "string",
+ FieldDescriptorProto_Type::TYPE_BYTES => "bytes",
+ FieldDescriptorProto_Type::TYPE_ENUM => "enum",
+ FieldDescriptorProto_Type::TYPE_MESSAGE => "message",
+ FieldDescriptorProto_Type::TYPE_GROUP => "group",
+ }
+}
+
+// rust type for protobuf base type
+pub(crate) fn rust_name(field_type: FieldDescriptorProto_Type) -> RustType {
+ match field_type {
+ FieldDescriptorProto_Type::TYPE_DOUBLE => RustType::Float(64),
+ FieldDescriptorProto_Type::TYPE_FLOAT => RustType::Float(32),
+ FieldDescriptorProto_Type::TYPE_INT32 => RustType::Int(true, 32),
+ FieldDescriptorProto_Type::TYPE_INT64 => RustType::Int(true, 64),
+ FieldDescriptorProto_Type::TYPE_UINT32 => RustType::Int(false, 32),
+ FieldDescriptorProto_Type::TYPE_UINT64 => RustType::Int(false, 64),
+ FieldDescriptorProto_Type::TYPE_SINT32 => RustType::Int(true, 32),
+ FieldDescriptorProto_Type::TYPE_SINT64 => RustType::Int(true, 64),
+ FieldDescriptorProto_Type::TYPE_FIXED32 => RustType::Int(false, 32),
+ FieldDescriptorProto_Type::TYPE_FIXED64 => RustType::Int(false, 64),
+ FieldDescriptorProto_Type::TYPE_SFIXED32 => RustType::Int(true, 32),
+ FieldDescriptorProto_Type::TYPE_SFIXED64 => RustType::Int(true, 64),
+ FieldDescriptorProto_Type::TYPE_BOOL => RustType::Bool,
+ FieldDescriptorProto_Type::TYPE_STRING => RustType::String,
+ FieldDescriptorProto_Type::TYPE_BYTES => RustType::Vec(Box::new(RustType::Int(false, 8))),
+ FieldDescriptorProto_Type::TYPE_ENUM
+ | FieldDescriptorProto_Type::TYPE_GROUP
+ | FieldDescriptorProto_Type::TYPE_MESSAGE => {
+ panic!("there is no rust name for {:?}", field_type)
+ }
+ }
+}
+
+fn file_last_component(file: &str) -> &str {
+ let bs = file.rfind('\\').map(|i| i + 1).unwrap_or(0);
+ let fs = file.rfind('/').map(|i| i + 1).unwrap_or(0);
+ &file[cmp::max(fs, bs)..]
+}
+
+#[cfg(test)]
+#[test]
+fn test_file_last_component() {
+ assert_eq!("ab.proto", file_last_component("ab.proto"));
+ assert_eq!("ab.proto", file_last_component("xx/ab.proto"));
+ assert_eq!("ab.proto", file_last_component("xx\\ab.proto"));
+ assert_eq!("ab.proto", file_last_component("yy\\xx\\ab.proto"));
+}
+
+fn is_descriptor_proto(file: &FileDescriptorProto) -> bool {
+ file.get_package() == "google.protobuf"
+ && file_last_component(file.get_name()) == "descriptor.proto"
+}
+
+pub(crate) fn type_name_to_rust_relative(
+ type_name: &ProtobufAbsolutePath,
+ file: &FileDescriptorProto,
+ subm: bool,
+ root_scope: &RootScope,
+ customize: &Customize,
+) -> String {
+ let message_or_enum = root_scope.find_message_or_enum(type_name);
+ if message_or_enum.get_scope().get_file_descriptor().get_name() == file.get_name() {
+ // field type is a message or enum declared in the same file
+ if subm {
+ format!("super::{}", message_or_enum.rust_name())
+ } else {
+ format!("{}", message_or_enum.rust_name())
+ }
+ } else if let Some(name) = is_well_known_type_full(&type_name.path) {
+ // Well-known types are included in rust-protobuf library
+ // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
+ format!(
+ "{}::well_known_types::{}",
+ protobuf_crate_path(customize),
+ name
+ )
+ } else if is_descriptor_proto(message_or_enum.get_file_descriptor()) {
+ // Messages defined in descriptor.proto
+ format!(
+ "{}::descriptor::{}",
+ protobuf_crate_path(customize),
+ message_or_enum.name_to_package()
+ )
+ } else {
+ if subm {
+ format!("super::super::{}", message_or_enum.rust_fq_name())
+ } else {
+ format!("super::{}", message_or_enum.rust_fq_name())
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum PrimitiveTypeVariant {
+ Default,
+ Carllerche,
+}
+
+pub enum _CarllercheBytesType {
+ Bytes,
+ Chars,
+}
+
+// ProtobufType trait name
+pub enum ProtobufTypeGen {
+ Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant),
+ Message(String),
+ Enum(String),
+}
+
+impl ProtobufTypeGen {
+ pub fn rust_type(&self, customize: &Customize) -> String {
+ match self {
+ &ProtobufTypeGen::Primitive(t, PrimitiveTypeVariant::Default) => format!(
+ "{}::types::ProtobufType{}",
+ protobuf_crate_path(customize),
+ capitalize(protobuf_name(t))
+ ),
+ &ProtobufTypeGen::Primitive(
+ FieldDescriptorProto_Type::TYPE_BYTES,
+ PrimitiveTypeVariant::Carllerche,
+ ) => format!(
+ "{}::types::ProtobufTypeCarllercheBytes",
+ protobuf_crate_path(customize)
+ ),
+ &ProtobufTypeGen::Primitive(
+ FieldDescriptorProto_Type::TYPE_STRING,
+ PrimitiveTypeVariant::Carllerche,
+ ) => format!(
+ "{}::types::ProtobufTypeCarllercheChars",
+ protobuf_crate_path(customize)
+ ),
+ &ProtobufTypeGen::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(),
+ &ProtobufTypeGen::Message(ref name) => format!(
+ "{}::types::ProtobufTypeMessage<{}>",
+ protobuf_crate_path(customize),
+ name
+ ),
+ &ProtobufTypeGen::Enum(ref name) => format!(
+ "{}::types::ProtobufTypeEnum<{}>",
+ protobuf_crate_path(customize),
+ name
+ ),
+ }
+ }
+}
diff --git a/2.27.1/src/scope.rs b/2.27.1/src/scope.rs
new file mode 100644
index 0000000..5f92d08
--- /dev/null
+++ b/2.27.1/src/scope.rs
@@ -0,0 +1,555 @@
+use protobuf::descriptor::DescriptorProto;
+use protobuf::descriptor::EnumDescriptorProto;
+use protobuf::descriptor::EnumValueDescriptorProto;
+use protobuf::descriptor::FieldDescriptorProto;
+use protobuf::descriptor::FileDescriptorProto;
+use protobuf::descriptor::OneofDescriptorProto;
+
+use crate::field::rust_field_name_for_protobuf_field_name;
+use crate::file::proto_path_to_rust_mod;
+use crate::protobuf_name::ProtobufAbsolutePath;
+use crate::protobuf_name::ProtobufIdent;
+use crate::protobuf_name::ProtobufRelativePath;
+use crate::rust;
+use crate::rust_name::RustIdent;
+use crate::rust_name::RustIdentWithPath;
+use crate::syntax::Syntax;
+
+pub(crate) struct RootScope<'a> {
+ pub file_descriptors: &'a [FileDescriptorProto],
+}
+
+impl<'a> RootScope<'a> {
+ fn packages(&'a self) -> Vec<FileScope<'a>> {
+ self.file_descriptors
+ .iter()
+ .map(|fd| FileScope {
+ file_descriptor: fd,
+ })
+ .collect()
+ }
+
+ // find enum by fully qualified name
+ pub fn _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a> {
+ match self.find_message_or_enum(fqn) {
+ MessageOrEnumWithScope::Enum(e) => e,
+ _ => panic!("not an enum: {}", fqn),
+ }
+ }
+
+ // find message by fully qualified name
+ pub fn find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a> {
+ match self.find_message_or_enum(fqn) {
+ MessageOrEnumWithScope::Message(m) => m,
+ _ => panic!("not a message: {}", fqn),
+ }
+ }
+
+ // find message or enum by fully qualified name
+ pub fn find_message_or_enum(
+ &'a self,
+ fqn: &ProtobufAbsolutePath,
+ ) -> MessageOrEnumWithScope<'a> {
+ assert!(!fqn.is_empty());
+ self.packages()
+ .into_iter()
+ .flat_map(|p| p.find_message_or_enum_abs(fqn))
+ .next()
+ .expect(&format!("enum not found by name: {}", fqn))
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct FileScope<'a> {
+ pub file_descriptor: &'a FileDescriptorProto,
+}
+
+impl<'a> FileScope<'a> {
+ fn get_package(&self) -> ProtobufAbsolutePath {
+ ProtobufRelativePath::from(self.file_descriptor.get_package()).into_absolute()
+ }
+
+ pub fn syntax(&self) -> Syntax {
+ Syntax::parse(self.file_descriptor.get_syntax())
+ }
+
+ pub fn to_scope(&self) -> Scope<'a> {
+ Scope {
+ file_scope: self.clone(),
+ path: Vec::new(),
+ }
+ }
+
+ fn find_message_or_enum(
+ &self,
+ name: &ProtobufRelativePath,
+ ) -> Option<MessageOrEnumWithScope<'a>> {
+ self.find_messages_and_enums()
+ .into_iter()
+ .filter(|e| e.protobuf_name_to_package() == *name)
+ .next()
+ }
+
+ fn find_message_or_enum_abs(
+ &self,
+ name: &ProtobufAbsolutePath,
+ ) -> Option<MessageOrEnumWithScope<'a>> {
+ match name.remove_prefix(&self.get_package()) {
+ Some(ref rem) => self.find_message_or_enum(rem),
+ None => None,
+ }
+ }
+
+ // find all enums in given file descriptor
+ pub fn _find_enums(&self) -> Vec<EnumWithScope<'a>> {
+ let mut r = Vec::new();
+
+ self.to_scope().walk_scopes(|scope| {
+ r.extend(scope.get_enums());
+ });
+
+ r
+ }
+
+ // find all messages in given file descriptor
+ pub fn _find_messages(&self) -> Vec<MessageWithScope<'a>> {
+ let mut r = Vec::new();
+
+ self.to_scope().walk_scopes(|scope| {
+ r.extend(scope.get_messages());
+ });
+
+ r
+ }
+
+ // find all messages and enums in given file descriptor
+ pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
+ let mut r = Vec::new();
+
+ self.to_scope().walk_scopes(|scope| {
+ r.extend(scope.get_messages_and_enums());
+ });
+
+ r
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct Scope<'a> {
+ pub file_scope: FileScope<'a>,
+ pub path: Vec<&'a DescriptorProto>,
+}
+
+impl<'a> Scope<'a> {
+ pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
+ self.file_scope.file_descriptor
+ }
+
+ // get message descriptors in this scope
+ fn get_message_descriptors(&self) -> &'a [DescriptorProto] {
+ if self.path.is_empty() {
+ &self.file_scope.file_descriptor.get_message_type()
+ } else {
+ &self.path.last().unwrap().get_nested_type()
+ }
+ }
+
+ // get enum descriptors in this scope
+ fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] {
+ if self.path.is_empty() {
+ &self.file_scope.file_descriptor.get_enum_type()
+ } else {
+ &self.path.last().unwrap().get_enum_type()
+ }
+ }
+
+ // get messages with attached scopes in this scope
+ pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> {
+ self.get_message_descriptors()
+ .iter()
+ .map(|m| MessageWithScope {
+ scope: self.clone(),
+ message: m,
+ })
+ .collect()
+ }
+
+ // get enums with attached scopes in this scope
+ pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> {
+ self.get_enum_descriptors()
+ .iter()
+ .map(|e| EnumWithScope {
+ scope: self.clone(),
+ en: e,
+ })
+ .collect()
+ }
+
+ // get messages and enums with attached scopes in this scope
+ pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
+ self.get_messages()
+ .into_iter()
+ .map(|m| MessageOrEnumWithScope::Message(m))
+ .chain(
+ self.get_enums()
+ .into_iter()
+ .map(|m| MessageOrEnumWithScope::Enum(m)),
+ )
+ .collect()
+ }
+
+ // nested scopes, i. e. scopes of nested messages
+ fn nested_scopes(&self) -> Vec<Scope<'a>> {
+ self.get_message_descriptors()
+ .iter()
+ .map(|m| {
+ let mut nested = self.clone();
+ nested.path.push(m);
+ nested
+ })
+ .collect()
+ }
+
+ fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
+ (*callback)(self);
+
+ for nested in self.nested_scopes() {
+ nested.walk_scopes_impl(callback);
+ }
+ }
+
+ // apply callback for this scope and all nested scopes
+ fn walk_scopes<F>(&self, mut callback: F)
+ where
+ F: FnMut(&Scope<'a>),
+ {
+ self.walk_scopes_impl(&mut callback);
+ }
+
+ pub fn prefix(&self) -> String {
+ if self.path.is_empty() {
+ "".to_string()
+ } else {
+ let v: Vec<&'a str> = self.path.iter().map(|m| m.get_name()).collect();
+ let mut r = v.join(".");
+ r.push_str(".");
+ r
+ }
+ }
+
+ pub fn protobuf_path_to_file(&self) -> ProtobufRelativePath {
+ ProtobufRelativePath::from_components(
+ self.path.iter().map(|m| ProtobufIdent::from(m.get_name())),
+ )
+ }
+
+ pub fn protobuf_absolute_path(&self) -> ProtobufAbsolutePath {
+ let mut r = self.file_scope.get_package();
+ r.push_relative(&self.protobuf_path_to_file());
+ r
+ }
+
+ // rust type name prefix for this scope
+ pub fn rust_prefix(&self) -> String {
+ self.prefix().replace(".", "_")
+ }
+}
+
+pub(crate) trait WithScope<'a> {
+ fn get_scope(&self) -> &Scope<'a>;
+
+ fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
+ self.get_scope().get_file_descriptor()
+ }
+
+ // message or enum name
+ fn get_name(&self) -> ProtobufIdent;
+
+ fn escape_prefix(&self) -> &'static str;
+
+ fn name_to_package(&self) -> String {
+ let mut r = self.get_scope().prefix();
+ r.push_str(self.get_name().get());
+ r
+ }
+
+ fn protobuf_name_to_package(&self) -> ProtobufRelativePath {
+ let r = self.get_scope().protobuf_path_to_file();
+ r.append_ident(&ProtobufIdent::from(self.get_name()))
+ }
+
+ /// Return absolute name starting with dot
+ fn name_absolute(&self) -> ProtobufAbsolutePath {
+ let mut path = self.get_scope().protobuf_absolute_path();
+ path.push_simple(self.get_name());
+ path
+ }
+
+ // rust type name of this descriptor
+ fn rust_name(&self) -> RustIdent {
+ let mut r = self.get_scope().rust_prefix();
+ // Only escape if prefix is not empty
+ if r.is_empty() && rust::is_rust_keyword(self.get_name().get()) {
+ r.push_str(self.escape_prefix());
+ }
+ r.push_str(self.get_name().get());
+ RustIdent::from(r)
+ }
+
+ // fully-qualified name of this type
+ fn rust_fq_name(&self) -> String {
+ format!(
+ "{}::{}",
+ proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name()),
+ self.rust_name()
+ )
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct MessageWithScope<'a> {
+ pub scope: Scope<'a>,
+ pub message: &'a DescriptorProto,
+}
+
+impl<'a> WithScope<'a> for MessageWithScope<'a> {
+ fn get_scope(&self) -> &Scope<'a> {
+ &self.scope
+ }
+
+ fn escape_prefix(&self) -> &'static str {
+ "message_"
+ }
+
+ fn get_name(&self) -> ProtobufIdent {
+ ProtobufIdent::from(self.message.get_name())
+ }
+}
+
+impl<'a> MessageWithScope<'a> {
+ pub fn into_scope(mut self) -> Scope<'a> {
+ self.scope.path.push(self.message);
+ self.scope
+ }
+
+ pub fn to_scope(&self) -> Scope<'a> {
+ self.clone().into_scope()
+ }
+
+ pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
+ self.message
+ .get_field()
+ .iter()
+ .map(|f| FieldWithContext {
+ field: f,
+ message: self.clone(),
+ })
+ .collect()
+ }
+
+ pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
+ self.message
+ .get_oneof_decl()
+ .iter()
+ .enumerate()
+ .map(|(index, oneof)| OneofWithContext {
+ message: self.clone(),
+ oneof: oneof,
+ index: index as u32,
+ })
+ .collect()
+ }
+
+ pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> {
+ self.oneofs().swap_remove(index as usize)
+ }
+
+ /// Pair of (key, value) if this message is map entry
+ pub fn map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)> {
+ if self.message.get_options().get_map_entry() {
+ let key = self
+ .fields()
+ .into_iter()
+ .find(|f| f.field.get_number() == 1)
+ .unwrap();
+ let value = self
+ .fields()
+ .into_iter()
+ .find(|f| f.field.get_number() == 2)
+ .unwrap();
+ Some((key, value))
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct EnumWithScope<'a> {
+ pub scope: Scope<'a>,
+ pub en: &'a EnumDescriptorProto,
+}
+
+impl<'a> EnumWithScope<'a> {
+ pub fn values(&self) -> Vec<EnumValueWithContext<'a>> {
+ self.en
+ .get_value()
+ .iter()
+ .map(|v| EnumValueWithContext {
+ _en: self.clone(),
+ proto: v,
+ })
+ .collect()
+ }
+
+ // find enum value by protobuf name
+ pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> {
+ self.values()
+ .into_iter()
+ .find(|v| v.proto.get_name() == name)
+ .unwrap()
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct EnumValueWithContext<'a> {
+ _en: EnumWithScope<'a>,
+ pub proto: &'a EnumValueDescriptorProto,
+}
+
+impl<'a> EnumValueWithContext<'a> {
+ pub fn rust_name(&self) -> RustIdent {
+ let mut r = String::new();
+ if rust::is_rust_keyword(self.proto.get_name()) {
+ r.push_str("value_");
+ }
+ r.push_str(self.proto.get_name());
+ RustIdent::new(&r)
+ }
+}
+
+impl<'a> WithScope<'a> for EnumWithScope<'a> {
+ fn get_scope(&self) -> &Scope<'a> {
+ &self.scope
+ }
+
+ fn escape_prefix(&self) -> &'static str {
+ "enum_"
+ }
+
+ fn get_name(&self) -> ProtobufIdent {
+ ProtobufIdent::from(self.en.get_name())
+ }
+}
+
+pub(crate) enum MessageOrEnumWithScope<'a> {
+ Message(MessageWithScope<'a>),
+ Enum(EnumWithScope<'a>),
+}
+
+impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
+ fn get_scope(&self) -> &Scope<'a> {
+ match self {
+ &MessageOrEnumWithScope::Message(ref m) => m.get_scope(),
+ &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(),
+ }
+ }
+
+ fn escape_prefix(&self) -> &'static str {
+ match self {
+ &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(),
+ &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(),
+ }
+ }
+
+ fn get_name(&self) -> ProtobufIdent {
+ match self {
+ &MessageOrEnumWithScope::Message(ref m) => m.get_name(),
+ &MessageOrEnumWithScope::Enum(ref e) => e.get_name(),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct FieldWithContext<'a> {
+ pub field: &'a FieldDescriptorProto,
+ pub message: MessageWithScope<'a>,
+}
+
+impl<'a> FieldWithContext<'a> {
+ pub fn is_oneof(&self) -> bool {
+ self.field.has_oneof_index()
+ }
+
+ pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
+ if self.is_oneof() {
+ Some(
+ self.message
+ .oneof_by_index(self.field.get_oneof_index() as u32),
+ )
+ } else {
+ None
+ }
+ }
+
+ pub fn number(&self) -> u32 {
+ self.field.get_number() as u32
+ }
+
+ /// Shortcut
+ pub fn name(&self) -> &str {
+ self.field.get_name()
+ }
+
+ pub fn rust_name(&self) -> RustIdent {
+ rust_field_name_for_protobuf_field_name(self.name())
+ }
+
+ // From field to file root
+ pub fn _containing_messages(&self) -> Vec<&'a DescriptorProto> {
+ let mut r = Vec::new();
+ r.push(self.message.message);
+ r.extend(self.message.scope.path.iter().rev());
+ r
+ }
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofVariantWithContext<'a> {
+ pub oneof: &'a OneofWithContext<'a>,
+ pub field: &'a FieldDescriptorProto,
+}
+
+#[derive(Clone)]
+pub(crate) struct OneofWithContext<'a> {
+ pub oneof: &'a OneofDescriptorProto,
+ pub index: u32,
+ pub message: MessageWithScope<'a>,
+}
+
+impl<'a> OneofWithContext<'a> {
+ pub fn field_name(&'a self) -> RustIdent {
+ return rust_field_name_for_protobuf_field_name(self.oneof.get_name());
+ }
+
+ // rust type name of enum
+ pub fn rust_name(&self) -> RustIdentWithPath {
+ RustIdentWithPath::from(format!(
+ "{}_oneof_{}",
+ self.message.rust_name(),
+ self.oneof.get_name()
+ ))
+ }
+
+ pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
+ self.message
+ .fields()
+ .iter()
+ .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32)
+ .map(|f| OneofVariantWithContext {
+ oneof: self,
+ field: &f.field,
+ })
+ .collect()
+ }
+}
diff --git a/2.27.1/src/serde.rs b/2.27.1/src/serde.rs
new file mode 100644
index 0000000..f799611
--- /dev/null
+++ b/2.27.1/src/serde.rs
@@ -0,0 +1,9 @@
+use code_writer::CodeWriter;
+use Customize;
+
+/// Write serde attr according to specified codegen option.
+pub fn write_serde_attr(w: &mut CodeWriter, customize: &Customize, attr: &str) {
+ if customize.serde_derive.unwrap_or(false) {
+ w.write_line(&format!("#[cfg_attr(feature = \"with-serde\", {})]", attr));
+ }
+}
diff --git a/2.27.1/src/strx.rs b/2.27.1/src/strx.rs
new file mode 100644
index 0000000..d1b26fa
--- /dev/null
+++ b/2.27.1/src/strx.rs
@@ -0,0 +1,57 @@
+pub fn remove_to<'s, P>(s: &'s str, pattern: P) -> &'s str
+where
+ P: Fn(char) -> bool,
+{
+ match s.rfind(pattern) {
+ Some(pos) => &s[(pos + 1)..],
+ None => s,
+ }
+}
+
+pub fn remove_suffix<'s>(s: &'s str, suffix: &str) -> &'s str {
+ if !s.ends_with(suffix) {
+ s
+ } else {
+ &s[..(s.len() - suffix.len())]
+ }
+}
+
+pub fn capitalize(s: &str) -> String {
+ if s.is_empty() {
+ return String::new();
+ }
+ let mut char_indices = s.char_indices();
+ char_indices.next().unwrap();
+ match char_indices.next() {
+ None => s.to_uppercase(),
+ Some((i, _)) => s[..i].to_uppercase() + &s[i..],
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use super::capitalize;
+ use super::remove_suffix;
+ use super::remove_to;
+
+ #[test]
+ fn test_remove_to() {
+ assert_eq!("aaa", remove_to("aaa", |c| c == '.'));
+ assert_eq!("bbb", remove_to("aaa.bbb", |c| c == '.'));
+ assert_eq!("ccc", remove_to("aaa.bbb.ccc", |c| c == '.'));
+ }
+
+ #[test]
+ fn test_remove_suffix() {
+ assert_eq!("bbb", remove_suffix("bbbaaa", "aaa"));
+ assert_eq!("aaa", remove_suffix("aaa", "bbb"));
+ }
+
+ #[test]
+ fn test_capitalize() {
+ assert_eq!("", capitalize(""));
+ assert_eq!("F", capitalize("f"));
+ assert_eq!("Foo", capitalize("foo"));
+ }
+}
diff --git a/2.27.1/src/syntax.rs b/2.27.1/src/syntax.rs
new file mode 100644
index 0000000..d075063
--- /dev/null
+++ b/2.27.1/src/syntax.rs
@@ -0,0 +1,15 @@
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Syntax {
+ PROTO2,
+ PROTO3,
+}
+
+impl Syntax {
+ pub fn parse(s: &str) -> Self {
+ match s {
+ "" | "proto2" => Syntax::PROTO2,
+ "proto3" => Syntax::PROTO3,
+ _ => panic!("unsupported syntax value: {:?}", s),
+ }
+ }
+}
diff --git a/2.27.1/src/well_known_types.rs b/2.27.1/src/well_known_types.rs
new file mode 100644
index 0000000..6264947
--- /dev/null
+++ b/2.27.1/src/well_known_types.rs
@@ -0,0 +1,63 @@
+static NAMES: &'static [&'static str] = &[
+ "Any",
+ "Api",
+ "BoolValue",
+ "BytesValue",
+ "DoubleValue",
+ "Duration",
+ "Empty",
+ "Enum",
+ "EnumValue",
+ "Field",
+ // TODO: dotted names
+ "Field.Cardinality",
+ "Field.Kind",
+ "FieldMask",
+ "FloatValue",
+ "Int32Value",
+ "Int64Value",
+ "ListValue",
+ "Method",
+ "Mixin",
+ "NullValue",
+ "Option",
+ "SourceContext",
+ "StringValue",
+ "Struct",
+ "Syntax",
+ "Timestamp",
+ "Type",
+ "UInt32Value",
+ "UInt64Value",
+ "Value",
+];
+
+fn is_well_known_type(name: &str) -> bool {
+ NAMES.iter().any(|&n| n == name)
+}
+
+pub fn is_well_known_type_full(name: &str) -> Option<&str> {
+ if let Some(dot) = name.rfind('.') {
+ if &name[..dot] == ".google.protobuf" && is_well_known_type(&name[dot + 1..]) {
+ Some(&name[dot + 1..])
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_is_well_known_type_full() {
+ assert_eq!(
+ Some("BoolValue"),
+ is_well_known_type_full(".google.protobuf.BoolValue")
+ );
+ assert_eq!(None, is_well_known_type_full(".google.protobuf.Fgfg"));
+ }
+}