Compare commits

..

1 Commits

Author SHA1 Message Date
Jeffrey Griffin
907f7d6e71 add std feature for no-std compatibility 2019-09-21 17:51:06 -07:00
55 changed files with 845 additions and 1285 deletions

View File

@ -1,6 +1,13 @@
language: rust
dist: xenial
# Even though this build script doesn't use sudo, we enable it in order to get
# more memory. Previously on the container infrastructure the OOM killer would
# come in and kill either the GCC processes compiling protobuf, or rustc. See
# https://github.com/travis-ci/travis-ci/issues/7427 for the source of this
# workaround.
sudo: required
cache: cargo
os:
@ -8,7 +15,7 @@ os:
- osx
rust:
- 1.39.0
- 1.32.0
- nightly
script:
@ -17,13 +24,3 @@ script:
- if [[ $TRAVIS_RUST_VERSION = nightly* ]]; then
cargo bench --verbose --no-run;
fi
addons:
homebrew:
packages:
- cmake
- ninja
apt:
packages:
- cmake
- ninja-build

View File

@ -1,6 +1,7 @@
[package]
name = "prost"
version = "0.6.1"
# NB: When modifying, also modify html_root_url in lib.rs
version = "0.5.0"
authors = ["Dan Burkert <dan@danburkert.com>"]
license = "Apache-2.0"
repository = "https://github.com/danburkert/prost"
@ -31,10 +32,6 @@ exclude = [
"fuzz",
]
[lib]
# https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options
bench = false
[features]
default = ["prost-derive", "std"]
no-recursion-limit = []
@ -42,18 +39,19 @@ std = []
[dependencies]
bytes = { version = "0.5", default-features = false }
prost-derive = { version = "0.6.1", path = "prost-derive", optional = true }
prost-derive = { version = "0.5.0", path = "prost-derive", optional = true }
[dev-dependencies]
criterion = "0.3"
env_logger = { version = "0.7", default-features = false }
criterion = "0.2"
env_logger = { version = "0.6", default-features = false }
failure = { version = "0.1", default-features = false }
log = "0.4"
quickcheck = "0.9"
rand = "0.7"
[profile.bench]
debug = true
protobuf = { version = "0", path = "protobuf" }
quickcheck = "0.8"
[[bench]]
name = "varint"
[[bench]]
name = "benchmark"
harness = false

View File

@ -2,7 +2,6 @@
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/24rpba3x2vqe8lje/branch/master?svg=true)](https://ci.appveyor.com/project/danburkert/prost/branch/master)
[![Documentation](https://docs.rs/prost/badge.svg)](https://docs.rs/prost/)
[![Crate](https://img.shields.io/crates/v/prost.svg)](https://crates.io/crates/prost)
[![Dependency Status](https://deps.rs/repo/github/danburkert/prost/status.svg)](https://deps.rs/repo/github/danburkert/prost)
# *PROST!*
@ -19,20 +18,22 @@ Compared to other Protocol Buffers implementations, `prost`
and deserialized by adding attributes.
* Uses the [`bytes::{Buf, BufMut}`](https://github.com/carllerche/bytes)
abstractions for serialization instead of `std::io::{Read, Write}`.
* Respects the Protobuf `package` specifier when organizing generated code
* Respects the Protobuf `package` declaration when organizing generated code
into Rust modules.
* Preserves unknown enum values during deserialization.
* Does not include support for runtime reflection or message descriptors.
## Using `prost` in a Cargo Project
First, add `prost` and its public dependencies to your `Cargo.toml`:
First, add `prost` and its public dependencies to your `Cargo.toml` (see
[crates.io](https://crates.io/crates/prost) for the current versions):
```
[dependencies]
prost = "0.6"
prost = <prost-version>
bytes = <bytes-version>
# Only necessary if using Protobuf well-known types:
prost-types = "0.6"
prost-types = <prost-version>
```
The recommended way to add `.proto` compilation to a Cargo project is to use the
@ -47,11 +48,9 @@ possible.
### Packages
All `.proto` files used with `prost` must contain a
[`package` specifier][package]. `prost` will translate the Protobuf package into
a Rust module. For example, given the `package` specifier:
[package]: https://developers.google.com/protocol-buffers/docs/proto#packages
Currently, all `.proto` files used with `prost` must contain a `package`
declaration. `prost` will translate the Protobuf package into a Rust module.
For example, given the `package` declaration:
```proto
package foo.bar;

108
benches/benchmark.rs Normal file
View File

@ -0,0 +1,108 @@
use std::fs::File;
use std::io::Read;
use std::result;
use criterion::{Benchmark, Criterion, Throughput};
use failure::bail;
use prost::encoding::DecodeContext;
use prost::Message;
use protobuf::benchmarks::{google_message3, google_message4, proto2, proto3, BenchmarkDataset};
type Result = result::Result<(), failure::Error>;
fn benchmark_dataset<M>(criterion: &mut Criterion, dataset: BenchmarkDataset) -> Result
where
M: prost::Message + Default + 'static,
{
let payload_len = dataset.payload.iter().map(Vec::len).sum::<usize>();
let messages = dataset
.payload
.iter()
.map(|buf| M::decode(buf))
.collect::<result::Result<Vec<_>, _>>()?;
let encoded_len = messages
.iter()
.map(|message| message.encoded_len())
.sum::<usize>();
let mut buf = Vec::with_capacity(encoded_len);
let encode = Benchmark::new("encode", move |b| {
b.iter(|| {
buf.clear();
for message in &messages {
message.encode(&mut buf).unwrap();
}
criterion::black_box(&buf);
})
})
.throughput(Throughput::Bytes(encoded_len as u32));
let payload = dataset.payload.clone();
let decode = Benchmark::new("decode", move |b| {
b.iter(|| {
for buf in &payload {
criterion::black_box(M::decode(buf).unwrap());
}
})
})
.throughput(Throughput::Bytes(payload_len as u32));
let payload = dataset.payload.clone();
let merge = Benchmark::new("merge", move |b| {
let mut message = M::default();
b.iter(|| {
for buf in &payload {
message.clear();
message.merge(buf).unwrap();
criterion::black_box(&message);
}
})
})
.throughput(Throughput::Bytes(payload_len as u32));
criterion
.bench(&dataset.name, encode)
.bench(&dataset.name, decode)
.bench(&dataset.name, merge);
Ok(())
}
fn main() -> Result {
let mut criterion = Criterion::default()
.configure_from_args()
// TODO(bheisler/criterion.rs#295): switch to a time-based limit.
.sample_size(10);
for dataset in protobuf::benchmarks::datasets() {
let dataset = {
let mut f = File::open(dataset)?;
let mut buf = Vec::new();
f.read_to_end(&mut buf)?;
protobuf::benchmarks::BenchmarkDataset::decode(buf)?
};
match dataset.message_name.as_str() {
"benchmarks.proto2.GoogleMessage1" => {
benchmark_dataset::<proto2::GoogleMessage1>(&mut criterion, dataset)?
}
"benchmarks.proto3.GoogleMessage1" => {
benchmark_dataset::<proto3::GoogleMessage1>(&mut criterion, dataset)?
}
"benchmarks.proto2.GoogleMessage2" => {
benchmark_dataset::<proto2::GoogleMessage2>(&mut criterion, dataset)?
}
"benchmarks.google_message3.GoogleMessage3" => {
benchmark_dataset::<google_message3::GoogleMessage3>(&mut criterion, dataset)?
}
"benchmarks.google_message4.GoogleMessage4" => {
benchmark_dataset::<google_message4::GoogleMessage4>(&mut criterion, dataset)?
}
_ => bail!("unknown dataset message type: {}", dataset.message_name),
}
}
criterion.final_summary();
Ok(())
}

View File

@ -1,95 +1,108 @@
use std::mem;
#![feature(test)]
use bytes::Buf;
use criterion::{Benchmark, Criterion, Throughput};
extern crate test;
use bytes::IntoBuf;
use prost::encoding::{decode_varint, encode_varint, encoded_len_varint};
use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng};
fn benchmark_varint(criterion: &mut Criterion, name: &str, mut values: Vec<u64>) {
// Shuffle the values in a stable order.
values.shuffle(&mut StdRng::seed_from_u64(0));
let encoded_len = values
.iter()
.cloned()
.map(encoded_len_varint)
.sum::<usize>() as u64;
let decoded_len = (values.len() * mem::size_of::<u64>()) as u64;
let encode_values = values.clone();
let encode = Benchmark::new("encode", move |b| {
let mut buf = Vec::<u8>::with_capacity(encode_values.len() * 10);
b.iter(|| {
buf.clear();
for &value in &encode_values {
encode_varint(value, &mut buf);
}
criterion::black_box(&buf);
})
})
.throughput(Throughput::Bytes(encoded_len));
let mut decode_values = values.clone();
let decode = Benchmark::new("decode", move |b| {
let mut buf = Vec::with_capacity(decode_values.len() * 10);
for &value in &decode_values {
encode_varint(value, &mut buf);
macro_rules! varint_bench {
($encode_name:ident, $decode_name:ident, $encoded_len_name: ident, $encode:expr) => {
#[bench]
fn $encode_name(b: &mut test::Bencher) {
let mut buf = Vec::with_capacity(100 * 10);
b.iter(|| {
buf.clear();
$encode(&mut buf);
test::black_box(&buf[..]);
});
b.bytes = 100 * 8;
}
#[bench]
fn $decode_name(b: &mut test::Bencher) {
let mut buf = Vec::with_capacity(100 * 10);
$encode(&mut buf);
let buf = &buf[..];
b.iter(|| {
decode_values.clear();
let mut buf = &mut buf.as_slice();
while buf.has_remaining() {
let value = decode_varint(&mut buf).unwrap();
decode_values.push(value);
let mut values = [0u64; 100];
b.iter(|| {
let mut buf = buf.into_buf();
for i in 0..100 {
values[i] = decode_varint(&mut buf).unwrap();
}
test::black_box(&values[..]);
});
b.bytes = 100 * 8;
}
#[bench]
fn $encoded_len_name(b: &mut test::Bencher) {
let mut values = [0u64; 100];
{
let mut buf = Vec::with_capacity(100 * 10);
$encode(&mut buf);
let mut buf = (&buf[..]).into_buf();
for i in 0..100 {
values[i] = decode_varint(&mut buf).unwrap();
}
}
criterion::black_box(&decode_values);
})
})
.throughput(Throughput::Bytes(decoded_len));
let encoded_len_values = values.clone();
let encoded_len = Benchmark::new("encoded_len", move |b| {
b.iter(|| {
let mut sum = 0;
for &value in &encoded_len_values {
sum += encoded_len_varint(value);
}
criterion::black_box(sum);
})
})
.throughput(Throughput::Bytes(decoded_len));
let name = format!("varint/{}", name);
criterion
.bench(&name, encode)
.bench(&name, decode)
.bench(&name, encoded_len);
b.iter(|| {
let mut sum = 0;
for &value in values.iter() {
sum += encoded_len_varint(value);
}
test::black_box(sum);
});
b.bytes = 100 * 8;
}
};
}
fn main() {
let mut criterion = Criterion::default().configure_from_args();
// Benchmark encoding and decoding 100 varints of mixed width (average 5.5 bytes).
varint_bench!(
encode_varint_mixed,
decode_varint_mixed,
encoded_len_varint_mixed,
|ref mut buf| for width in 0..10 {
let exponent = width * 7;
for offset in 0..10 {
encode_varint(offset + (1 << exponent), buf);
}
}
);
// Benchmark encoding and decoding 100 small (1 byte) varints.
benchmark_varint(&mut criterion, "small", (0..100).collect());
// Benchmark encoding and decoding 100 small (1 byte) varints.
varint_bench!(
encode_varint_small,
decode_varint_small,
encoded_len_varint_small,
|ref mut buf| for value in 0..100 {
encode_varint(value, buf);
}
);
// Benchmark encoding and decoding 100 medium (5 byte) varints.
benchmark_varint(&mut criterion, "medium", (1 << 28..).take(100).collect());
// Benchmark encoding and decoding 100 medium (5 byte) varints.
varint_bench!(
encode_varint_medium,
decode_varint_medium,
encoded_len_varint_medium,
|ref mut buf| {
let start = 1 << 28;
for value in start..start + 100 {
encode_varint(value, buf);
}
}
);
// Benchmark encoding and decoding 100 large (10 byte) varints.
benchmark_varint(&mut criterion, "large", (1 << 63..).take(100).collect());
// Benchmark encoding and decoding 100 varints of mixed width (average 5.5 bytes).
benchmark_varint(
&mut criterion,
"mixed",
(0..10)
.flat_map(move |width| {
let exponent = width * 7;
(0..10).map(move |offset| offset + (1 << exponent))
})
.collect(),
);
criterion.final_summary();
}
// Benchmark encoding and decoding 100 large (10 byte) varints.
varint_bench!(
encode_varint_large,
decode_varint_large,
encoded_len_varint_large,
|ref mut buf| {
let start = 1 << 63;
for value in start..start + 100 {
encode_varint(value, buf);
}
}
);

View File

@ -6,9 +6,9 @@ publish = false
edition = "2018"
[dependencies]
bytes = "0.5"
env_logger = { version = "0.7", default-features = false }
log = "0.4"
bytes = "0.4.7"
env_logger = { version = "0.6", default-features = false }
log = "0.3"
prost = { path = ".." }
protobuf = { path = "../protobuf" }
tests = { path = "../tests" }

View File

@ -1,6 +1,6 @@
use std::io::{self, Read, Write};
use bytes::{Buf, BufMut};
use bytes::{ByteOrder, LittleEndian};
use prost::Message;
use protobuf::conformance::{
@ -10,24 +10,24 @@ use protobuf::test_messages::proto2::TestAllTypesProto2;
use protobuf::test_messages::proto3::TestAllTypesProto3;
use tests::{roundtrip, RoundtripResult};
fn main() -> io::Result<()> {
fn main() {
env_logger::init();
let mut bytes = Vec::new();
loop {
bytes.resize(4, 0);
if io::stdin().read_exact(&mut *bytes).is_err() {
if io::stdin().read_exact(&mut bytes[..]).is_err() {
// No more test cases.
return Ok(());
break;
}
let len = bytes.as_slice().get_u32_le() as usize;
let len = LittleEndian::read_u32(&bytes[..]) as usize;
bytes.resize(len, 0);
io::stdin().read_exact(&mut *bytes)?;
io::stdin().read_exact(&mut bytes[..]).unwrap();
let result = match ConformanceRequest::decode(&*bytes) {
let result = match ConformanceRequest::decode(&bytes) {
Ok(request) => handle_request(request),
Err(error) => conformance_response::Result::ParseError(format!("{:?}", error)),
};
@ -36,14 +36,15 @@ fn main() -> io::Result<()> {
response.result = Some(result);
let len = response.encoded_len();
bytes.clear();
bytes.put_u32_le(len as u32);
response.encode(&mut bytes)?;
bytes.resize(4, 0);
LittleEndian::write_u32(&mut bytes[..4], len as u32);
response.encode(&mut bytes).unwrap();
assert_eq!(len + 4, bytes.len());
let mut stdout = io::stdout();
stdout.lock().write_all(&bytes)?;
stdout.flush()?;
stdout.lock().write_all(&bytes).unwrap();
stdout.flush().unwrap();
}
}

View File

@ -1,47 +0,0 @@
#!/bin/bash
# Script which automates modifying source version fields, and creating a release
# commit and tag. The commit and tag are not automatically pushed, nor are the
# crates published (see publish-release.sh).
set -ex
if [ "$#" -ne 1 ]
then
echo "Usage: $0 <version>"
exit 1
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
VERSION="$1"
MINOR="$( echo ${VERSION} | cut -d\. -f1-2 )"
VERSION_MATCHER="([a-z0-9\\.-]+)"
PROST_CRATE_MATCHER="(prost|prost-[a-z]+)"
# Update the README.md.
sed -i -E "s/${PROST_CRATE_MATCHER} = \"${VERSION_MATCHER}\"/\1 = \"${MINOR}\"/" "$DIR/README.md"
# Update html_root_url attributes.
sed -i -E "s~html_root_url = \"https://docs\.rs/${PROST_CRATE_MATCHER}/$VERSION_MATCHER\"~html_root_url = \"https://docs.rs/\1/${VERSION}\"~" \
"$DIR/src/lib.rs" \
"$DIR/prost-derive/src/lib.rs" \
"$DIR/prost-build/src/lib.rs" \
"$DIR/prost-types/src/lib.rs"
# Update Cargo.toml version fields.
sed -i -E "s/^version = \"${VERSION_MATCHER}\"$/version = \"${VERSION}\"/" \
"$DIR/Cargo.toml" \
"$DIR/prost-derive/Cargo.toml" \
"$DIR/prost-build/Cargo.toml" \
"$DIR/prost-types/Cargo.toml"
# Update Cargo.toml dependency versions.
sed -i -E "s/^${PROST_CRATE_MATCHER} = \{ version = \"${VERSION_MATCHER}\"/\1 = { version = \"${VERSION}\"/" \
"$DIR/Cargo.toml" \
"$DIR/prost-derive/Cargo.toml" \
"$DIR/prost-build/Cargo.toml" \
"$DIR/prost-types/Cargo.toml"
git commit -a -m "release ${VERSION}"
git tag -a "v${VERSION}" -m "release ${VERSION}"

View File

@ -1,6 +1,7 @@
[package]
name = "prost-build"
version = "0.6.1"
# NB: When modifying, also modify html_root_url in lib.rs
version = "0.5.0"
authors = ["Dan Burkert <dan@danburkert.com>"]
license = "Apache-2.0"
repository = "https://github.com/danburkert/prost"
@ -10,18 +11,18 @@ description = "A Protocol Buffers implementation for the Rust Language."
edition = "2018"
[dependencies]
bytes = "0.5"
bytes = "0.4.7"
heck = "0.3"
itertools = "0.8"
log = "0.4"
multimap = { version = "0.8", default-features = false }
petgraph = { version = "0.5", default-features = false }
prost = { version = "0.6.1", path = ".." }
prost-types = { version = "0.6.1", path = "../prost-types" }
multimap = { version = "0.4", default-features = false }
petgraph = { version = "0.4", default-features = false }
prost = { version = "0.5.0", path = ".." }
prost-types = { version = "0.5.0", path = "../prost-types" }
tempfile = "3"
[build-dependencies]
which = { version = "3", default-features = false }
which = "2"
[dev-dependencies]
env_logger = { version = "0.7", default-features = false }
env_logger = { version = "0.6", default-features = false }

View File

@ -1,9 +0,0 @@
syntax = "proto3";
import "types.proto";
package helloworld;
service Farewell {
rpc Goodbye (Message) returns (Response) {}
}

View File

@ -1,9 +0,0 @@
syntax = "proto3";
import "types.proto";
package helloworld;
service Greeting {
rpc Hello (Message) returns (Response) {}
}

View File

@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/prost-build/0.6.1")]
#![doc(html_root_url = "https://docs.rs/prost-build/0.5.0")]
//! `prost-build` compiles `.proto` files into Rust.
//!
@ -114,7 +114,7 @@ use std::collections::HashMap;
use std::default;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::io::{Error, ErrorKind, Read, Result, Write};
use std::path::{Path, PathBuf};
use std::process::Command;
@ -163,16 +163,6 @@ pub trait ServiceGenerator {
///
/// The default implementation is empty and does nothing.
fn finalize(&mut self, _buf: &mut String) {}
/// Finalizes the generation process for an entire protobuf package.
///
/// This differs from [`finalize`](#method.finalize) by where (and how often) it is called
/// during the service generator life cycle. This method is called once per protobuf package,
/// making it ideal for grouping services within a single package spread across multiple
/// `.proto` files.
///
/// The default implementation is empty and does nothing.
fn finalize_package(&mut self, _package: &str, _buf: &mut String) {}
}
/// Configuration options for Protobuf code generation.
@ -546,27 +536,18 @@ impl Config {
));
}
let buf = fs::read(descriptor_set)?;
let descriptor_set = FileDescriptorSet::decode(&*buf)?;
let mut buf = Vec::new();
fs::File::open(descriptor_set)?.read_to_end(&mut buf)?;
let descriptor_set = FileDescriptorSet::decode(&buf[..])?;
let modules = self.generate(descriptor_set.file)?;
for (module, content) in modules {
let mut filename = module.join(".");
filename.push_str(".rs");
let output_path = target.join(&filename);
let previous_content = fs::read(&output_path);
if previous_content
.map(|previous_content| previous_content == content.as_bytes())
.unwrap_or(false)
{
trace!("unchanged: {:?}", filename);
} else {
trace!("writing: {:?}", filename);
fs::write(output_path, content)?;
}
trace!("writing: {:?}", filename);
let mut file = fs::File::create(target.join(filename))?;
file.write_all(content.as_bytes())?;
file.flush()?;
}
Ok(())
@ -574,32 +555,16 @@ impl Config {
fn generate(&mut self, files: Vec<FileDescriptorProto>) -> Result<HashMap<Module, String>> {
let mut modules = HashMap::new();
let mut packages = HashMap::new();
let message_graph = MessageGraph::new(&files)
.map_err(|error| Error::new(ErrorKind::InvalidInput, error))?;
let message_graph = MessageGraph::new(&files);
let extern_paths = ExternPaths::new(&self.extern_paths, self.prost_types)
.map_err(|error| Error::new(ErrorKind::InvalidInput, error))?;
for file in files {
let module = self.module(&file);
// Only record packages that have services
if !file.service.is_empty() {
packages.insert(module.clone(), file.package().to_string());
}
let mut buf = modules.entry(module).or_insert_with(String::new);
CodeGenerator::generate(self, &message_graph, &extern_paths, file, &mut buf);
}
if let Some(ref mut service_generator) = self.service_generator {
for (module, package) in packages {
let buf = modules.get_mut(&module).unwrap();
service_generator.finalize_package(&package, buf);
}
}
Ok(modules)
}
@ -650,7 +615,6 @@ impl default::Default for Config {
/// - Failure to locate or download `protoc`.
/// - Failure to parse the `.proto`s.
/// - Failure to locate an imported `.proto`.
/// - Failure to compile a `.proto` without a [package specifier][4].
///
/// It's expected that this function call be `unwrap`ed in a `build.rs`; there is typically no
/// reason to gracefully recover from errors during a build.
@ -667,7 +631,6 @@ impl default::Default for Config {
/// [1]: https://doc.rust-lang.org/std/macro.include.html
/// [2]: http://doc.crates.io/build-script.html#case-study-code-generation
/// [3]: https://developers.google.com/protocol-buffers/docs/proto3#importing-definitions
/// [4]: https://developers.google.com/protocol-buffers/docs/proto#packages
pub fn compile_protos<P>(protos: &[P], includes: &[P]) -> Result<()>
where
P: AsRef<Path>,
@ -689,8 +652,6 @@ pub fn protoc_include() -> &'static Path {
mod tests {
use super::*;
use env_logger;
use std::cell::RefCell;
use std::rc::Rc;
/// An example service generator that generates a trait with methods corresponding to the
/// service methods.
@ -719,66 +680,12 @@ mod tests {
}
}
/// Implements `ServiceGenerator` and provides some state for assertions.
struct MockServiceGenerator {
state: Rc<RefCell<MockState>>,
}
/// Holds state for `MockServiceGenerator`
#[derive(Default)]
struct MockState {
service_names: Vec<String>,
package_names: Vec<String>,
finalized: u32,
}
impl MockServiceGenerator {
fn new(state: Rc<RefCell<MockState>>) -> Self {
Self { state }
}
}
impl ServiceGenerator for MockServiceGenerator {
fn generate(&mut self, service: Service, _buf: &mut String) {
let mut state = self.state.borrow_mut();
state.service_names.push(service.name.clone());
}
fn finalize(&mut self, _buf: &mut String) {
let mut state = self.state.borrow_mut();
state.finalized += 1;
}
fn finalize_package(&mut self, package: &str, _buf: &mut String) {
let mut state = self.state.borrow_mut();
state.package_names.push(package.to_string());
}
}
#[test]
fn smoke_test() {
let _ = env_logger::try_init();
let _ = env_logger::init();
Config::new()
.service_generator(Box::new(ServiceTraitGenerator))
.compile_protos(&["src/smoke_test.proto"], &["src"])
.unwrap();
}
#[test]
fn finalize_package() {
let _ = env_logger::try_init();
let state = Rc::new(RefCell::new(MockState::default()));
let gen = MockServiceGenerator::new(Rc::clone(&state));
Config::new()
.service_generator(Box::new(gen))
.compile_protos(&["src/hello.proto", "src/goodbye.proto"], &["src"])
.unwrap();
let state = state.borrow();
assert_eq!(&state.service_names, &["Greeting", "Farewell"]);
assert_eq!(&state.package_names, &["helloworld"]);
assert_eq!(state.finalized, 3);
}
}

View File

@ -15,30 +15,20 @@ pub struct MessageGraph {
}
impl MessageGraph {
pub fn new(files: &[FileDescriptorProto]) -> Result<MessageGraph, String> {
pub fn new(files: &[FileDescriptorProto]) -> MessageGraph {
let mut msg_graph = MessageGraph {
index: HashMap::new(),
graph: Graph::new(),
};
for file in files {
let package = format!(
".{}",
file.package.as_ref().ok_or_else(|| {
format!(
"prost requires a package specifier in all .proto files \
(https://developers.google.com/protocol-buffers/docs/proto#packages); \
file with missing package specifier: {}",
file.name.as_ref().map_or("(unknown)", String::as_ref),
)
})?,
);
let package = format!(".{}", file.package.as_ref().expect("expected a package"));
for msg in &file.message_type {
msg_graph.add_message(&package, msg);
}
}
Ok(msg_graph)
msg_graph
}
fn get_or_insert_index(&mut self, msg_name: String) -> NodeIndex {

View File

@ -1,11 +0,0 @@
syntax = "proto3";
package helloworld;
message Message {
string say = 1;
}
message Response {
string say = 1;
}

11
prost-build/third-party/protobuf/README.md vendored Executable file
View File

@ -0,0 +1,11 @@
`LICENSE` was taken from https://github.com/google/protobuf/archive/v3.7.1.zip.
The `protoc-*` and `protoc-*.exe` binaries here were taken from:
* https://github.com/google/protobuf/releases/download/v3.7.1/protoc-3.7.1-linux-aarch_64.zip
* https://github.com/google/protobuf/releases/download/v3.7.1/protoc-3.7.1-linux-x86_32.zip
* https://github.com/google/protobuf/releases/download/v3.7.1/protoc-3.7.1-linux-x86_64.zip
* https://github.com/google/protobuf/releases/download/v3.7.1/protoc-3.7.1-osx-x86_64.zip
* https://github.com/google/protobuf/releases/download/v3.7.1/protoc-3.7.1-win32.zip
The `include` directory's contents were taken from the linux-x86_64 package.

View File

@ -45,7 +45,6 @@
// flag "--${NAME}_out" is passed to protoc.
syntax = "proto2";
package google.protobuf.compiler;
option java_package = "com.google.protobuf.compiler";
option java_outer_classname = "PluginProtos";

View File

@ -40,7 +40,6 @@
syntax = "proto2";
package google.protobuf;
option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";
option java_package = "com.google.protobuf";
option java_outer_classname = "DescriptorProtos";
@ -60,8 +59,8 @@ message FileDescriptorSet {
// Describes a complete .proto file.
message FileDescriptorProto {
optional string name = 1; // file name, relative to root of source tree
optional string package = 2; // e.g. "foo", "foo.bar", etc.
optional string name = 1; // file name, relative to root of source tree
optional string package = 2; // e.g. "foo", "foo.bar", etc.
// Names of files imported by this file.
repeated string dependency = 3;
@ -101,8 +100,8 @@ message DescriptorProto {
repeated EnumDescriptorProto enum_type = 4;
message ExtensionRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Exclusive.
optional int32 start = 1;
optional int32 end = 2;
optional ExtensionRangeOptions options = 3;
}
@ -116,8 +115,8 @@ message DescriptorProto {
// fields or extension ranges in the same message. Reserved ranges may
// not overlap.
message ReservedRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Exclusive.
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Exclusive.
}
repeated ReservedRange reserved_range = 9;
// Reserved field names, which may not be used by fields in the same message.
@ -138,42 +137,42 @@ message FieldDescriptorProto {
enum Type {
// 0 is reserved for errors.
// Order is weird for historical reasons.
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
// negative values are likely.
TYPE_INT64 = 3;
TYPE_UINT64 = 4;
TYPE_INT64 = 3;
TYPE_UINT64 = 4;
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
// negative values are likely.
TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
TYPE_STRING = 9;
TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
TYPE_STRING = 9;
// Tag-delimited aggregate.
// Group type is deprecated and not supported in proto3. However, Proto3
// implementations should still be able to parse the group wire format and
// treat group fields as unknown fields.
TYPE_GROUP = 10;
TYPE_MESSAGE = 11; // Length-delimited aggregate.
TYPE_GROUP = 10;
TYPE_MESSAGE = 11; // Length-delimited aggregate.
// New in version 2.
TYPE_BYTES = 12;
TYPE_UINT32 = 13;
TYPE_ENUM = 14;
TYPE_SFIXED32 = 15;
TYPE_SFIXED64 = 16;
TYPE_SINT32 = 17; // Uses ZigZag encoding.
TYPE_SINT64 = 18; // Uses ZigZag encoding.
}
TYPE_BYTES = 12;
TYPE_UINT32 = 13;
TYPE_ENUM = 14;
TYPE_SFIXED32 = 15;
TYPE_SFIXED64 = 16;
TYPE_SINT32 = 17; // Uses ZigZag encoding.
TYPE_SINT64 = 18; // Uses ZigZag encoding.
};
enum Label {
// 0 is reserved for errors
LABEL_OPTIONAL = 1;
LABEL_REQUIRED = 2;
LABEL_REPEATED = 3;
}
LABEL_OPTIONAL = 1;
LABEL_REQUIRED = 2;
LABEL_REPEATED = 3;
};
optional string name = 1;
optional int32 number = 3;
@ -235,8 +234,8 @@ message EnumDescriptorProto {
// is inclusive such that it can appropriately represent the entire int32
// domain.
message EnumReservedRange {
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Inclusive.
optional int32 start = 1; // Inclusive.
optional int32 end = 2; // Inclusive.
}
// Range of reserved numeric values. Reserved numeric values may not be used
@ -277,9 +276,9 @@ message MethodDescriptorProto {
optional MethodOptions options = 4;
// Identifies if client streams multiple client messages
optional bool client_streaming = 5 [default = false];
optional bool client_streaming = 5 [default=false];
// Identifies if server streams multiple server messages
optional bool server_streaming = 6 [default = false];
optional bool server_streaming = 6 [default=false];
}
@ -315,6 +314,7 @@ message MethodDescriptorProto {
// If this turns out to be popular, a web service will be set up
// to automatically assign option numbers.
message FileOptions {
// Sets the Java package where classes generated from this .proto will be
@ -337,7 +337,7 @@ message FileOptions {
// named by java_outer_classname. However, the outer class will still be
// generated to contain the file's getDescriptor() method as well as any
// top-level extensions defined in the file.
optional bool java_multiple_files = 10 [default = false];
optional bool java_multiple_files = 10 [default=false];
// This option does nothing.
optional bool java_generate_equals_and_hash = 20 [deprecated=true];
@ -348,17 +348,17 @@ message FileOptions {
// Message reflection will do the same.
// However, an extension field still accepts non-UTF-8 byte sequences.
// This option has no effect on when used with the lite runtime.
optional bool java_string_check_utf8 = 27 [default = false];
optional bool java_string_check_utf8 = 27 [default=false];
// Generated classes can be optimized for speed or code size.
enum OptimizeMode {
SPEED = 1; // Generate complete code for parsing, serialization,
// etc.
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
SPEED = 1; // Generate complete code for parsing, serialization,
// etc.
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
}
optional OptimizeMode optimize_for = 9 [default = SPEED];
optional OptimizeMode optimize_for = 9 [default=SPEED];
// Sets the Go package where structs generated from this .proto will be
// placed. If omitted, the Go package will be derived from the following:
@ -369,7 +369,6 @@ message FileOptions {
// Should generic services be generated in each language? "Generic" services
// are not specific to any particular RPC system. They are generated by the
// main code generators in each language (without additional plugins).
@ -380,20 +379,20 @@ message FileOptions {
// that generate code specific to your particular RPC system. Therefore,
// these default to false. Old code which depends on generic services should
// explicitly set them to true.
optional bool cc_generic_services = 16 [default = false];
optional bool java_generic_services = 17 [default = false];
optional bool py_generic_services = 18 [default = false];
optional bool php_generic_services = 42 [default = false];
optional bool cc_generic_services = 16 [default=false];
optional bool java_generic_services = 17 [default=false];
optional bool py_generic_services = 18 [default=false];
optional bool php_generic_services = 42 [default=false];
// Is this file deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for everything in the file, or it will be completely ignored; in the very
// least, this is a formalization for deprecating files.
optional bool deprecated = 23 [default = false];
optional bool deprecated = 23 [default=false];
// Enables the use of arenas for the proto messages in this file. This applies
// only to generated classes for C++.
optional bool cc_enable_arenas = 31 [default = false];
optional bool cc_enable_arenas = 31 [default=false];
// Sets the objective c class prefix which is prepended to all objective c
@ -418,9 +417,10 @@ message FileOptions {
// determining the namespace.
optional string php_namespace = 41;
// Use this option to change the namespace of php generated metadata classes.
// Default is empty. When this option is empty, the proto file name will be
// used for determining the namespace.
// Default is empty. When this option is empty, the proto file name will be used
// for determining the namespace.
optional string php_metadata_namespace = 44;
// Use this option to change the package of ruby generated classes. Default
@ -428,7 +428,6 @@ message FileOptions {
// determining the ruby package.
optional string ruby_package = 45;
// The parser stores options it doesn't recognize here.
// See the documentation for the "Options" section above.
repeated UninterpretedOption uninterpreted_option = 999;
@ -459,18 +458,18 @@ message MessageOptions {
//
// Because this is an option, the above two restrictions are not enforced by
// the protocol compiler.
optional bool message_set_wire_format = 1 [default = false];
optional bool message_set_wire_format = 1 [default=false];
// Disables the generation of the standard "descriptor()" accessor, which can
// conflict with a field of the same name. This is meant to make migration
// from proto1 easier; new code should avoid fields named "descriptor".
optional bool no_standard_descriptor_accessor = 2 [default = false];
optional bool no_standard_descriptor_accessor = 2 [default=false];
// Is this message deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for the message, or it will be completely ignored; in the very least,
// this is a formalization for deprecating messages.
optional bool deprecated = 3 [default = false];
optional bool deprecated = 3 [default=false];
// Whether the message is an automatically generated map entry type for the
// maps field.
@ -487,7 +486,7 @@ message MessageOptions {
//
// Implementations may choose not to generate the map_entry=true message, but
// use a native map in the target language to hold the keys and values.
// The reflection APIs in such implementations still need to work as
// The reflection APIs in such implementions still need to work as
// if the field is a repeated message field.
//
// NOTE: Do not set the option in .proto files. Always use the maps syntax
@ -498,7 +497,6 @@ message MessageOptions {
reserved 8; // javalite_serializable
reserved 9; // javanano_as_lite
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@ -578,16 +576,16 @@ message FieldOptions {
// implementation must either *always* check its required fields, or *never*
// check its required fields, regardless of whether or not the message has
// been parsed.
optional bool lazy = 5 [default = false];
optional bool lazy = 5 [default=false];
// Is this field deprecated?
// Depending on the target platform, this can emit Deprecated annotations
// for accessors, or it will be completely ignored; in the very least, this
// is a formalization for deprecating fields.
optional bool deprecated = 3 [default = false];
optional bool deprecated = 3 [default=false];
// For Google-internal migration only. Do not use.
optional bool weak = 10 [default = false];
optional bool weak = 10 [default=false];
// The parser stores options it doesn't recognize here. See above.
@ -617,7 +615,7 @@ message EnumOptions {
// Depending on the target platform, this can emit Deprecated annotations
// for the enum, or it will be completely ignored; in the very least, this
// is a formalization for deprecating enums.
optional bool deprecated = 3 [default = false];
optional bool deprecated = 3 [default=false];
reserved 5; // javanano_as_lite
@ -633,7 +631,7 @@ message EnumValueOptions {
// Depending on the target platform, this can emit Deprecated annotations
// for the enum value, or it will be completely ignored; in the very least,
// this is a formalization for deprecating enum values.
optional bool deprecated = 1 [default = false];
optional bool deprecated = 1 [default=false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@ -653,7 +651,7 @@ message ServiceOptions {
// Depending on the target platform, this can emit Deprecated annotations
// for the service, or it will be completely ignored; in the very least,
// this is a formalization for deprecating services.
optional bool deprecated = 33 [default = false];
optional bool deprecated = 33 [default=false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@ -673,18 +671,18 @@ message MethodOptions {
// Depending on the target platform, this can emit Deprecated annotations
// for the method, or it will be completely ignored; in the very least,
// this is a formalization for deprecating methods.
optional bool deprecated = 33 [default = false];
optional bool deprecated = 33 [default=false];
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
// or neither? HTTP based RPC implementation may choose GET verb for safe
// methods, and PUT verb for idempotent methods instead of the default POST.
enum IdempotencyLevel {
IDEMPOTENCY_UNKNOWN = 0;
NO_SIDE_EFFECTS = 1; // implies idempotent
IDEMPOTENT = 2; // idempotent, but may have side effects
NO_SIDE_EFFECTS = 1; // implies idempotent
IDEMPOTENT = 2; // idempotent, but may have side effects
}
optional IdempotencyLevel idempotency_level = 34
[default = IDEMPOTENCY_UNKNOWN];
optional IdempotencyLevel idempotency_level =
34 [default=IDEMPOTENCY_UNKNOWN];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@ -765,7 +763,7 @@ message SourceCodeInfo {
// beginning of the "extend" block and is shared by all extensions within
// the block.
// - Just because a location's span is a subset of some other location's span
// does not mean that it is a descendant. For example, a "group" defines
// does not mean that it is a descendent. For example, a "group" defines
// both a type and a field in a single declaration. Thus, the locations
// corresponding to the type and field and their components will overlap.
// - Code which tries to interpret locations should probably be designed to
@ -796,14 +794,14 @@ message SourceCodeInfo {
// [ 4, 3, 2, 7 ]
// this path refers to the whole field declaration (from the beginning
// of the label to the terminating semicolon).
repeated int32 path = 1 [packed = true];
repeated int32 path = 1 [packed=true];
// Always has exactly three or four elements: start line, start column,
// end line (optional, otherwise assumed same as start line), end column.
// These are packed into a single field for efficiency. Note that line
// and column numbers are zero-based -- typically you will want to add
// 1 to each before displaying to a user.
repeated int32 span = 2 [packed = true];
repeated int32 span = 2 [packed=true];
// If this SourceCodeInfo represents a complete declaration, these are any
// comments appearing before and after the declaration which appear to be
@ -868,7 +866,7 @@ message GeneratedCodeInfo {
message Annotation {
// Identifies the element in the original source .proto file. This field
// is formatted the same as SourceCodeInfo.Location.path.
repeated int32 path = 1 [packed = true];
repeated int32 path = 1 [packed=true];
// Identifies the filesystem path to the original source .proto.
optional string source_file = 2;

View File

@ -61,7 +61,7 @@ option objc_class_prefix = "GPB";
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (duration.seconds > 0 && duration.nanos < 0) {
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
@ -101,6 +101,7 @@ option objc_class_prefix = "GPB";
//
//
message Duration {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years

View File

@ -238,7 +238,7 @@ option cc_enable_arenas = true;
//
// The implementation of any API method which has a FieldMask type field in the
// request should verify the included field paths, and return an
// `INVALID_ARGUMENT` error if any path is unmappable.
// `INVALID_ARGUMENT` error if any path is duplicated or unmappable.
message FieldMask {
// The set of field mask paths.
repeated string paths = 1;

View File

@ -40,6 +40,7 @@ option java_outer_classname = "StructProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
// `Struct` represents a structured data value, consisting of fields
// which map to dynamically typed values. In some languages, `Struct`
// might be supported by a native representation. For example, in

View File

@ -113,18 +113,17 @@ option objc_class_prefix = "GPB";
// 01:30 UTC on January 15, 2017.
//
// In JavaScript, one can convert a Date object to this format using the
// standard
// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
// method. In Python, a standard `datetime.datetime` object can be converted
// to this format using
// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
// the Joda Time's [`ISODateTimeFormat.dateTime()`](
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
// ) to obtain a formatter capable of generating timestamps in this format.
//
//
message Timestamp {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.

View File

@ -64,44 +64,44 @@ message Field {
// Basic field types.
enum Kind {
// Field type unknown.
TYPE_UNKNOWN = 0;
TYPE_UNKNOWN = 0;
// Field type double.
TYPE_DOUBLE = 1;
TYPE_DOUBLE = 1;
// Field type float.
TYPE_FLOAT = 2;
TYPE_FLOAT = 2;
// Field type int64.
TYPE_INT64 = 3;
TYPE_INT64 = 3;
// Field type uint64.
TYPE_UINT64 = 4;
TYPE_UINT64 = 4;
// Field type int32.
TYPE_INT32 = 5;
TYPE_INT32 = 5;
// Field type fixed64.
TYPE_FIXED64 = 6;
TYPE_FIXED64 = 6;
// Field type fixed32.
TYPE_FIXED32 = 7;
TYPE_FIXED32 = 7;
// Field type bool.
TYPE_BOOL = 8;
TYPE_BOOL = 8;
// Field type string.
TYPE_STRING = 9;
TYPE_STRING = 9;
// Field type group. Proto2 syntax only, and deprecated.
TYPE_GROUP = 10;
TYPE_GROUP = 10;
// Field type message.
TYPE_MESSAGE = 11;
TYPE_MESSAGE = 11;
// Field type bytes.
TYPE_BYTES = 12;
TYPE_BYTES = 12;
// Field type uint32.
TYPE_UINT32 = 13;
TYPE_UINT32 = 13;
// Field type enum.
TYPE_ENUM = 14;
TYPE_ENUM = 14;
// Field type sfixed32.
TYPE_SFIXED32 = 15;
TYPE_SFIXED32 = 15;
// Field type sfixed64.
TYPE_SFIXED64 = 16;
TYPE_SFIXED64 = 16;
// Field type sint32.
TYPE_SINT32 = 17;
TYPE_SINT32 = 17;
// Field type sint64.
TYPE_SINT64 = 18;
}
TYPE_SINT64 = 18;
};
// Whether a field is optional, required, or repeated.
enum Cardinality {

Binary file not shown.

View File

@ -1,51 +0,0 @@
#!/bin/bash
set -ex
if [ "$#" -ne 1 ]
then
echo "Usage: $0 <protobuf-version>"
exit 1
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
VERSION="$1"
TEMPDIR=$(mktemp -d "protobuf-$VERSION-XXX")
ARCHS=( \
"linux-aarch_64" \
"linux-x86_32" \
"linux-x86_64" \
"osx-x86_64" \
"win32" \
)
for ARCH in "${ARCHS[@]}"; do
mkdir "$TEMPDIR/$ARCH"
curl --proto '=https' --tlsv1.2 -sSfL \
"https://github.com/protocolbuffers/protobuf/releases/download/v$VERSION/protoc-$VERSION-$ARCH.zip" \
-o "$TEMPDIR/$ARCH/protoc.zip"
EXTENSION=""
if [[ "$ARCH" == *"win"* ]]; then
EXTENSION=".exe"
fi
unzip "$TEMPDIR/$ARCH/protoc.zip" -d "$TEMPDIR/$ARCH"
mv "$TEMPDIR/$ARCH/bin/protoc$EXTENSION" "$DIR/protobuf/protoc-$ARCH$EXTENSION"
done
# Update the include directory
rm -rf "$DIR/protobuf/include"
mv "$TEMPDIR/linux-x86_64/include" "$DIR/protobuf/"
# Update the Protocol Buffers license.
mkdir "$TEMPDIR/src"
curl --proto '=https' --tlsv1.2 -sSfL \
"https://github.com/protocolbuffers/protobuf/archive/v$VERSION.zip" \
https://github.com/protocolbuffers/protobuf/archive/v3.11.2.zip
-o "$TEMPDIR/src/protobuf.zip"
unzip "$TEMPDIR/src/protobuf.zip" -d "$TEMPDIR/src"
mv "$TEMPDIR/src/license.txt" "$DIR/protobuf/license"
rm -rf $TEMPDIR

View File

@ -1,6 +1,7 @@
[package]
name = "prost-derive"
version = "0.6.1"
# NB: When modifying, also modify html_root_url in lib.rs
version = "0.5.0"
authors = ["Dan Burkert <dan@danburkert.com>"]
license = "Apache-2.0"
repository = "https://github.com/danburkert/prost"
@ -13,8 +14,8 @@ edition = "2018"
proc_macro = true
[dependencies]
anyhow = "1"
failure = { version = "0.1", default-features = false }
itertools = "0.8"
proc-macro2 = "1"
quote = "1"
syn = { version = "1", features = [ "extra-traits" ] }
proc-macro2 = "0.4.4"
quote = "0.6.3"
syn = { version = "0.15", features = [ "extra-traits" ] }

View File

@ -1,6 +1,6 @@
use anyhow::{bail, Error};
use failure::{bail, Error};
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use quote::quote;
use syn::Meta;
use crate::field::{set_bool, set_option, tag_attr, word_attr, Label};
@ -58,10 +58,7 @@ impl Field {
pub fn new_oneof(attrs: &[Meta]) -> Result<Option<Field>, Error> {
if let Some(mut field) = Field::new(attrs, None)? {
if let Some(attr) = attrs.iter().find(|attr| Label::from_attr(attr).is_some()) {
bail!(
"invalid attribute for oneof field: {}",
attr.path().into_token_stream()
);
bail!("invalid atribute for oneof field: {}", attr.name());
}
field.label = Label::Required;
Ok(Some(field))
@ -75,15 +72,15 @@ impl Field {
match self.label {
Label::Optional => quote! {
if let Some(ref msg) = #ident {
::prost::encoding::group::encode(#tag, msg, buf);
_prost::encoding::group::encode(#tag, msg, buf);
}
},
Label::Required => quote! {
::prost::encoding::group::encode(#tag, &#ident, buf);
_prost::encoding::group::encode(#tag, &#ident, buf);
},
Label::Repeated => quote! {
for msg in &#ident {
::prost::encoding::group::encode(#tag, msg, buf);
_prost::encoding::group::encode(#tag, msg, buf);
}
},
}
@ -92,19 +89,16 @@ impl Field {
pub fn merge(&self, ident: TokenStream) -> TokenStream {
match self.label {
Label::Optional => quote! {
::prost::encoding::group::merge(
tag,
wire_type,
#ident.get_or_insert_with(Default::default),
buf,
ctx,
)
_prost::encoding::group::merge(tag, wire_type,
#ident.get_or_insert_with(Default::default),
buf,
ctx)
},
Label::Required => quote! {
::prost::encoding::group::merge(tag, wire_type, #ident, buf, ctx)
_prost::encoding::group::merge(tag, wire_type, &mut #ident, buf, ctx)
},
Label::Repeated => quote! {
::prost::encoding::group::merge_repeated(tag, wire_type, #ident, buf, ctx)
_prost::encoding::group::merge_repeated(tag, wire_type, &mut #ident, buf, ctx)
},
}
}
@ -113,13 +107,13 @@ impl Field {
let tag = self.tag;
match self.label {
Label::Optional => quote! {
#ident.as_ref().map_or(0, |msg| ::prost::encoding::group::encoded_len(#tag, msg))
#ident.as_ref().map_or(0, |msg| _prost::encoding::group::encoded_len(#tag, msg))
},
Label::Required => quote! {
::prost::encoding::group::encoded_len(#tag, &#ident)
_prost::encoding::group::encoded_len(#tag, &#ident)
},
Label::Repeated => quote! {
::prost::encoding::group::encoded_len_repeated(#tag, &#ident)
_prost::encoding::group::encoded_len_repeated(#tag, &#ident)
},
}
}

View File

@ -1,4 +1,4 @@
use anyhow::{bail, Error};
use failure::{bail, Error};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Ident, Lit, Meta, MetaNameValue, NestedMeta};
@ -53,11 +53,7 @@ impl Field {
for attr in attrs {
if let Some(t) = tag_attr(attr)? {
set_option(&mut tag, t, "duplicate tag attributes")?;
} else if let Some(map_ty) = attr
.path()
.get_ident()
.and_then(|i| MapTy::from_str(&i.to_string()))
{
} else if let Some(map_ty) = MapTy::from_str(&attr.name().to_string()) {
let (k, v): (String, String) = match *attr {
Meta::NameValue(MetaNameValue {
lit: Lit::Str(ref lit),
@ -81,15 +77,11 @@ impl Field {
bail!("invalid map attribute: must contain key and value types");
}
let k = match &meta_list.nested[0] {
&NestedMeta::Meta(Meta::Path(ref k)) if k.get_ident().is_some() => {
k.get_ident().unwrap().to_string()
}
&NestedMeta::Meta(Meta::Word(ref k)) => k.to_string(),
_ => bail!("invalid map attribute: key must be an identifier"),
};
let v = match &meta_list.nested[1] {
&NestedMeta::Meta(Meta::Path(ref v)) if v.get_ident().is_some() => {
v.get_ident().unwrap().to_string()
}
&NestedMeta::Meta(Meta::Word(ref v)) => v.to_string(),
_ => bail!("invalid map attribute: value must be an identifier"),
};
(k, v)
@ -125,52 +117,37 @@ impl Field {
pub fn encode(&self, ident: TokenStream) -> TokenStream {
let tag = self.tag;
let key_mod = self.key_ty.module();
let ke = quote!(::prost::encoding::#key_mod::encode);
let kl = quote!(::prost::encoding::#key_mod::encoded_len);
let ke = quote!(_prost::encoding::#key_mod::encode);
let kl = quote!(_prost::encoding::#key_mod::encoded_len);
let module = self.map_ty.module();
match self.value_ty {
ValueTy::Scalar(scalar::Ty::Enumeration(ref ty)) => {
let default = quote!(#ty::default() as i32);
quote! {
::prost::encoding::#module::encode_with_default(
#ke,
#kl,
::prost::encoding::int32::encode,
::prost::encoding::int32::encoded_len,
&(#default),
#tag,
&#ident,
buf,
);
_prost::encoding::#module::encode_with_default(#ke, #kl,
_prost::encoding::int32::encode,
_prost::encoding::int32::encoded_len,
&(#default),
#tag, &#ident, buf);
}
}
ValueTy::Scalar(ref value_ty) => {
let val_mod = value_ty.module();
let ve = quote!(::prost::encoding::#val_mod::encode);
let vl = quote!(::prost::encoding::#val_mod::encoded_len);
let ve = quote!(_prost::encoding::#val_mod::encode);
let vl = quote!(_prost::encoding::#val_mod::encoded_len);
quote! {
::prost::encoding::#module::encode(
#ke,
#kl,
#ve,
#vl,
#tag,
&#ident,
buf,
);
_prost::encoding::#module::encode(#ke, #kl, #ve, #vl,
#tag, &#ident, buf);
}
}
ValueTy::Message => {
quote! {
_prost::encoding::#module::encode(#ke, #kl,
_prost::encoding::message::encode,
_prost::encoding::message::encoded_len,
#tag, &#ident, buf);
}
}
ValueTy::Message => quote! {
::prost::encoding::#module::encode(
#ke,
#kl,
::prost::encoding::message::encode,
::prost::encoding::message::encoded_len,
#tag,
&#ident,
buf,
);
},
}
}
@ -178,36 +155,25 @@ impl Field {
/// into the map.
pub fn merge(&self, ident: TokenStream) -> TokenStream {
let key_mod = self.key_ty.module();
let km = quote!(::prost::encoding::#key_mod::merge);
let km = quote!(_prost::encoding::#key_mod::merge);
let module = self.map_ty.module();
match self.value_ty {
ValueTy::Scalar(scalar::Ty::Enumeration(ref ty)) => {
let default = quote!(#ty::default() as i32);
quote! {
::prost::encoding::#module::merge_with_default(
#km,
::prost::encoding::int32::merge,
#default,
&mut #ident,
buf,
ctx,
)
_prost::encoding::#module::merge_with_default(#km, _prost::encoding::int32::merge,
#default, &mut #ident, buf, ctx)
}
}
ValueTy::Scalar(ref value_ty) => {
let val_mod = value_ty.module();
let vm = quote!(::prost::encoding::#val_mod::merge);
quote!(::prost::encoding::#module::merge(#km, #vm, &mut #ident, buf, ctx))
let vm = quote!(_prost::encoding::#val_mod::merge);
quote!(_prost::encoding::#module::merge(#km, #vm, &mut #ident, buf, ctx))
}
ValueTy::Message => {
quote!(_prost::encoding::#module::merge(#km, _prost::encoding::message::merge,
&mut #ident, buf, ctx))
}
ValueTy::Message => quote! {
::prost::encoding::#module::merge(
#km,
::prost::encoding::message::merge,
&mut #ident,
buf,
ctx,
)
},
}
}
@ -215,34 +181,26 @@ impl Field {
pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
let tag = self.tag;
let key_mod = self.key_ty.module();
let kl = quote!(::prost::encoding::#key_mod::encoded_len);
let kl = quote!(_prost::encoding::#key_mod::encoded_len);
let module = self.map_ty.module();
match self.value_ty {
ValueTy::Scalar(scalar::Ty::Enumeration(ref ty)) => {
let default = quote!(#ty::default() as i32);
quote! {
::prost::encoding::#module::encoded_len_with_default(
#kl,
::prost::encoding::int32::encoded_len,
&(#default),
#tag,
&#ident,
)
_prost::encoding::#module::encoded_len_with_default(
#kl, _prost::encoding::int32::encoded_len,
&(#default), #tag, &#ident)
}
}
ValueTy::Scalar(ref value_ty) => {
let val_mod = value_ty.module();
let vl = quote!(::prost::encoding::#val_mod::encoded_len);
quote!(::prost::encoding::#module::encoded_len(#kl, #vl, #tag, &#ident))
let vl = quote!(_prost::encoding::#val_mod::encoded_len);
quote!(_prost::encoding::#module::encoded_len(#kl, #vl, #tag, &#ident))
}
ValueTy::Message => {
quote!(_prost::encoding::#module::encoded_len(#kl, _prost::encoding::message::encoded_len,
#tag, &#ident))
}
ValueTy::Message => quote! {
::prost::encoding::#module::encoded_len(
#kl,
::prost::encoding::message::encoded_len,
#tag,
&#ident,
)
},
}
}
@ -264,18 +222,10 @@ impl Field {
quote!()
};
let get_doc = format!(
"Returns the enum value for the corresponding key in `{}`, \
or `None` if the entry does not exist or it is not a valid enum value.",
ident,
);
let insert_doc = format!("Inserts a key value pair into `{}`.", ident);
Some(quote! {
#[doc=#get_doc]
pub fn #get(&self, key: #key_ref_ty) -> ::std::option::Option<#ty> {
self.#ident.get(#take_ref key).cloned().and_then(#ty::from_i32)
}
#[doc=#insert_doc]
pub fn #insert(&mut self, key: #key_ty, value: #ty) -> ::std::option::Option<#ty> {
self.#ident.insert(key, value as i32).and_then(#ty::from_i32)
}

View File

@ -1,6 +1,6 @@
use anyhow::{bail, Error};
use failure::{bail, Error};
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use quote::quote;
use syn::Meta;
use crate::field::{set_bool, set_option, tag_attr, word_attr, Label};
@ -61,10 +61,7 @@ impl Field {
pub fn new_oneof(attrs: &[Meta]) -> Result<Option<Field>, Error> {
if let Some(mut field) = Field::new(attrs, None)? {
if let Some(attr) = attrs.iter().find(|attr| Label::from_attr(attr).is_some()) {
bail!(
"invalid attribute for oneof field: {}",
attr.path().into_token_stream()
);
bail!("invalid atribute for oneof field: {}", attr.name());
}
field.label = Label::Required;
Ok(Some(field))
@ -78,15 +75,15 @@ impl Field {
match self.label {
Label::Optional => quote! {
if let Some(ref msg) = #ident {
::prost::encoding::message::encode(#tag, msg, buf);
_prost::encoding::message::encode(#tag, msg, buf);
}
},
Label::Required => quote! {
::prost::encoding::message::encode(#tag, &#ident, buf);
_prost::encoding::message::encode(#tag, &#ident, buf);
},
Label::Repeated => quote! {
for msg in &#ident {
::prost::encoding::message::encode(#tag, msg, buf);
_prost::encoding::message::encode(#tag, msg, buf);
}
},
}
@ -95,16 +92,16 @@ impl Field {
pub fn merge(&self, ident: TokenStream) -> TokenStream {
match self.label {
Label::Optional => quote! {
::prost::encoding::message::merge(wire_type,
_prost::encoding::message::merge(wire_type,
#ident.get_or_insert_with(Default::default),
buf,
ctx)
},
Label::Required => quote! {
::prost::encoding::message::merge(wire_type, #ident, buf, ctx)
_prost::encoding::message::merge(wire_type, &mut #ident, buf, ctx)
},
Label::Repeated => quote! {
::prost::encoding::message::merge_repeated(wire_type, #ident, buf, ctx)
_prost::encoding::message::merge_repeated(wire_type, &mut #ident, buf, ctx)
},
}
}
@ -113,13 +110,13 @@ impl Field {
let tag = self.tag;
match self.label {
Label::Optional => quote! {
#ident.as_ref().map_or(0, |msg| ::prost::encoding::message::encoded_len(#tag, msg))
#ident.as_ref().map_or(0, |msg| _prost::encoding::message::encoded_len(#tag, msg))
},
Label::Required => quote! {
::prost::encoding::message::encoded_len(#tag, &#ident)
_prost::encoding::message::encoded_len(#tag, &#ident)
},
Label::Repeated => quote! {
::prost::encoding::message::encoded_len_repeated(#tag, &#ident)
_prost::encoding::message::encoded_len_repeated(#tag, &#ident)
},
}
}

View File

@ -7,7 +7,7 @@ mod scalar;
use std::fmt;
use std::slice;
use anyhow::{bail, Error};
use failure::{bail, Error};
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Attribute, Ident, Lit, LitBool, Meta, MetaList, MetaNameValue, NestedMeta};
@ -200,9 +200,9 @@ impl Label {
/// Parses a string into a field label.
/// If the string doesn't match a field label, `None` is returned.
fn from_attr(attr: &Meta) -> Option<Label> {
if let Meta::Path(ref path) = *attr {
if let Meta::Word(ref ident) = *attr {
for &label in Label::variants() {
if path.is_ident(label.as_str()) {
if ident == label.as_str() {
return Some(label);
}
}
@ -227,10 +227,10 @@ impl fmt::Display for Label {
pub(super) fn prost_attrs(attrs: Vec<Attribute>) -> Result<Vec<Meta>, Error> {
Ok(attrs
.iter()
.flat_map(Attribute::parse_meta)
.flat_map(Attribute::interpret_meta)
.flat_map(|meta| match meta {
Meta::List(MetaList { path, nested, .. }) => {
if path.is_ident("prost") {
Meta::List(MetaList { ident, nested, .. }) => {
if ident == "prost" {
nested.into_iter().collect()
} else {
Vec::new()
@ -241,7 +241,7 @@ pub(super) fn prost_attrs(attrs: Vec<Attribute>) -> Result<Vec<Meta>, Error> {
.flat_map(|attr| -> Result<_, _> {
match attr {
NestedMeta::Meta(attr) => Ok(attr),
NestedMeta::Lit(lit) => bail!("invalid prost attribute: {:?}", lit),
NestedMeta::Literal(lit) => bail!("invalid prost attribute: {:?}", lit),
}
})
.collect())
@ -270,15 +270,15 @@ pub fn set_bool(b: &mut bool, message: &str) -> Result<(), Error> {
/// Unpacks an attribute into a (key, boolean) pair, returning the boolean value.
/// If the key doesn't match the attribute, `None` is returned.
fn bool_attr(key: &str, attr: &Meta) -> Result<Option<bool>, Error> {
if !attr.path().is_ident(key) {
if attr.name() != key {
return Ok(None);
}
match *attr {
Meta::Path(..) => Ok(Some(true)),
Meta::Word(..) => Ok(Some(true)),
Meta::List(ref meta_list) => {
// TODO(rustlang/rust#23121): slice pattern matching would make this much nicer.
if meta_list.nested.len() == 1 {
if let NestedMeta::Lit(Lit::Bool(LitBool { value, .. })) = meta_list.nested[0] {
if let NestedMeta::Literal(Lit::Bool(LitBool { value, .. })) = meta_list.nested[0] {
return Ok(Some(value));
}
}
@ -302,23 +302,23 @@ fn bool_attr(key: &str, attr: &Meta) -> Result<Option<bool>, Error> {
/// Checks if an attribute matches a word.
fn word_attr(key: &str, attr: &Meta) -> bool {
if let Meta::Path(ref path) = *attr {
path.is_ident(key)
if let Meta::Word(ref ident) = *attr {
ident == key
} else {
false
}
}
pub(super) fn tag_attr(attr: &Meta) -> Result<Option<u32>, Error> {
if !attr.path().is_ident("tag") {
if attr.name() != "tag" {
return Ok(None);
}
match *attr {
Meta::List(ref meta_list) => {
// TODO(rustlang/rust#23121): slice pattern matching would make this much nicer.
if meta_list.nested.len() == 1 {
if let NestedMeta::Lit(Lit::Int(ref lit)) = meta_list.nested[0] {
return Ok(Some(lit.base10_parse()?));
if let NestedMeta::Literal(Lit::Int(ref lit)) = meta_list.nested[0] {
return Ok(Some(lit.value() as u32));
}
}
bail!("invalid tag attribute: {:?}", attr);
@ -329,7 +329,7 @@ pub(super) fn tag_attr(attr: &Meta) -> Result<Option<u32>, Error> {
.parse::<u32>()
.map_err(Error::from)
.map(Option::Some),
Lit::Int(ref lit) => Ok(Some(lit.base10_parse()?)),
Lit::Int(ref lit) => Ok(Some(lit.value() as u32)),
_ => bail!("invalid tag attribute: {:?}", attr),
},
_ => bail!("invalid tag attribute: {:?}", attr),
@ -337,15 +337,15 @@ pub(super) fn tag_attr(attr: &Meta) -> Result<Option<u32>, Error> {
}
fn tags_attr(attr: &Meta) -> Result<Option<Vec<u32>>, Error> {
if !attr.path().is_ident("tags") {
if attr.name() != "tags" {
return Ok(None);
}
match *attr {
Meta::List(ref meta_list) => {
let mut tags = Vec::with_capacity(meta_list.nested.len());
for item in &meta_list.nested {
if let NestedMeta::Lit(Lit::Int(ref lit)) = *item {
tags.push(lit.base10_parse()?);
if let NestedMeta::Literal(Lit::Int(ref lit)) = *item {
tags.push(lit.value() as u32);
} else {
bail!("invalid tag attribute: {:?}", attr);
}

View File

@ -1,4 +1,4 @@
use anyhow::{bail, Error};
use failure::{bail, Error};
use proc_macro2::TokenStream;
use quote::quote;
use syn::{parse_str, Lit, Meta, MetaNameValue, NestedMeta, Path};
@ -18,7 +18,7 @@ impl Field {
let mut unknown_attrs = Vec::new();
for attr in attrs {
if attr.path().is_ident("oneof") {
if attr.name() == "oneof" {
let t = match *attr {
Meta::NameValue(MetaNameValue {
lit: Lit::Str(ref lit),
@ -26,12 +26,8 @@ impl Field {
}) => parse_str::<Path>(&lit.value())?,
Meta::List(ref list) if list.nested.len() == 1 => {
// TODO(rustlang/rust#23121): slice pattern matching would make this much nicer.
if let NestedMeta::Meta(Meta::Path(ref path)) = list.nested[0] {
if let Some(ident) = path.get_ident() {
Path::from(ident.clone())
} else {
bail!("invalid oneof attribute: item must be an identifier");
}
if let NestedMeta::Meta(Meta::Word(ref ident)) = list.nested[0] {
Path::from(ident.clone())
} else {
bail!("invalid oneof attribute: item must be an identifier");
}
@ -81,7 +77,7 @@ impl Field {
pub fn merge(&self, ident: TokenStream) -> TokenStream {
let ty = &self.ty;
quote! {
#ty::merge(#ident, tag, wire_type, buf, ctx)
#ty::merge(&mut #ident, tag, wire_type, buf, ctx)
}
}

View File

@ -1,11 +1,11 @@
use std::convert::TryFrom;
use std::fmt;
use anyhow::{anyhow, bail, Error};
use failure::{bail, format_err, Error};
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{
self, parse_str, Ident, Lit, LitByteStr, Meta, MetaList, MetaNameValue, NestedMeta, Path,
self, parse_str, FloatSuffix, Ident, IntSuffix, Lit, LitByteStr, Meta, MetaList, MetaNameValue,
NestedMeta, Path,
};
use crate::field::{bool_attr, set_option, tag_attr, Label};
@ -118,7 +118,7 @@ impl Field {
Kind::Repeated => quote!(encode_repeated),
Kind::Packed => quote!(encode_packed),
};
let encode_fn = quote!(::prost::encoding::#module::#encode_fn);
let encode_fn = quote!(_prost::encoding::#module::#encode_fn);
let tag = self.tag;
match self.kind {
@ -149,11 +149,11 @@ impl Field {
Kind::Plain(..) | Kind::Optional(..) | Kind::Required(..) => quote!(merge),
Kind::Repeated | Kind::Packed => quote!(merge_repeated),
};
let merge_fn = quote!(::prost::encoding::#module::#merge_fn);
let merge_fn = quote!(_prost::encoding::#module::#merge_fn);
match self.kind {
Kind::Plain(..) | Kind::Required(..) | Kind::Repeated | Kind::Packed => quote! {
#merge_fn(wire_type, #ident, buf, ctx)
#merge_fn(wire_type, &mut #ident, buf, ctx)
},
Kind::Optional(..) => quote! {
#merge_fn(wire_type,
@ -172,7 +172,7 @@ impl Field {
Kind::Repeated => quote!(encoded_len_repeated),
Kind::Packed => quote!(encoded_len_packed),
};
let encoded_len_fn = quote!(::prost::encoding::#module::#encoded_len_fn);
let encoded_len_fn = quote!(_prost::encoding::#module::#encoded_len_fn);
let tag = self.tag;
match self.kind {
@ -278,63 +278,38 @@ impl Field {
if ident_str.starts_with("r#") {
ident_str = ident_str[2..].to_owned();
}
let set = Ident::new(&format!("set_{}", ident_str), Span::call_site());
let push = Ident::new(&format!("push_{}", ident_str), Span::call_site());
if let Ty::Enumeration(ref ty) = self.ty {
let set = Ident::new(&format!("set_{}", ident_str), Span::call_site());
let set_doc = format!("Sets `{}` to the provided enum value.", ident_str);
Some(match self.kind {
Kind::Plain(ref default) | Kind::Required(ref default) => {
let get_doc = format!(
"Returns the enum value of `{}`, \
or the default if the field is set to an invalid enum value.",
ident_str,
);
quote! {
#[doc=#get_doc]
pub fn #ident(&self) -> #ty {
#ty::from_i32(self.#ident).unwrap_or(#default)
}
#[doc=#set_doc]
pub fn #set(&mut self, value: #ty) {
self.#ident = value as i32;
}
}
}
Kind::Optional(ref default) => {
let get_doc = format!(
"Returns the enum value of `{}`, \
or the default if the field is unset or set to an invalid enum value.",
ident_str,
);
quote! {
#[doc=#get_doc]
pub fn #ident(&self) -> #ty {
self.#ident.and_then(#ty::from_i32).unwrap_or(#default)
}
#[doc=#set_doc]
pub fn #set(&mut self, value: #ty) {
self.#ident = ::std::option::Option::Some(value as i32);
}
}
}
Kind::Repeated | Kind::Packed => {
let iter_doc = format!(
"Returns an iterator which yields the valid enum values contained in `{}`.",
ident_str,
);
let push = Ident::new(&format!("push_{}", ident_str), Span::call_site());
let push_doc = format!("Appends the provided enum value to `{}`.", ident_str);
quote! {
#[doc=#iter_doc]
pub fn #ident(&self) -> ::std::iter::FilterMap<
::std::iter::Cloned<::std::slice::Iter<i32>>,
fn(i32) -> ::std::option::Option<#ty>,
> {
pub fn #ident(&self) -> ::std::iter::FilterMap<::std::iter::Cloned<::std::slice::Iter<i32>>,
fn(i32) -> Option<#ty>> {
self.#ident.iter().cloned().filter_map(#ty::from_i32)
}
#[doc=#push_doc]
pub fn #push(&mut self, value: #ty) {
self.#ident.push(value as i32);
}
@ -350,13 +325,7 @@ impl Field {
quote!(::std::option::Option::Some(ref val) => &val[..],)
};
let get_doc = format!(
"Returns the value of `{0}`, or the default value if `{0}` is unset.",
ident_str,
);
Some(quote! {
#[doc=#get_doc]
pub fn #ident(&self) -> #ty {
match self.#ident {
#match_some
@ -394,35 +363,35 @@ pub enum Ty {
impl Ty {
pub fn from_attr(attr: &Meta) -> Result<Option<Ty>, Error> {
let ty = match *attr {
Meta::Path(ref name) if name.is_ident("float") => Ty::Float,
Meta::Path(ref name) if name.is_ident("double") => Ty::Double,
Meta::Path(ref name) if name.is_ident("int32") => Ty::Int32,
Meta::Path(ref name) if name.is_ident("int64") => Ty::Int64,
Meta::Path(ref name) if name.is_ident("uint32") => Ty::Uint32,
Meta::Path(ref name) if name.is_ident("uint64") => Ty::Uint64,
Meta::Path(ref name) if name.is_ident("sint32") => Ty::Sint32,
Meta::Path(ref name) if name.is_ident("sint64") => Ty::Sint64,
Meta::Path(ref name) if name.is_ident("fixed32") => Ty::Fixed32,
Meta::Path(ref name) if name.is_ident("fixed64") => Ty::Fixed64,
Meta::Path(ref name) if name.is_ident("sfixed32") => Ty::Sfixed32,
Meta::Path(ref name) if name.is_ident("sfixed64") => Ty::Sfixed64,
Meta::Path(ref name) if name.is_ident("bool") => Ty::Bool,
Meta::Path(ref name) if name.is_ident("string") => Ty::String,
Meta::Path(ref name) if name.is_ident("bytes") => Ty::Bytes,
Meta::Word(ref name) if name == "float" => Ty::Float,
Meta::Word(ref name) if name == "double" => Ty::Double,
Meta::Word(ref name) if name == "int32" => Ty::Int32,
Meta::Word(ref name) if name == "int64" => Ty::Int64,
Meta::Word(ref name) if name == "uint32" => Ty::Uint32,
Meta::Word(ref name) if name == "uint64" => Ty::Uint64,
Meta::Word(ref name) if name == "sint32" => Ty::Sint32,
Meta::Word(ref name) if name == "sint64" => Ty::Sint64,
Meta::Word(ref name) if name == "fixed32" => Ty::Fixed32,
Meta::Word(ref name) if name == "fixed64" => Ty::Fixed64,
Meta::Word(ref name) if name == "sfixed32" => Ty::Sfixed32,
Meta::Word(ref name) if name == "sfixed64" => Ty::Sfixed64,
Meta::Word(ref name) if name == "bool" => Ty::Bool,
Meta::Word(ref name) if name == "string" => Ty::String,
Meta::Word(ref name) if name == "bytes" => Ty::Bytes,
Meta::NameValue(MetaNameValue {
ref path,
ref ident,
lit: Lit::Str(ref l),
..
}) if path.is_ident("enumeration") => Ty::Enumeration(parse_str::<Path>(&l.value())?),
}) if ident == "enumeration" => Ty::Enumeration(parse_str::<Path>(&l.value())?),
Meta::List(MetaList {
ref path,
ref ident,
ref nested,
..
}) if path.is_ident("enumeration") => {
}) if ident == "enumeration" => {
// TODO(rustlang/rust#23121): slice pattern matching would make this much nicer.
if nested.len() == 1 {
if let NestedMeta::Meta(Meta::Path(ref path)) = nested[0] {
Ty::Enumeration(path.clone())
if let NestedMeta::Meta(Meta::Word(ref ident)) = nested[0] {
Ty::Enumeration(Path::from(ident.clone()))
} else {
bail!("invalid enumeration attribute: item must be an identifier");
}
@ -437,7 +406,7 @@ impl Ty {
pub fn from_str(s: &str) -> Result<Ty, Error> {
let enumeration_len = "enumeration".len();
let error = Err(anyhow!("invalid type: {}", s));
let error = Err(format_err!("invalid type: {}", s));
let ty = match s.trim() {
"float" => Ty::Float,
"double" => Ty::Double,
@ -583,7 +552,7 @@ pub enum DefaultValue {
impl DefaultValue {
pub fn from_attr(attr: &Meta) -> Result<Option<Lit>, Error> {
if !attr.path().is_ident("default") {
if attr.name() != "default" {
return Ok(None);
} else if let Meta::NameValue(ref name_value) = *attr {
Ok(Some(name_value.lit.clone()))
@ -599,35 +568,51 @@ impl DefaultValue {
let is_u32 = *ty == Ty::Uint32 || *ty == Ty::Fixed32;
let is_u64 = *ty == Ty::Uint64 || *ty == Ty::Fixed64;
let empty_or_is = |expected, actual: &str| expected == actual || actual.is_empty();
let default = match lit {
Lit::Int(ref lit) if is_i32 && empty_or_is("i32", lit.suffix()) => {
DefaultValue::I32(lit.base10_parse()?)
Lit::Int(ref lit)
if is_i32
&& (lit.suffix() == IntSuffix::I32 || lit.suffix() == IntSuffix::None) =>
{
DefaultValue::I32(lit.value() as _)
}
Lit::Int(ref lit) if is_i64 && empty_or_is("i64", lit.suffix()) => {
DefaultValue::I64(lit.base10_parse()?)
Lit::Int(ref lit)
if is_i64
&& (lit.suffix() == IntSuffix::I64 || lit.suffix() == IntSuffix::None) =>
{
DefaultValue::I64(lit.value() as _)
}
Lit::Int(ref lit) if is_u32 && empty_or_is("u32", lit.suffix()) => {
DefaultValue::U32(lit.base10_parse()?)
Lit::Int(ref lit)
if is_u32
&& (lit.suffix() == IntSuffix::U32 || lit.suffix() == IntSuffix::None) =>
{
DefaultValue::U32(lit.value() as _)
}
Lit::Int(ref lit) if is_u64 && empty_or_is("u64", lit.suffix()) => {
DefaultValue::U64(lit.base10_parse()?)
Lit::Int(ref lit)
if is_u64
&& (lit.suffix() == IntSuffix::U64 || lit.suffix() == IntSuffix::None) =>
{
DefaultValue::U64(lit.value())
}
Lit::Float(ref lit) if *ty == Ty::Float && empty_or_is("f32", lit.suffix()) => {
DefaultValue::F32(lit.base10_parse()?)
Lit::Float(ref lit)
if *ty == Ty::Float
&& (lit.suffix() == FloatSuffix::F32 || lit.suffix() == FloatSuffix::None) =>
{
DefaultValue::F32(lit.value() as _)
}
Lit::Int(ref lit) if *ty == Ty::Float => DefaultValue::F32(lit.base10_parse()?),
Lit::Int(ref lit) if *ty == Ty::Float => DefaultValue::F32(lit.value() as _),
Lit::Float(ref lit) if *ty == Ty::Double && empty_or_is("f64", lit.suffix()) => {
DefaultValue::F64(lit.base10_parse()?)
Lit::Float(ref lit)
if *ty == Ty::Double
&& (lit.suffix() == FloatSuffix::F64 || lit.suffix() == FloatSuffix::None) =>
{
DefaultValue::F64(lit.value())
}
Lit::Int(ref lit) if *ty == Ty::Double => DefaultValue::F64(lit.base10_parse()?),
Lit::Int(ref lit) if *ty == Ty::Double => DefaultValue::F64(lit.value() as _),
Lit::Bool(ref lit) if *ty == Ty::Bool => DefaultValue::Bool(lit.value),
Lit::Str(ref lit) if *ty == Ty::String => DefaultValue::String(lit.value()),
Lit::ByteStr(ref lit) if *ty == Ty::Bytes => DefaultValue::Bytes(lit.value()),
Lit::Str(ref lit) if *ty == Ty::String => DefaultValue::String(lit.value().clone()),
Lit::ByteStr(ref lit) if *ty == Ty::Bytes => DefaultValue::Bytes(lit.value().clone()),
Lit::Str(ref lit) => {
let value = lit.value();
@ -680,36 +665,48 @@ impl DefaultValue {
if value.chars().next() == Some('-') {
if let Ok(lit) = syn::parse_str::<Lit>(&value[1..]) {
match lit {
Lit::Int(ref lit) if is_i32 && empty_or_is("i32", lit.suffix()) => {
// Initially parse into an i64, so that i32::MIN does not overflow.
let value: i64 = -lit.base10_parse()?;
return Ok(i32::try_from(value).map(DefaultValue::I32)?);
Lit::Int(ref lit)
if is_i32
&& (lit.suffix() == IntSuffix::I32
|| lit.suffix() == IntSuffix::None) =>
{
return Ok(DefaultValue::I32((!lit.value() + 1) as i32));
}
Lit::Int(ref lit) if is_i64 && empty_or_is("i64", lit.suffix()) => {
// Initially parse into an i128, so that i64::MIN does not overflow.
let value: i128 = -lit.base10_parse()?;
return Ok(i64::try_from(value).map(DefaultValue::I64)?);
Lit::Int(ref lit)
if is_i64
&& (lit.suffix() == IntSuffix::I64
|| lit.suffix() == IntSuffix::None) =>
{
return Ok(DefaultValue::I64((!lit.value() + 1) as i64));
}
Lit::Float(ref lit)
if *ty == Ty::Float && empty_or_is("f32", lit.suffix()) =>
if *ty == Ty::Float
&& (lit.suffix() == FloatSuffix::F32
|| lit.suffix() == FloatSuffix::None) =>
{
return Ok(DefaultValue::F32(-lit.base10_parse()?));
return Ok(DefaultValue::F32(-lit.value() as f32));
}
Lit::Float(ref lit)
if *ty == Ty::Double && empty_or_is("f64", lit.suffix()) =>
if *ty == Ty::Double
&& (lit.suffix() == FloatSuffix::F64
|| lit.suffix() == FloatSuffix::None) =>
{
return Ok(DefaultValue::F64(-lit.base10_parse()?));
return Ok(DefaultValue::F64(-lit.value()));
}
Lit::Int(ref lit) if *ty == Ty::Float && lit.suffix().is_empty() => {
return Ok(DefaultValue::F32(-lit.base10_parse()?));
Lit::Int(ref lit)
if *ty == Ty::Float && lit.suffix() == IntSuffix::None =>
{
return Ok(DefaultValue::F32(-(lit.value() as f32)));
}
Lit::Int(ref lit) if *ty == Ty::Double && lit.suffix().is_empty() => {
return Ok(DefaultValue::F64(-lit.base10_parse()?));
Lit::Int(ref lit)
if *ty == Ty::Double && lit.suffix() == IntSuffix::None =>
{
return Ok(DefaultValue::F64(-(lit.value() as f64)));
}
_ => (),

View File

@ -1,13 +1,13 @@
#![doc(html_root_url = "https://docs.rs/prost-derive/0.6.1")]
#![doc(html_root_url = "https://docs.rs/prost-derive/0.5.0")]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "4096"]
extern crate proc_macro;
use anyhow::bail;
use failure::bail;
use quote::quote;
use anyhow::Error;
use failure::Error;
use itertools::Itertools;
use proc_macro::TokenStream;
use proc_macro2::Span;
@ -71,7 +71,7 @@ fn try_message(input: TokenStream) -> Result<TokenStream, Error> {
)),
}
})
.collect::<Result<Vec<_>, _>>()?;
.collect::<Result<Vec<(Ident, Field)>, failure::Context<String>>>()?;
// We want Debug to be in declaration order
let unsorted_fields = fields.clone();
@ -94,6 +94,9 @@ fn try_message(input: TokenStream) -> Result<TokenStream, Error> {
bail!("message {} has fields with duplicate tags", ident);
}
// Put impls in a const, so that 'extern crate' can be used.
let dummy_const = Ident::new(&format!("{}_MESSAGE", ident), Span::call_site());
let encoded_len = fields
.iter()
.map(|&(ref field_ident, ref field)| field.encoded_len(quote!(self.#field_ident)));
@ -103,21 +106,16 @@ fn try_message(input: TokenStream) -> Result<TokenStream, Error> {
.map(|&(ref field_ident, ref field)| field.encode(quote!(self.#field_ident)));
let merge = fields.iter().map(|&(ref field_ident, ref field)| {
let merge = field.merge(quote!(value));
let merge = field.merge(quote!(self.#field_ident));
let tags = field
.tags()
.into_iter()
.map(|tag| quote!(#tag))
.intersperse(quote!(|));
quote! {
#(#tags)* => {
let mut value = &mut self.#field_ident;
#merge.map_err(|mut error| {
error.push(STRUCT_NAME, stringify!(#field_ident));
error
})
},
}
quote!(#(#tags)* => #merge.map_err(|mut error| {
error.push(STRUCT_NAME, stringify!(#field_ident));
error
}),)
});
let struct_name = if fields.is_empty() {
@ -176,55 +174,60 @@ fn try_message(input: TokenStream) -> Result<TokenStream, Error> {
};
let expanded = quote! {
impl ::prost::Message for #ident {
#[allow(unused_variables)]
fn encode_raw<B>(&self, buf: &mut B) where B: ::prost::bytes::BufMut {
#(#encode)*
}
#[allow(non_snake_case, unused_attributes)]
const #dummy_const: () = {
extern crate prost as _prost;
extern crate bytes as _bytes;
#[allow(unused_variables)]
fn merge_field<B>(
&mut self,
tag: u32,
wire_type: ::prost::encoding::WireType,
buf: &mut B,
ctx: ::prost::encoding::DecodeContext,
) -> ::std::result::Result<(), ::prost::DecodeError>
where B: ::prost::bytes::Buf {
#struct_name
match tag {
#(#merge)*
_ => ::prost::encoding::skip_field(wire_type, tag, buf, ctx),
impl _prost::Message for #ident {
#[allow(unused_variables)]
fn encode_raw<B>(&self, buf: &mut B) where B: _bytes::BufMut {
#(#encode)*
}
#[allow(unused_variables)]
fn merge_field<B>(&mut self,
tag: u32,
wire_type: _prost::encoding::WireType,
buf: &mut B,
ctx: _prost::encoding::DecodeContext,
) -> ::std::result::Result<(), _prost::DecodeError>
where B: _bytes::Buf {
#struct_name
match tag {
#(#merge)*
_ => _prost::encoding::skip_field(wire_type, tag, buf),
}
}
#[inline]
fn encoded_len(&self) -> usize {
0 #(+ #encoded_len)*
}
fn clear(&mut self) {
#(#clear;)*
}
}
#[inline]
fn encoded_len(&self) -> usize {
0 #(+ #encoded_len)*
}
fn clear(&mut self) {
#(#clear;)*
}
}
impl Default for #ident {
fn default() -> #ident {
#ident {
#(#default)*
impl Default for #ident {
fn default() -> #ident {
#ident {
#(#default)*
}
}
}
}
impl ::std::fmt::Debug for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let mut builder = #debug_builder;
#(#debugs;)*
builder.finish()
impl ::std::fmt::Debug for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let mut builder = #debug_builder;
#(#debugs;)*
builder.finish()
}
}
}
#methods
#methods
};
};
Ok(expanded.into())
@ -277,6 +280,8 @@ fn try_enumeration(input: TokenStream) -> Result<TokenStream, Error> {
let default = variants[0].0.clone();
// Put impls in a const, so that 'extern crate' can be used.
let dummy_const = Ident::new(&format!("{}_ENUMERATION", ident), Span::call_site());
let is_valid = variants
.iter()
.map(|&(_, ref value)| quote!(#value => true));
@ -291,35 +296,39 @@ fn try_enumeration(input: TokenStream) -> Result<TokenStream, Error> {
);
let expanded = quote! {
impl #ident {
#[doc=#is_valid_doc]
pub fn is_valid(value: i32) -> bool {
match value {
#(#is_valid,)*
_ => false,
#[allow(non_snake_case, unused_attributes)]
const #dummy_const: () = {
impl #ident {
#[doc=#is_valid_doc]
pub fn is_valid(value: i32) -> bool {
match value {
#(#is_valid,)*
_ => false,
}
}
#[doc=#from_i32_doc]
pub fn from_i32(value: i32) -> ::std::option::Option<#ident> {
match value {
#(#from,)*
_ => ::std::option::Option::None,
}
}
}
#[doc=#from_i32_doc]
pub fn from_i32(value: i32) -> ::std::option::Option<#ident> {
match value {
#(#from,)*
_ => ::std::option::Option::None,
impl ::std::default::Default for #ident {
fn default() -> #ident {
#ident::#default
}
}
}
impl ::std::default::Default for #ident {
fn default() -> #ident {
#ident::#default
impl ::std::convert::From<#ident> for i32 {
fn from(value: #ident) -> i32 {
value as i32
}
}
}
impl ::std::convert::From<#ident> for i32 {
fn from(value: #ident) -> i32 {
value as i32
}
}
};
};
Ok(expanded.into())
@ -389,6 +398,9 @@ fn try_oneof(input: TokenStream) -> Result<TokenStream, Error> {
panic!("invalid oneof {}: variants have duplicate tags", ident);
}
// Put impls in a const, so that 'extern crate' can be used.
let dummy_const = Ident::new(&format!("{}_ONEOF", ident), Span::call_site());
let encode = fields.iter().map(|&(ref variant_ident, ref field)| {
let encode = field.encode(quote!(*value));
quote!(#ident::#variant_ident(ref value) => { #encode })
@ -399,16 +411,8 @@ fn try_oneof(input: TokenStream) -> Result<TokenStream, Error> {
let merge = field.merge(quote!(value));
quote! {
#tag => {
match field {
::std::option::Option::Some(#ident::#variant_ident(ref mut value)) => {
#merge
},
_ => {
let mut owned_value = ::std::default::Default::default();
let value = &mut owned_value;
#merge.map(|_| *field = ::std::option::Option::Some(#ident::#variant_ident(owned_value)))
},
}
let mut value = ::std::default::Default::default();
#merge.map(|_| *field = ::std::option::Option::Some(#ident::#variant_ident(value)))
}
}
});
@ -429,42 +433,47 @@ fn try_oneof(input: TokenStream) -> Result<TokenStream, Error> {
});
let expanded = quote! {
impl #ident {
pub fn encode<B>(&self, buf: &mut B) where B: ::prost::bytes::BufMut {
match *self {
#(#encode,)*
#[allow(non_snake_case, unused_attributes)]
const #dummy_const: () = {
extern crate bytes as _bytes;
extern crate prost as _prost;
impl #ident {
pub fn encode<B>(&self, buf: &mut B) where B: _bytes::BufMut {
match *self {
#(#encode,)*
}
}
pub fn merge<B>(field: &mut ::std::option::Option<#ident>,
tag: u32,
wire_type: _prost::encoding::WireType,
buf: &mut B,
ctx: _prost::encoding::DecodeContext,
) -> ::std::result::Result<(), _prost::DecodeError>
where B: _bytes::Buf {
match tag {
#(#merge,)*
_ => unreachable!(concat!("invalid ", stringify!(#ident), " tag: {}"), tag),
}
}
#[inline]
pub fn encoded_len(&self) -> usize {
match *self {
#(#encoded_len,)*
}
}
}
pub fn merge<B>(
field: &mut ::std::option::Option<#ident>,
tag: u32,
wire_type: ::prost::encoding::WireType,
buf: &mut B,
ctx: ::prost::encoding::DecodeContext,
) -> ::std::result::Result<(), ::prost::DecodeError>
where B: ::prost::bytes::Buf {
match tag {
#(#merge,)*
_ => unreachable!(concat!("invalid ", stringify!(#ident), " tag: {}"), tag),
impl ::std::fmt::Debug for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
#(#debug,)*
}
}
}
#[inline]
pub fn encoded_len(&self) -> usize {
match *self {
#(#encoded_len,)*
}
}
}
impl ::std::fmt::Debug for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
#(#debug,)*
}
}
}
};
};
Ok(expanded.into())

View File

@ -1,6 +1,7 @@
[package]
name = "prost-types"
version = "0.6.1"
# NB: When modifying, also modify html_root_url in lib.rs
version = "0.5.0"
authors = ["Dan Burkert <dan@danburkert.com>"]
license = "Apache-2.0"
repository = "https://github.com/danburkert/prost"
@ -15,4 +16,4 @@ test = false
[dependencies]
bytes = { version = "0.5", default-features = false }
prost = { version = "0.6.1", path = "..", default-features = false }
prost = { version = "0.5.0", path = "..", default-features = false }

View File

@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/prost-types/0.6.1")]
#![doc(html_root_url = "https://docs.rs/prost-codegen/0.5.0")]
//! Protocol Buffers well-known types.
//!
@ -9,7 +9,6 @@
//!
//! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
use std::convert::TryFrom;
use std::i32;
use std::i64;
use std::time;
@ -72,12 +71,11 @@ impl From<time::Duration> for Duration {
}
}
impl TryFrom<Duration> for time::Duration {
type Error = time::Duration;
/// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
/// `std::time::Duration`.
fn try_from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
/// Converts a `Duration` to a result containing a positive (`Ok`) or negative (`Err`)
/// `std::time::Duration`.
// TODO: convert this to TryFrom when it's stable.
impl From<Duration> for Result<time::Duration, time::Duration> {
fn from(mut duration: Duration) -> Result<time::Duration, time::Duration> {
duration.normalize();
if duration.seconds >= 0 {
Ok(time::Duration::new(
@ -128,12 +126,11 @@ impl From<time::SystemTime> for Timestamp {
}
}
impl TryFrom<Timestamp> for time::SystemTime {
type Error = time::Duration;
/// Converts a `Timestamp` to a `SystemTime`, or if the timestamp falls before the Unix epoch,
/// a duration containing the difference.
fn try_from(mut timestamp: Timestamp) -> Result<time::SystemTime, time::Duration> {
/// Converts a `Timestamp` to a `SystemTime`, or if the timestamp falls before the Unix epoch, a
/// duration containing the difference.
// TODO: convert this to TryFrom when it's stable.
impl From<Timestamp> for Result<time::SystemTime, time::Duration> {
fn from(mut timestamp: Timestamp) -> Result<time::SystemTime, time::Duration> {
timestamp.normalize();
if timestamp.seconds >= 0 {
Ok(time::UNIX_EPOCH

View File

@ -75,10 +75,8 @@ pub struct DescriptorProto {
pub mod descriptor_proto {
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ExtensionRange {
/// Inclusive.
#[prost(int32, optional, tag="1")]
pub start: ::std::option::Option<i32>,
/// Exclusive.
#[prost(int32, optional, tag="2")]
pub end: ::std::option::Option<i32>,
#[prost(message, optional, tag="3")]
@ -403,8 +401,8 @@ pub struct FileOptions {
#[prost(string, optional, tag="41")]
pub php_namespace: ::std::option::Option<std::string::String>,
/// Use this option to change the namespace of php generated metadata classes.
/// Default is empty. When this option is empty, the proto file name will be
/// used for determining the namespace.
/// Default is empty. When this option is empty, the proto file name will be used
/// for determining the namespace.
#[prost(string, optional, tag="44")]
pub php_metadata_namespace: ::std::option::Option<std::string::String>,
/// Use this option to change the package of ruby generated classes. Default
@ -480,7 +478,7 @@ pub struct MessageOptions {
///
/// Implementations may choose not to generate the map_entry=true message, but
/// use a native map in the target language to hold the keys and values.
/// The reflection APIs in such implementations still need to work as
/// The reflection APIs in such implementions still need to work as
/// if the field is a repeated message field.
///
/// NOTE: Do not set the option in .proto files. Always use the maps syntax
@ -750,7 +748,7 @@ pub struct SourceCodeInfo {
/// beginning of the "extend" block and is shared by all extensions within
/// the block.
/// - Just because a location's span is a subset of some other location's span
/// does not mean that it is a descendant. For example, a "group" defines
/// does not mean that it is a descendent. For example, a "group" defines
/// both a type and a field in a single declaration. Thus, the locations
/// corresponding to the type and field and their components will overlap.
/// - Code which tries to interpret locations should probably be designed to
@ -1368,7 +1366,7 @@ pub struct Mixin {
/// if (duration.seconds < 0 && duration.nanos > 0) {
/// duration.seconds += 1;
/// duration.nanos -= 1000000000;
/// } else if (duration.seconds > 0 && duration.nanos < 0) {
/// } else if (durations.seconds > 0 && duration.nanos < 0) {
/// duration.seconds -= 1;
/// duration.nanos += 1000000000;
/// }
@ -1621,7 +1619,7 @@ pub struct Duration {
///
/// The implementation of any API method which has a FieldMask type field in the
/// request should verify the included field paths, and return an
/// `INVALID_ARGUMENT` error if any path is unmappable.
/// `INVALID_ARGUMENT` error if any path is duplicated or unmappable.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct FieldMask {
/// The set of field mask paths.
@ -1770,13 +1768,11 @@ pub enum NullValue {
/// 01:30 UTC on January 15, 2017.
///
/// In JavaScript, one can convert a Date object to this format using the
/// standard
/// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
/// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
/// method. In Python, a standard `datetime.datetime` object can be converted
/// to this format using
/// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
/// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
/// the Joda Time's [`ISODateTimeFormat.dateTime()`](
/// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
/// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
/// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
/// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
/// ) to obtain a formatter capable of generating timestamps in this format.
///

View File

@ -17,14 +17,3 @@ flate2 = "1.0"
prost-build = { path = "../prost-build" }
tar = "0.4"
tempfile = "3"
[dev-dependencies]
criterion = "0.3"
[lib]
# https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options
bench = false
[[bench]]
name = "dataset"
harness = false

View File

@ -1,109 +0,0 @@
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use criterion::{criterion_group, criterion_main, Criterion};
use prost::Message;
use protobuf::benchmarks::{
dataset, google_message3::GoogleMessage3, google_message4::GoogleMessage4, proto2, proto3,
BenchmarkDataset,
};
fn load_dataset(dataset: &Path) -> Result<BenchmarkDataset, Box<dyn Error>> {
let mut f = File::open(dataset)?;
let mut buf = Vec::new();
f.read_to_end(&mut buf)?;
Ok(BenchmarkDataset::decode(&*buf)?)
}
fn benchmark_dataset<M>(criterion: &mut Criterion, name: &str, dataset: &'static Path)
where
M: prost::Message + Default + 'static,
{
criterion.bench_function(&format!("dataset/{}/merge", name), move |b| {
let dataset = load_dataset(dataset).unwrap();
let mut message = M::default();
b.iter(|| {
for buf in &dataset.payload {
message.clear();
message.merge(buf.as_slice()).unwrap();
criterion::black_box(&message);
}
});
});
criterion.bench_function(&format!("dataset/{}/encode", name), move |b| {
let messages = load_dataset(dataset)
.unwrap()
.payload
.iter()
.map(Vec::as_slice)
.map(M::decode)
.collect::<Result<Vec<_>, _>>()
.unwrap();
let mut buf = Vec::with_capacity(messages.iter().map(M::encoded_len).sum::<usize>());
b.iter(|| {
buf.clear();
for message in &messages {
message.encode(&mut buf).unwrap();
}
criterion::black_box(&buf);
});
});
criterion.bench_function(&format!("dataset/{}/encoded_len", name), move |b| {
let messages = load_dataset(dataset)
.unwrap()
.payload
.iter()
.map(Vec::as_slice)
.map(M::decode)
.collect::<Result<Vec<_>, _>>()
.unwrap();
b.iter(|| {
let encoded_len = messages.iter().map(M::encoded_len).sum::<usize>();
criterion::black_box(encoded_len)
});
});
}
macro_rules! dataset {
($name: ident, $ty: ty) => {
fn $name(criterion: &mut Criterion) {
benchmark_dataset::<$ty>(criterion, stringify!($name), dataset::$name());
}
};
}
dataset!(google_message1_proto2, proto2::GoogleMessage1);
dataset!(google_message1_proto3, proto3::GoogleMessage1);
dataset!(google_message2, proto2::GoogleMessage2);
dataset!(google_message3_1, GoogleMessage3);
dataset!(google_message3_2, GoogleMessage3);
dataset!(google_message3_3, GoogleMessage3);
dataset!(google_message3_4, GoogleMessage3);
dataset!(google_message3_5, GoogleMessage3);
dataset!(google_message4, GoogleMessage4);
criterion_group!(
dataset,
google_message1_proto2,
google_message1_proto3,
google_message2,
);
criterion_group! {
name = slow;
config = Criterion::default().sample_size(10);
targets = google_message3_2, google_message3_4, google_message3_3
}
criterion_group! {
name = extra_slow;
config = Criterion::default().sample_size(3);
targets = google_message3_1, google_message3_5, google_message4
}
criterion_main!(dataset, slow, extra_slow);

View File

@ -12,7 +12,7 @@ use curl::easy::Easy;
use flate2::bufread::GzDecoder;
use tar::Archive;
const VERSION: &'static str = "3.11.2";
const VERSION: &'static str = "3.7.1";
static TEST_PROTOS: &[&str] = &[
"test_messages_proto2.proto",
@ -107,7 +107,6 @@ fn download_tarball(url: &str, out_dir: &Path) {
let mut data = Vec::new();
let mut handle = Easy::new();
// Download the tarball.
handle.url(url).expect("failed to configure tarball URL");
handle
.follow_location(true)
@ -123,7 +122,6 @@ fn download_tarball(url: &str, out_dir: &Path) {
transfer.perform().expect("failed to download tarball");
}
// Unpack the tarball.
Archive::new(GzDecoder::new(Cursor::new(data)))
.unpack(out_dir)
.expect("failed to unpack tarball");
@ -138,58 +136,50 @@ fn download_protobuf(out_dir: &Path) -> PathBuf {
),
out_dir,
);
let src_dir = out_dir.join(format!("protobuf-{}", VERSION));
// Apply patches.
let mut patch_src = env::current_dir().expect("failed to get current working directory");
patch_src.push("src");
patch_src.push("fix-conformance_test_runner-cmake-build.patch");
let rc = Command::new("patch")
.arg("-p1")
.arg("-i")
.arg(patch_src)
.current_dir(&src_dir)
.status()
.expect("failed to apply patch");
assert!(rc.success(), "protobuf patch failed");
src_dir
out_dir.join(format!("protobuf-{}", VERSION))
}
fn install_conformance_test_runner(src_dir: &Path, prefix_dir: &Path) {
#[cfg(not(windows))]
{
// Build and install protoc, the protobuf libraries, and the conformance test runner.
let rc = Command::new("cmake")
.arg("-GNinja")
.arg("cmake/")
.arg("-DCMAKE_BUILD_TYPE=DEBUG")
.arg(&format!("-DCMAKE_INSTALL_PREFIX={}", prefix_dir.display()))
.arg("-Dprotobuf_BUILD_CONFORMANCE=ON")
.arg("-Dprotobuf_BUILD_TESTS=OFF")
let rc = Command::new("./autogen.sh")
.current_dir(&src_dir)
.status()
.expect("failed to execute CMake");
assert!(rc.success(), "protobuf CMake failed");
.expect("failed to execute autogen.sh");
assert!(rc.success(), "protobuf autogen.sh failed");
let num_jobs = env::var("NUM_JOBS").expect("NUM_JOBS environment variable not set");
let rc = Command::new("ninja")
let rc = Command::new("./configure")
.arg("--disable-shared")
.arg("--prefix")
.arg(&prefix_dir)
.current_dir(&src_dir)
.status()
.expect("failed to execute configure");
assert!(rc.success(), "failed to configure protobuf");
let rc = Command::new("make")
.arg("-j")
.arg(&num_jobs)
.arg("install")
.current_dir(&src_dir)
.status()
.expect("failed to execute ninja protobuf");
.expect("failed to execute make protobuf");
assert!(rc.success(), "failed to make protobuf");
// Install the conformance-test-runner binary, since it isn't done automatically.
fs::rename(
src_dir.join("conformance_test_runner"),
prefix_dir.join("bin").join("conformance-test-runner"),
)
.expect("failed to move conformance-test-runner");
// Workaround for protocolbuffers/protobuf#6210.
fs::create_dir(src_dir.join("conformance").join("google-protobuf")).unwrap();
let rc = Command::new("make")
.arg("-j")
.arg(&num_jobs)
.arg("install")
.current_dir(src_dir.join("conformance"))
.status()
.expect("failed to execute make conformance");
assert!(rc.success(), "failed to make conformance");
}
}

View File

@ -1,41 +0,0 @@
From 104a483fbf3b87d42b0c3381049c72ab45d0f630 Mon Sep 17 00:00:00 2001
From: Dan Burkert <dan@danburkert.com>
Date: Sat, 11 Jan 2020 13:44:02 -0800
Subject: [PATCH] Fix conformance_test_runner CMake build
Makes the conformance_test_runner declared sources in
cmake/conformance.cmake match the corresponding sources in
conformance/Makefile.am, which allows the test runner to build
successfully with CMake.
---
cmake/conformance.cmake | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/cmake/conformance.cmake b/cmake/conformance.cmake
index 82b4cf580..7be713d33 100644
--- a/cmake/conformance.cmake
+++ b/cmake/conformance.cmake
@@ -19,14 +19,17 @@ add_custom_command(
)
add_executable(conformance_test_runner
- ${protobuf_source_dir}/conformance/conformance.pb.cc
+ ${protobuf_source_dir}/conformance/conformance_test.h
${protobuf_source_dir}/conformance/conformance_test.cc
- ${protobuf_source_dir}/conformance/binary_json_conformance_main.cc
- ${protobuf_source_dir}/conformance/binary_json_conformance_suite.cc
+ ${protobuf_source_dir}/conformance/conformance_test_main.cc
${protobuf_source_dir}/conformance/binary_json_conformance_suite.h
+ ${protobuf_source_dir}/conformance/binary_json_conformance_suite.cc
+ ${protobuf_source_dir}/conformance/text_format_conformance_suite.h
+ ${protobuf_source_dir}/conformance/text_format_conformance_suite.cc
${protobuf_source_dir}/conformance/conformance_test_runner.cc
${protobuf_source_dir}/conformance/third_party/jsoncpp/json.h
${protobuf_source_dir}/conformance/third_party/jsoncpp/jsoncpp.cpp
+ ${protobuf_source_dir}/conformance/conformance.pb.cc
${protobuf_source_dir}/src/google/protobuf/test_messages_proto3.pb.cc
${protobuf_source_dir}/src/google/protobuf/test_messages_proto2.pb.cc
)
--
2.21.1

View File

@ -1,71 +1,47 @@
pub mod benchmarks {
include!(concat!(env!("OUT_DIR"), "/benchmarks.rs"));
pub mod dataset {
use std::path::Path;
use std::path::Path;
pub fn google_message1_proto2() -> &'static Path {
pub fn datasets() -> Vec<&'static Path> {
vec![
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message1_proto2.pb"
))
}
pub fn google_message1_proto3() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message1_proto3.pb"
))
}
pub fn google_message2() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message2.pb"
))
}
pub fn google_message3_1() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message3_1.pb"
))
}
pub fn google_message3_2() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message3_2.pb"
))
}
pub fn google_message3_3() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message3_3.pb"
))
}
pub fn google_message3_4() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message3_4.pb"
))
}
pub fn google_message3_5() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message3_5.pb"
))
}
pub fn google_message4() -> &'static Path {
)),
Path::new(concat!(
env!("PROTOBUF"),
"/share/dataset.google_message4.pb"
))
}
)),
]
}
pub mod google_message3 {

View File

@ -1,26 +0,0 @@
#!/bin/bash
# Script which automates publishing a crates.io release of the prost crates.
set -ex
if [ "$#" -ne 0 ]
then
echo "Usage: $0"
exit 1
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
CRATES=( \
"prost-derive" \
"." \
"prost-types" \
"prost-build" \
)
for CRATE in "${CRATES[@]}"; do
pushd "$DIR/$CRATE"
cargo publish
popd
done

View File

@ -5,14 +5,12 @@
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::TryFrom;
use core::cmp::min;
use core::mem;
use core::str;
use core::u32;
use core::usize;
use ::bytes::{buf::ext::BufExt, Buf, BufMut};
use ::bytes::{Buf, BufMut};
use crate::DecodeError;
use crate::Message;
@ -26,6 +24,9 @@ where
{
// Safety notes:
//
// - bytes_mut is unsafe because it may return an uninitialized slice.
// The use here is safe because the slice is only written to, never read from.
//
// - advance_mut is unsafe because it could cause uninitialized memory to be
// advanced over. The use here is safe since each byte which is advanced over
// has been written to in the previous loop iteration.
@ -33,13 +34,13 @@ where
'outer: loop {
i = 0;
for byte in buf.bytes_mut() {
for byte in unsafe { buf.bytes_mut() } {
i += 1;
if value < 0x80 {
*byte = mem::MaybeUninit::new(value as u8);
*byte = value as u8;
break 'outer;
} else {
*byte = mem::MaybeUninit::new(((value & 0x7F) | 0x80) as u8);
*byte = ((value & 0x7F) | 0x80) as u8;
value >>= 7;
}
}
@ -282,12 +283,11 @@ pub enum WireType {
pub const MIN_TAG: u32 = 1;
pub const MAX_TAG: u32 = (1 << 29) - 1;
impl TryFrom<u64> for WireType {
type Error = DecodeError;
#[inline]
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
impl WireType {
// TODO: impl TryFrom<u64> when stable.
#[inline(always)]
pub fn try_from(val: u64) -> Result<WireType, DecodeError> {
match val {
0 => Ok(WireType::Varint),
1 => Ok(WireType::SixtyFourBit),
2 => Ok(WireType::LengthDelimited),
@ -296,7 +296,7 @@ impl TryFrom<u64> for WireType {
5 => Ok(WireType::ThirtyTwoBit),
_ => Err(DecodeError::new(format!(
"invalid wire type value: {}",
value
val
))),
}
}
@ -384,11 +384,10 @@ where
Ok(())
}
pub fn skip_field<B>(wire_type: WireType, tag: u32, buf: &mut B, ctx: DecodeContext) -> Result<(), DecodeError>
pub fn skip_field<B>(wire_type: WireType, tag: u32, buf: &mut B) -> Result<(), DecodeError>
where
B: Buf,
{
ctx.limit_reached()?;
let len = match wire_type {
WireType::Varint => decode_varint(buf).map(|_| 0)?,
WireType::ThirtyTwoBit => 4,
@ -403,7 +402,7 @@ where
}
break 0;
}
_ => skip_field(inner_wire_type, inner_tag, buf, ctx.enter_recursion())?,
_ => skip_field(inner_wire_type, inner_tag, buf)?,
}
},
WireType::EndGroup => return Err(DecodeError::new("unexpected end group tag")),
@ -824,41 +823,11 @@ pub mod string {
where
B: Buf,
{
// ## Unsafety
//
// `string::merge` reuses `bytes::merge`, with an additional check of utf-8
// well-formedness. If the utf-8 is not well-formed, or if any other error occurs, then the
// string is cleared, so as to avoid leaking a string field with invalid data.
//
// This implementation uses the unsafe `String::as_mut_vec` method instead of the safe
// alternative of temporarily swapping an empty `String` into the field, because it results
// in up to 10% better performance on the protobuf message decoding benchmarks.
//
// It's required when using `String::as_mut_vec` that invalid utf-8 data not be leaked into
// the backing `String`. To enforce this, even in the event of a panic in `bytes::merge` or
// in the buf implementation, a drop guard is used.
unsafe {
struct DropGuard<'a>(&'a mut Vec<u8>);
impl<'a> Drop for DropGuard<'a> {
#[inline]
fn drop(&mut self) {
self.0.clear();
}
}
let drop_guard = DropGuard(value.as_mut_vec());
bytes::merge(wire_type, drop_guard.0, buf, ctx)?;
match str::from_utf8(drop_guard.0) {
Ok(_) => {
// Success; do not clear the bytes.
mem::forget(drop_guard);
Ok(())
}
Err(_) => Err(DecodeError::new(
"invalid string value: data is not UTF-8 encoded",
)),
}
}
let mut value_bytes = mem::replace(value, String::new()).into_bytes();
bytes::merge(wire_type, &mut value_bytes, buf, ctx)?;
*value = String::from_utf8(value_bytes)
.map_err(|_| DecodeError::new("invalid string value: data is not UTF-8 encoded"))?;
Ok(())
}
length_delimited!(String);
@ -891,16 +860,6 @@ pub mod bytes {
return Err(DecodeError::new("buffer underflow"));
}
let len = len as usize;
// Clear the existing value. This follows from the following rule in the encoding guide[1]:
//
// > Normally, an encoded message would never have more than one instance of a non-repeated
// > field. However, parsers are expected to handle the case in which they do. For numeric
// > types and strings, if the same field appears multiple times, the parser accepts the
// > last value it sees.
//
// [1]: https://developers.google.com/protocol-buffers/docs/encoding#optional
value.clear();
value.reserve(len);
value.put(buf.take(len));
Ok(())
@ -1222,7 +1181,7 @@ macro_rules! map {
match tag {
1 => key_merge(wire_type, key, buf, ctx),
2 => val_merge(wire_type, val, buf, ctx),
_ => skip_field(wire_type, tag, buf, ctx),
_ => skip_field(wire_type, tag, buf),
}
},
)?;
@ -1275,6 +1234,9 @@ pub mod hash_map {
}
pub mod btree_map {
#[cfg(feature = "std")]
use std::collections::BTreeMap;
#[cfg(not(feature = "std"))]
use alloc::collections::BTreeMap;
map!(BTreeMap);
}
@ -1296,7 +1258,7 @@ mod test {
tag: u32,
wire_type: WireType,
encode: fn(u32, &B, &mut BytesMut),
merge: fn(WireType, &mut T, &mut Bytes, DecodeContext) -> Result<(), DecodeError>,
merge: fn(WireType, &mut T, &mut Cursor<Bytes>, DecodeContext) -> Result<(), DecodeError>,
encoded_len: fn(u32, &B) -> usize,
) -> TestResult
where
@ -1312,7 +1274,7 @@ mod test {
let mut buf = BytesMut::with_capacity(expected_len);
encode(tag, value.borrow(), &mut buf);
let mut buf = buf.freeze();
let mut buf = buf.freeze().to_bytes();
if buf.remaining() != expected_len {
return TestResult::error(format!(
@ -1400,7 +1362,7 @@ mod test {
T: Debug + Default + PartialEq + Borrow<B>,
B: ?Sized,
E: FnOnce(u32, &B, &mut BytesMut),
M: FnMut(WireType, &mut T, &mut Bytes, DecodeContext) -> Result<(), DecodeError>,
M: FnMut(WireType, &mut T, &mut Cursor<Bytes>, DecodeContext) -> Result<(), DecodeError>,
L: FnOnce(u32, &B) -> usize,
{
if tag > MAX_TAG || tag < MIN_TAG {
@ -1461,10 +1423,9 @@ mod test {
}
#[test]
fn string_merge_invalid_utf8() {
fn string_merge_failure() {
let mut s = String::new();
let mut buf = Cursor::new(b"\x02\x80\x80");
let mut buf = Cursor::new(b"\x80\x80");
let r = string::merge(
WireType::LengthDelimited,
&mut s,
@ -1477,7 +1438,7 @@ mod test {
#[test]
fn varint() {
fn check(value: u64, mut encoded: &[u8]) {
fn check(value: u64, encoded: &[u8]) {
// Small buffer.
let mut buf = Vec::with_capacity(1);
encode_varint(value, &mut buf);
@ -1490,11 +1451,11 @@ mod test {
assert_eq!(encoded_len_varint(value), encoded.len());
let roundtrip_value = decode_varint(&mut encoded.clone()).expect("decoding failed");
let roundtrip_value = decode_varint(&mut encoded).expect("decoding failed");
assert_eq!(value, roundtrip_value);
println!("encoding {:?}", encoded);
let roundtrip_value = decode_varint_slow(&mut encoded).expect("slow decoding failed");
let roundtrip_value =
decode_varint_slow(&mut encoded).expect("slow decoding failed");
assert_eq!(value, roundtrip_value);
}

View File

@ -58,7 +58,11 @@ impl fmt::Display for DecodeError {
}
#[cfg(feature = "std")]
impl error::Error for DecodeError {}
impl error::Error for DecodeError {
fn description(&self) -> &str {
&self.description
}
}
#[cfg(feature = "std")]
impl From<DecodeError> for io::Error {
@ -96,20 +100,29 @@ impl EncodeError {
pub fn remaining(&self) -> usize {
self.remaining
}
fn description(&self) -> &str {
"failed to encode Protobuf message: insufficient buffer capacity"
}
}
impl fmt::Display for EncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(EncodeError::description(self))?;
write!(
f,
"failed to encode Protobuf messsage; insufficient buffer capacity (required: {}, remaining: {})",
" (required: {}, remaining: {})",
self.required, self.remaining
)
}
}
#[cfg(feature = "std")]
impl error::Error for EncodeError {}
impl error::Error for EncodeError {
fn description(&self) -> &str {
EncodeError::description(self)
}
}
#[cfg(feature = "std")]
impl From<EncodeError> for io::Error {

View File

@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/prost/0.6.1")]
#![doc(html_root_url = "https://docs.rs/prost/0.5.0")]
#![cfg_attr(not(feature = "std"), no_std)]
@ -67,11 +67,11 @@ pub fn length_delimiter_len(length: usize) -> usize {
/// input is required to decode the full delimiter.
/// * If the supplied buffer contains more than 10 bytes, then the buffer contains an invalid
/// delimiter, and typically the buffer should be considered corrupt.
pub fn decode_length_delimiter<B>(mut buf: B) -> Result<usize, DecodeError>
pub fn decode_length_delimiter<B>(buf: &mut B) -> Result<usize, DecodeError>
where
B: Buf,
{
let length = decode_varint(&mut buf)?;
let length = decode_varint(buf)?;
if length > usize::max_value() as u64 {
return Err(DecodeError::new(
"length delimiter exceeds maximum usize value",
@ -90,7 +90,4 @@ where
extern crate prost_derive;
#[cfg(feature = "prost-derive")]
#[doc(hidden)]
pub use bytes;
#[cfg(feature = "prost-derive")]
#[doc(hidden)]
pub use prost_derive::*;

View File

@ -2,11 +2,9 @@ use alloc::boxed::Box;
use core::fmt::Debug;
use core::usize;
use bytes::{Buf, BufMut};
use ::bytes::{Buf, BufMut};
use crate::encoding::{
decode_key, encode_varint, encoded_len_varint, message, DecodeContext, WireType,
};
use crate::encoding::*;
use crate::DecodeError;
use crate::EncodeError;
@ -81,13 +79,13 @@ pub trait Message: Debug + Send + Sync {
/// Decodes an instance of the message from a buffer.
///
/// The entire buffer will be consumed.
fn decode<B>(mut buf: B) -> Result<Self, DecodeError>
fn decode<B>(buf: B) -> Result<Self, DecodeError>
where
B: Buf,
Self: Default,
{
let mut message = Self::default();
Self::merge(&mut message, &mut buf).map(|_| message)
Self::merge(&mut message, buf).map(|_| message)
}
/// Decodes a length-delimited instance of the message from the buffer.

View File

@ -10,13 +10,9 @@ use alloc::vec::Vec;
use ::bytes::{Buf, BufMut};
use crate::{
encoding::{
bool, bytes, double, float, int32, int64, skip_field, string, uint32, uint64,
DecodeContext, WireType,
},
DecodeError, Message,
};
use crate::encoding::*;
use crate::DecodeError;
use crate::Message;
/// `google.protobuf.BoolValue`
impl Message for bool {
@ -41,7 +37,7 @@ impl Message for bool {
if tag == 1 {
bool::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -79,7 +75,7 @@ impl Message for u32 {
if tag == 1 {
uint32::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -117,7 +113,7 @@ impl Message for u64 {
if tag == 1 {
uint64::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -155,7 +151,7 @@ impl Message for i32 {
if tag == 1 {
int32::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -193,7 +189,7 @@ impl Message for i64 {
if tag == 1 {
int64::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -231,7 +227,7 @@ impl Message for f32 {
if tag == 1 {
float::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -269,7 +265,7 @@ impl Message for f64 {
if tag == 1 {
double::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -307,7 +303,7 @@ impl Message for String {
if tag == 1 {
string::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -345,7 +341,7 @@ impl Message for Vec<u8> {
if tag == 1 {
bytes::merge(wire_type, self, buf, ctx)
} else {
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
}
fn encoded_len(&self) -> usize {
@ -372,12 +368,12 @@ impl Message for () {
tag: u32,
wire_type: WireType,
buf: &mut B,
ctx: DecodeContext,
_ctx: DecodeContext,
) -> Result<(), DecodeError>
where
B: Buf,
{
skip_field(wire_type, tag, buf, ctx)
skip_field(wire_type, tag, buf)
}
fn encoded_len(&self) -> usize {
0

View File

@ -16,7 +16,7 @@ default = ["edition-2015"]
edition-2015 = []
[dependencies]
bytes = "0.5"
bytes = "0.4.7"
cfg-if = "0.1"
prost = { path = ".." }
prost-types = { path = "../prost-types" }
@ -29,6 +29,6 @@ tempfile = "3"
[build-dependencies]
cfg-if = "0.1"
env_logger = { version = "0.7", default-features = false }
env_logger = { version = "0.6", default-features = false }
prost-build = { path = "../prost-build" }
protobuf = { path = "../protobuf" }

View File

@ -11,7 +11,7 @@ build = "src/build.rs"
doctest = false
[dependencies]
bytes = "0.5"
bytes = "0.4.7"
cfg-if = "0.1"
prost = { path = ".." }
prost-types = { path = "../prost-types" }
@ -24,6 +24,6 @@ tempfile = "3"
[build-dependencies]
cfg-if = "0.1"
env_logger = { version = "0.7", default-features = false }
env_logger = { version = "0.6", default-features = false }
prost-build = { path = "../prost-build" }
protobuf = { path = "../protobuf" }

View File

@ -88,12 +88,6 @@ fn main() {
)
.unwrap();
// Check that attempting to compile a .proto without a package declaration results in an error.
config
.compile_protos(&[src.join("no_package.proto")], includes)
.err()
.unwrap();
let out_dir =
&PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR environment variable not set"))
.join("extern_paths");

View File

@ -145,7 +145,7 @@ where
);
}
let roundtrip = match M::decode(&*buf1) {
let roundtrip = match M::decode(&buf1) {
Ok(roundtrip) => roundtrip,
Err(error) => return RoundtripResult::Error(error.into()),
};
@ -180,7 +180,6 @@ where
msg.encode(&mut buf).unwrap();
assert_eq!(expected_len, buf.len());
let mut buf = &*buf;
let roundtrip = M::decode(&mut buf).unwrap();
if buf.has_remaining() {
@ -355,7 +354,7 @@ mod tests {
let mut buf = Vec::new();
a.encode(&mut buf).unwrap();
A::decode(&*buf).map(|_| ())
A::decode(buf).map(|_| ())
}
assert!(build_and_roundtrip(100).is_ok());
@ -378,7 +377,7 @@ mod tests {
let mut buf = Vec::new();
a.encode(&mut buf).unwrap();
A::decode(&*buf).map(|_| ())
A::decode(buf).map(|_| ())
}
assert!(build_and_roundtrip(99).is_ok());
@ -401,7 +400,7 @@ mod tests {
let mut buf = Vec::new();
a.encode(&mut buf).unwrap();
NestedGroup2::decode(&*buf).map(|_| ())
NestedGroup2::decode(buf).map(|_| ())
}
assert!(build_and_roundtrip(50).is_ok());
@ -422,7 +421,7 @@ mod tests {
let mut buf = Vec::new();
c.encode(&mut buf).unwrap();
C::decode(&*buf).map(|_| ())
C::decode(buf).map(|_| ())
}
assert!(build_and_roundtrip(100).is_ok());
@ -443,7 +442,7 @@ mod tests {
let mut buf = Vec::new();
d.encode(&mut buf).unwrap();
D::decode(&*buf).map(|_| ())
D::decode(buf).map(|_| ())
}
assert!(build_and_roundtrip(50).is_ok());
@ -462,16 +461,6 @@ mod tests {
};
}
#[test]
fn test_267_regression() {
// Checks that skip_field will error appropriately when given a big stack of StartGroup
// tags.
//
// https://github.com/danburkert/prost/issues/267
let buf = vec![b'C'; 1 << 20];
<() as Message>::decode(&buf[..]).err().unwrap();
}
#[test]
fn test_default_enum() {
let msg = default_enum_value::Test::default();

View File

@ -1 +0,0 @@
syntax = "proto3";