protobuf-codegen-2.27.1/.cargo_vcs_info.json0000644000000001560000000000100143710ustar { "git": { "sha1": "ec31ce829473039ac598ca6fdcb245cbd6fa82ba" }, "path_in_vcs": "protobuf-codegen" }protobuf-codegen-2.27.1/Cargo.lock0000644000000006020000000000100123400ustar # 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", ] protobuf-codegen-2.27.1/Cargo.toml0000644000000022430000000000100123660ustar # 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 "] 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" protobuf-codegen-2.27.1/Cargo.toml.orig000064400000000000000000000013560072674642500161030ustar 00000000000000[package] name = "protobuf-codegen" version = "2.27.1" authors = ["Stepan Koltsov "] 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 protobuf-codegen-2.27.1/LICENSE.txt000064400000000000000000000020410072674642500150270ustar 00000000000000Copyright (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.protobuf-codegen-2.27.1/README.md000064400000000000000000000044010072674642500144650ustar 00000000000000 # 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. protobuf-codegen-2.27.1/src/bin/protobuf-bin-gen-rust-do-not-use.rs000064400000000000000000000015330072674642500232560ustar 00000000000000extern 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 = 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 = std::env::args().collect(); if args.len() != 2 { panic!("must have exactly one argument"); } let ref pb_bin = args[1]; write_file(&pb_bin); } protobuf-codegen-2.27.1/src/bin/protoc-gen-rust.rs000064400000000000000000000001340072674642500201620ustar 00000000000000extern crate protobuf_codegen; fn main() { protobuf_codegen::protoc_gen_rust_main(); } protobuf-codegen-2.27.1/src/code_writer.rs000064400000000000000000000254550072674642500166650ustar 00000000000000// 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>(&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(&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(&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(&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(&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(&mut self, prefix: &str, cb: F) where F: Fn(&mut CodeWriter), { self.block(&format!("{} {{", prefix), "}", cb); } pub fn stmt_block, F>(&mut self, prefix: S, cb: F) where F: Fn(&mut CodeWriter), { self.block(&format!("{} {{", prefix.as_ref()), "};", cb); } pub fn unsafe_expr(&mut self, cb: F) where F: Fn(&mut CodeWriter), { self.expr_block("unsafe", cb); } pub fn impl_self_block, 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, S2: AsRef, 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(&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, 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, 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(&mut self, name: &str, cb: F) where F: Fn(&mut CodeWriter), { self.expr_block(&format!("pub enum {}", name), cb); } pub fn pub_trait(&mut self, name: &str, cb: F) where F: Fn(&mut CodeWriter), { self.expr_block(&format!("pub trait {}", name), cb); } pub fn pub_trait_extend(&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 = 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 = 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(&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(&mut self, sig: &str, cb: F) where F: Fn(&mut CodeWriter), { self.fn_block(true, sig, cb); } pub fn def_fn(&mut self, sig: &str, cb: F) where F: Fn(&mut CodeWriter), { self.fn_block(false, sig, cb); } pub fn def_mod(&mut self, name: &str, cb: F) where F: Fn(&mut CodeWriter), { self.expr_block(&format!("mod {}", name), cb) } pub fn pub_mod(&mut self, name: &str, cb: F) where F: Fn(&mut CodeWriter), { self.expr_block(&format!("pub mod {}", name), cb) } pub fn while_block, 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, 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, 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(&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(&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, S2: AsRef, 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, 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, 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, F>(&mut self, cond: S, cb: F) where F: Fn(&mut CodeWriter), { self.block(&format!("{} => {{", cond.as_ref()), "},", cb); } pub fn case_expr, S2: AsRef>(&mut self, cond: S1, body: S2) { self.write_line(&format!("{} => {},", cond.as_ref(), body.as_ref())); } } protobuf-codegen-2.27.1/src/customize.rs000064400000000000000000000215550072674642500163760ustar 00000000000000use 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, /// When true all fields are public, and accessors are not generated pub expose_fields: Option, /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated pub generate_accessors: Option, /// Use `bytes::Bytes` for `bytes` fields pub carllerche_bytes_for_bytes: Option, /// Use `bytes::Bytes` for `string` fields pub carllerche_bytes_for_string: Option, /// Implement serde_derive for messages pub serde_derive: Option, /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`. pub serde_derive_cfg: Option, /// When `serde_derive` is set, use attribute rename_all pub serde_rename_all: Option, /// Enable lite runtime pub lite_runtime: Option, /// 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, /// Used internally to generate protos bundled in protobuf crate /// like `descriptor.proto` pub inside_protobuf: Option, // 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 = Result; 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 { fn parse_bool(v: &str) -> CustomizeParseParameterResult { 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: (), } } protobuf-codegen-2.27.1/src/enums.rs000064400000000000000000000312270072674642500155000ustar 00000000000000use 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 { 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 { 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(&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() )) }); }); } } protobuf-codegen-2.27.1/src/extensions.rs000064400000000000000000000066100072674642500165460ustar 00000000000000use 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); } }); } protobuf-codegen-2.27.1/src/field/mod.rs000064400000000000000000002247620072674642500162230ustar 00000000000000use 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 { 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>>, 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) { 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, 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, 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 { 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 { 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(¶m_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(¶m_type, var, &self.customize) ) } else { format!( "{}::rt::value_size({}, {}, {}::wire_format::{:?})", protobuf_crate_path(&self.customize), self.proto_field.number(), var_type.into_target(¶m_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(¶m_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(&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(&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(&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(&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(¶m_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) } } protobuf-codegen-2.27.1/src/file.rs000064400000000000000000000040120072674642500152600ustar 00000000000000use 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::(); 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"), ) } } protobuf-codegen-2.27.1/src/file_and_mod.rs000064400000000000000000000003020072674642500167370ustar 00000000000000use rust_name::RustRelativePath; use Customize; #[allow(dead_code)] pub(crate) struct FileAndMod { pub file: String, pub relative_mod: RustRelativePath, pub customize: Customize, } protobuf-codegen-2.27.1/src/file_descriptor.rs000064400000000000000000000002100072674642500175120ustar 00000000000000use crate::scope::Scope; pub(crate) fn file_descriptor_proto_expr(_scope: &Scope) -> String { format!("file_descriptor_proto()") } protobuf-codegen-2.27.1/src/float.rs000064400000000000000000000033440072674642500154550ustar 00000000000000use std::f64; #[derive(Debug)] pub enum ProtobufFloatParseError { EmptyString, CannotParseFloat, } pub type ProtobufFloatParseResult = Result; 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 { 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)); } } protobuf-codegen-2.27.1/src/inside.rs000064400000000000000000000004470072674642500156240ustar 00000000000000use 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", } } protobuf-codegen-2.27.1/src/lib.rs000064400000000000000000000260130072674642500151140ustar 00000000000000//! # 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", env!("CARGO_PKG_VERSION")); 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 { let root_scope = RootScope { file_descriptors: file_descriptors, }; let mut results: Vec = 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)) } protobuf-codegen-2.27.1/src/message.rs000064400000000000000000000547040072674642500160020ustar 00000000000000use 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>, 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> { 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(&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) -> ::std::boxed::Box", |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!("{}: ", &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); } } } protobuf-codegen-2.27.1/src/oneof.rs000064400000000000000000000134030072674642500154530ustar 00000000000000//! 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> { 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) )); } }); } } protobuf-codegen-2.27.1/src/protobuf_name.rs000064400000000000000000000246540072674642500172170ustar 00000000000000use 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 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: I) -> ProtobufRelativePath { let v: Vec = 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 { 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 { 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 for ProtobufRelativePath { fn from(s: String) -> ProtobufRelativePath { ProtobufRelativePath::new(s) } } impl From for ProtobufRelativePath { fn from(s: ProtobufIdent) -> ProtobufRelativePath { ProtobufRelativePath::from(s.get()) } } impl From> for ProtobufRelativePath { fn from(s: Vec) -> 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 { 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 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())) ); } } protobuf-codegen-2.27.1/src/rust.rs000064400000000000000000000015450072674642500153460ustar 00000000000000#[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) } protobuf-codegen-2.27.1/src/rust_name.rs000064400000000000000000000141200072674642500163370ustar 00000000000000use 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 for RustIdent { fn from(s: String) -> Self { RustIdent::new(&s) } } impl Into for RustIdent { fn into(self) -> String { self.0 } } #[derive(Default, Eq, PartialEq, Debug, Clone)] pub(crate) struct RustRelativePath { path: Vec, } #[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: I) -> RustRelativePath { RustRelativePath { path: i.into_iter().collect(), } } pub fn is_empty(&self) -> bool { self.path.is_empty() } pub fn first(&self) -> Option { self.path.iter().cloned().next() } pub fn remove_first(&mut self) -> Option { 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 { assert!(!self.absolute); self.path.first() } pub fn remove_first(&mut self) -> Option { 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 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> From 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) } } protobuf-codegen-2.27.1/src/rust_types_values.rs000064400000000000000000000515350072674642500201550ustar 00000000000000use 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), HashMap(Box, Box), String, // [T], not &[T] Slice(Box), // str, not &str Str, Option(Box), SingularField(Box), SingularPtrField(Box), RepeatedField(Box), // Box Uniq(Box), // &T Ref(Box), // 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!(""), 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 { 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 ), } } } protobuf-codegen-2.27.1/src/scope.rs000064400000000000000000000357330072674642500154700ustar 00000000000000use 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> { 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> { 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> { 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> { 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> { 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> { 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> { 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> { 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> { 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> { self.get_message_descriptors() .iter() .map(|m| { let mut nested = self.clone(); nested.path.push(m); nested }) .collect() } fn walk_scopes_impl)>(&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(&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> { self.message .get_field() .iter() .map(|f| FieldWithContext { field: f, message: self.clone(), }) .collect() } pub fn oneofs(&self) -> Vec> { 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> { 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> { 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> { 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() } } protobuf-codegen-2.27.1/src/serde.rs000064400000000000000000000005060072674642500154470ustar 00000000000000use 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)); } } protobuf-codegen-2.27.1/src/strx.rs000064400000000000000000000024760072674642500153550ustar 00000000000000pub 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")); } } protobuf-codegen-2.27.1/src/syntax.rs000064400000000000000000000005030072674642500156700ustar 00000000000000#[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), } } } protobuf-codegen-2.27.1/src/well_known_types.rs000064400000000000000000000023440072674642500177520ustar 00000000000000static 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")); } }