Skip to content

Commit

Permalink
Add well-known types, fold prost-codegen into prost-build
Browse files Browse the repository at this point in the history
* Folds the prost-codegen crate into prost-build.
* Removes the protoc-gen-prost tool. It wasn't being used or tested, and
  prost-build has obviated the need for it. Can always be added back in
  the future if a need arises.
* Adds the prost-types crate, which centralizes definitions for Protobuf
  well-known types.

This commit would have been better split into two, but it snowballed out
of control and I'm not patient enough to go back and separate the
concerns.

fixes danburkert/prost#3
fixes danburkert/prost#8.

This is a breaking change.
  • Loading branch information
danburkert committed Jul 27, 2017
1 parent cea0bf3 commit 0529321
Show file tree
Hide file tree
Showing 29 changed files with 2,507 additions and 1,241 deletions.
2 changes: 1 addition & 1 deletion .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test_script:
- SET RUST_BACKTRACE=1
# The 'protobuf' crate can't be compiled on Windows, which means none of the
# integration tests or benchmarks can be run.
- cargo test --target %TARGET% -p prost -p prost-build -p prost-codegen
- cargo test --target %TARGET% -p prost -p prost-build -p prost-types

cache:
- C:\Users\appveyor\.cargo\registry
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ members = [
"benchmarks",
"conformance",
"prost-build",
"prost-codegen",
"prost-derive",
"prost-types",
"protobuf",
"tests",
]
Expand Down
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,14 @@ First, add `prost` and its public dependencies to your `Cargo.toml` (see
[dependencies]
prost = <prost-version>
prost-derive = <prost-version>
# Only necessary if using Protobuf well-known types:
prost-types = <prost-version>
bytes = <bytes-version>
```

The recommended way to add `.proto` compilation to a Cargo project is to use the
`prost-build` library to handle compilation at build-time. See the
[`prost-build` documentation](prost-build) for more details and examples.

Alternatively, the `prost-codegen` crate provides a `protoc` plugin which can be
used to manually compile `.proto` files into Rust source files. The resulting
Rust files can be added to a project source tree like any other. See the
[`prost-codegen` documentation](prost-codegen) for more details and examples.
`prost-build` library. See the [`prost-build` documentation](prost-build) for
more details and examples.

## Generated Code

Expand Down
4 changes: 4 additions & 0 deletions benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ version = "0.1.0"
authors = ["Dan Burkert <dan@danburkert.com>"]
publish = false

[lib]
doctest = false
test = false

[dependencies]
bytes = "0.4"
prost = { path = ".." }
Expand Down
9 changes: 5 additions & 4 deletions benchmarks/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ extern crate protobuf;

fn main() {
let benchmarks = protobuf::include().join("benchmarks");
prost_build::compile_protos(&[benchmarks.join("benchmark_messages_proto2.proto")],
&[benchmarks.clone()]).unwrap();
prost_build::compile_protos(&[benchmarks.join("benchmark_messages_proto3.proto")],
&[benchmarks]).unwrap();
let prost_build = prost_build::Config::new();
prost_build.compile_protos(&[benchmarks.join("benchmark_messages_proto2.proto")],
&[benchmarks.clone()]).unwrap();
prost_build.compile_protos(&[benchmarks.join("benchmark_messages_proto3.proto")],
&[benchmarks]).unwrap();

println!("cargo:rustc-env=GOOGLE_MESSAGE1={}",
protobuf::share().join("google_message1.dat").display());
Expand Down
7 changes: 6 additions & 1 deletion prost-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ description = "A Protocol Buffers implementation for the Rust Language."

[dependencies]
bytes = "0.4"
prost-codegen = { path = "../prost-codegen" }
env_logger = "0.4"
itertools = "0.6"
log = "0.3"
multimap = "0.3"
petgraph = "0.4"
prost = { path = ".." }
prost-types = { path = "../prost-types" }
tempdir = "0.3"

[build-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions prost-build/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

# `prost-build`

`prost-build` is a small library which makes it easy to add code generation of
`.proto` files to a Cargo project.
`prost-build` makes it easy to generate Rust code from `.proto` files as part of
a Cargo build.

See the Crate [documentation](https://crates.io/crates/prost-build) for examples
of how to integrate `prost` into a Cargo project.
2 changes: 1 addition & 1 deletion prost-codegen/src/ast.rs → prost-build/src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use google::protobuf::source_code_info::Location;
use prost_types::source_code_info::Location;

#[derive(Debug, Default)]
pub struct Comments {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ use std::collections::{HashMap, HashSet};

use itertools::{Either, Itertools};
use multimap::MultiMap;

use ast::{
Comments,
Method,
Service,
};
use google::protobuf::{
use prost_types::{
DescriptorProto,
EnumDescriptorProto,
EnumValueDescriptorProto,
Expand All @@ -19,8 +13,14 @@ use google::protobuf::{
ServiceDescriptorProto,
SourceCodeInfo,
};
use google::protobuf::field_descriptor_proto::{Label, Type};
use google::protobuf::source_code_info::Location;
use prost_types::field_descriptor_proto::{Label, Type};
use prost_types::source_code_info::Location;

use ast::{
Comments,
Method,
Service,
};
use ident::{
camel_to_snake,
match_field,
Expand Down Expand Up @@ -122,6 +122,10 @@ impl <'a> CodeGenerator<'a> {
// that comments can be retrieved.
let message_name = message.name.as_ref().expect("message name");
let fq_message_name = format!(".{}.{}", self.package, message_name);

// Skip Protobuf well-known types.
if self.well_known_type(&fq_message_name).is_some() { return; }

let (nested_types, map_types): (Vec<(DescriptorProto, usize)>, HashMap<String, (FieldDescriptorProto, FieldDescriptorProto)>) =
message.nested_type.into_iter().enumerate().partition_map(|(idx, nested_type)| {
if nested_type.options.as_ref().and_then(|options| options.map_entry).unwrap_or(false) {
Expand Down Expand Up @@ -254,9 +258,9 @@ impl <'a> CodeGenerator<'a> {
self.buf.push_str("pub ");
self.buf.push_str(&camel_to_snake(field.name()));
self.buf.push_str(": ");
if repeated { self.buf.push_str("Vec<"); }
else if optional { self.buf.push_str("Option<"); }
if boxed { self.buf.push_str("Box<"); }
if repeated { self.buf.push_str("::std::vec::Vec<"); }
else if optional { self.buf.push_str("::std::option::Option<"); }
if boxed { self.buf.push_str("::std::boxed::Box<"); }
self.buf.push_str(&ty);
if boxed { self.buf.push_str(">"); }
if repeated || optional { self.buf.push_str(">"); }
Expand Down Expand Up @@ -312,7 +316,7 @@ impl <'a> CodeGenerator<'a> {
name,
fields.iter().map(|&(ref field, _)| field.number()).join(", ")));
self.push_indent();
self.buf.push_str(&format!("pub {}: Option<{}>,\n", camel_to_snake(oneof.name()), name));
self.buf.push_str(&format!("pub {}: ::std::option::Option<{}>,\n", camel_to_snake(oneof.name()), name));
}

fn append_oneof(&mut self,
Expand Down Expand Up @@ -527,7 +531,13 @@ impl <'a> CodeGenerator<'a> {
Type::TypeBool => Cow::Borrowed("bool"),
Type::TypeString => Cow::Borrowed("String"),
Type::TypeBytes => Cow::Borrowed("Vec<u8>"),
Type::TypeGroup | Type::TypeMessage => Cow::Owned(self.resolve_ident(field.type_name())),
Type::TypeGroup | Type::TypeMessage => {
if let Some(ty) = self.well_known_type(field.type_name()) {
Cow::Borrowed(ty)
} else {
Cow::Owned(self.resolve_ident(field.type_name()))
}
},
Type::TypeEnum => Cow::Borrowed("i32"),
}
}
Expand Down Expand Up @@ -595,8 +605,65 @@ impl <'a> CodeGenerator<'a> {
_ => self.syntax == Syntax::Proto2,
}
}

/// Returns the prost_types name for a well-known Protobuf type, or `None` if the provided
/// message type is not a well-known type, or prost_types has been disabled.
fn well_known_type(&self, fq_msg_type: &str) -> Option<&'static str> {
if !self.config.prost_types { return None; }
Some(match fq_msg_type {
".google.protobuf.BoolValue" => "bool",
".google.protobuf.UInt32Value" => "u32",
".google.protobuf.UInt64Value" => "u64",
".google.protobuf.Int32Value" => "i32",
".google.protobuf.Int64Value" => "i64",
".google.protobuf.FloatValue" => "f32",
".google.protobuf.DoubleValue" => "f64",
".google.protobuf.StringValue" => "::std::string::String",
".google.protobuf.BytesValue" => "::std::vec::Vec<u8>",
".google.protobuf.Empty" => "()",
".google.protobuf.Duration" => "::prost::types::Duration",
".google.protobuf.Timestamp" => "::prost::types::Timestamp",

".google.protobuf.Any" => "::prost_types::Any",
".google.protobuf.Api" => "::prost_types::Api",
".google.protobuf.DescriptorProto" => "::prost_types::DescriptorProto",
".google.protobuf.Enum" => "::prost_types::Enum",
".google.protobuf.EnumDescriptorProto" => "::prost_types::EnumDescriptorProt",
".google.protobuf.EnumOptions" => "::prost_types::EnumOptions",
".google.protobuf.EnumValue" => "::prost_types::EnumValue",
".google.protobuf.EnumValueDescriptorProto" => "::prost_types::EnumValueDescriptorProto",
".google.protobuf.EnumValueOptions" => "::prost_types::EnumValueOptions",
".google.protobuf.Field" => "::prost_types::Field",
".google.protobuf.FieldDescriptorProto" => "::prost_types::FieldDescriptorProto",
".google.protobuf.FieldMask" => "::prost_types::FieldMask",
".google.protobuf.FieldOptions" => "::prost_types::FieldOptions",
".google.protobuf.FileDescriptorProto" => "::prost_types::FileDescriptorProto",
".google.protobuf.FileDescriptorSet" => "::prost_types::FileDescriptorSet",
".google.protobuf.FileOptions" => "::prost_types::FileOptions",
".google.protobuf.GeneratedCodeInfo" => "::prost_types::GeneratedCodeInfo",
".google.protobuf.ListValue" => "::prost_types::ListValue",
".google.protobuf.MessageOptions" => "::prost_types::MessageOptions",
".google.protobuf.Method" => "::prost_types::Method",
".google.protobuf.MethodDescriptorProto" => "::prost_types::MethodDescriptorProto",
".google.protobuf.MethodOption" => "::prost_types::MethodOption",
".google.protobuf.Mixin" => "::prost_types::Mixin",
".google.protobuf.OneofDescriptorProto" => "::prost_types::OneofDescriptorProto",
".google.protobuf.OneofOptions" => "::prost_types::OneofOptions",
".google.protobuf.Option" => "::prost_types::Option",
".google.protobuf.ServiceDescriptorProto" => "::prost_types::ServiceDescriptorProto",
".google.protobuf.ServiceOptions" => "::prost_types::ServiceOptions",
".google.protobuf.SourceCodeInfo" => "::prost_types::SourceCodeInfo",
".google.protobuf.SourceContext" => "::prost_types::SourceContext",
".google.protobuf.Struct" => "::prost_types::Struct",
".google.protobuf.Type" => "::prost_types::Type",
".google.protobuf.UninterpretedOption" => "::prost_types::UninterpretedOption",
".google.protobuf.Value" => "::prost_types::Value",
_ => return None,
})
}
}

/// Returns `true` if the repeated field type can be packed.
fn can_pack(field: &FieldDescriptorProto) -> bool {
match field.type_().expect("unknown field type") {
Type::TypeFloat | Type::TypeDouble | Type::TypeInt32 | Type::TypeInt64 |
Expand Down
File renamed without changes.

0 comments on commit 0529321

Please sign in to comment.