diff options
author | David LeGare <legare@google.com> | 2022-03-07 14:40:51 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-03-07 14:40:51 +0000 |
commit | 7786b27d4cbe2fd06ecddd656dd1c65b5515e3c1 (patch) | |
tree | e5729062dc903dc271e2bfdc1803bcd03affbeb3 | |
parent | a4237418eefa2aa10beb6cade874ba8d12c8d853 (diff) | |
parent | 793d84b7b9add8be0de7846184d4f21c7fa7c17e (diff) | |
download | protobuf-7786b27d4cbe2fd06ecddd656dd1c65b5515e3c1.tar.gz |
Update protobuf to 2.27.1 am: 793d84b7b9
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/protobuf/+/2004797
Change-Id: Iee787b68100f8a15e7b07f4c80b99f42cb2ad5e2
47 files changed, 751 insertions, 397 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 051cfa6..ca74a42 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "d65abd3c6cee1dacef1448146b488ee168492a7d" - } -} + "sha1": "ec31ce829473039ac598ca6fdcb245cbd6fa82ba" + }, + "path_in_vcs": "protobuf" +}
\ No newline at end of file @@ -30,7 +30,7 @@ rust_library { host_supported: true, crate_name: "protobuf", cargo_env_compat: true, - cargo_pkg_version: "2.25.1", + cargo_pkg_version: "2.27.1", srcs: [ "src/lib.rs", ":copy_protobuf_build_out", @@ -12,19 +12,23 @@ [package] edition = "2018" name = "protobuf" -version = "2.25.1" +version = "2.27.1" authors = ["Stepan Koltsov <stepan.koltsov@gmail.com>"] -description = "Rust implementation of Google protocol buffers\n" +description = """ +Rust implementation of Google protocol buffers +""" homepage = "https://github.com/stepancheg/rust-protobuf/" documentation = "https://github.com/stepancheg/rust-protobuf/blob/master/README.md" license = "MIT" repository = "https://github.com/stepancheg/rust-protobuf/" + [package.metadata.docs.rs] all-features = true [lib] doctest = false bench = false + [dependencies.bytes] version = "1.0" optional = true @@ -40,4 +44,7 @@ optional = true [features] with-bytes = ["bytes"] -with-serde = ["serde", "serde_derive"] +with-serde = [ + "serde", + "serde_derive", +] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 058e8f1..c1be2f7 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,7 +1,7 @@ [package] name = "protobuf" -version = "2.25.1" +version = "2.27.1" authors = ["Stepan Koltsov <stepan.koltsov@gmail.com>"] edition = "2018" license = "MIT" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/protobuf/protobuf-2.25.1.crate" + value: "https://static.crates.io/crates/protobuf/protobuf-2.27.1.crate" } - version: "2.25.1" + version: "2.27.1" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 9 - day: 22 + year: 2022 + month: 3 + day: 1 } } @@ -1,6 +1,95 @@ -## How to develop rust-protobuf itself +<!-- cargo-sync-readme start --> -`cargo test --all` to build everything. +# Library to read and write protocol buffers data -If code generator is changed, code needs to be regenerated, see -`regenerate.sh`. +# Version 2 is stable + +Currently developed branch of rust-protobuf [is 3](https://docs.rs/protobuf/%3E=3.0.0-alpha). +It has the same spirit as version 2, but contains numerous improvements like: +* runtime reflection for mutability, not just for access +* protobuf text format and JSON parsing (which rely on reflection) +* dynamic message support: work with protobuf data without generating code from schema + +Stable version of rust-protobuf will be supported until version 3 released. + +[Tracking issue for version 3](https://github.com/stepancheg/rust-protobuf/issues/518). + +# How to generate rust code + +There are several ways to generate rust code from `.proto` files + +## Invoke `protoc` programmatically with protoc-rust crate (recommended) + +Have a look at readme in [protoc-rust crate](https://docs.rs/protoc-rust/=2). + +## Use pure rust protobuf parser and code generator + +Readme should be in +[protobuf-codegen-pure crate](https://docs.rs/protobuf-codegen-pure/=2). + +## Use protoc-gen-rust plugin + +Readme is [here](https://docs.rs/protobuf-codegen/=2). + +## Generated code + +Have a look at generated files (for current development version), +used internally in rust-protobuf: + +* [descriptor.rs](https://github.com/stepancheg/rust-protobuf/blob/master/protobuf/src/descriptor.rs) + for [descriptor.proto](https://github.com/stepancheg/rust-protobuf/blob/master/protoc-bin-vendored/include/google/protobuf/descriptor.proto) + (that is part of Google protobuf) + +# Copy on write + +Rust-protobuf can be used with [bytes crate](https://github.com/tokio-rs/bytes). + +To enable `Bytes` you need to: + +1. Enable `with-bytes` feature in rust-protobuf: + +```rust +[dependencies] +protobuf = { version = "~2.0", features = ["with-bytes"] } +``` + +2. Enable bytes option + +with `Customize` when codegen is invoked programmatically: + +```rust +protoc_rust::run(protoc_rust::Args { + ... + customize: Customize { + carllerche_bytes_for_bytes: Some(true), + carllerche_bytes_for_string: Some(true), + ..Default::default() + }, +}); +``` + +or in `.proto` file: + +```rust +import "rustproto.proto"; + +option (rustproto.carllerche_bytes_for_bytes_all) = true; +option (rustproto.carllerche_bytes_for_string_all) = true; +``` + +With these options enabled, fields of type `bytes` or `string` are +generated as `Bytes` or `Chars` respectively. When `CodedInputStream` is constructed +from `Bytes` object, fields of these types get subslices of original `Bytes` object, +instead of being allocated on heap. + +# Accompanying crates + +* [`protoc-rust`](https://docs.rs/protoc-rust/=2) + and [`protobuf-codegen-pure`](https://docs.rs/protobuf-codegen-pure/=2) + can be used to rust code from `.proto` crates. +* [`protobuf-codegen`](https://docs.rs/protobuf-codegen/=2) for `protoc-gen-rust` protoc plugin. +* [`protoc`](https://docs.rs/protoc/=2) crate can be used to invoke `protoc` programmatically. +* [`protoc-bin-vendored`](https://docs.rs/protoc-bin-vendored/=2) contains `protoc` command + packed into the crate. + +<!-- cargo-sync-readme end --> diff --git a/benches/coded_output_stream.rs b/benches/coded_output_stream.rs index 0f57a38..9edf95c 100644 --- a/benches/coded_output_stream.rs +++ b/benches/coded_output_stream.rs @@ -5,9 +5,10 @@ extern crate protobuf; extern crate test; -use self::test::Bencher; use protobuf::CodedOutputStream; +use self::test::Bencher; + #[inline] fn buffer_write_byte(os: &mut CodedOutputStream) { for i in 0..10 { diff --git a/out/version.rs b/out/version.rs index fd20f6c..18bbac5 100644 --- a/out/version.rs +++ b/out/version.rs @@ -1,7 +1,7 @@ /// protobuf crate version -pub const VERSION: &'static str = "2.25.1"; +pub const VERSION: &'static str = "2.27.1"; /// This symbol is used by codegen #[doc(hidden)] -pub const VERSION_IDENT: &'static str = "VERSION_2_25_1"; +pub const VERSION_IDENT: &'static str = "VERSION_2_27_1"; /// This symbol can be referenced to assert that proper version of crate is used -pub const VERSION_2_25_1: () = (); +pub const VERSION_2_27_1: () = (); diff --git a/regenerate.sh b/regenerate.sh index 672106e..0173496 100755 --- a/regenerate.sh +++ b/regenerate.sh @@ -1,6 +1,6 @@ #!/bin/sh -ex -cd $(dirname $0) +cd "$(dirname "$0")" die() { echo "$@" >&2 @@ -9,29 +9,35 @@ die() { protoc_ver=$(protoc --version) case "$protoc_ver" in - "libprotoc 3"*) ;; - *) - die "you need to use protobuf 3 to regenerate .rs from .proto" +"libprotoc 3"*) ;; +*) + die "you need to use protobuf 3 to regenerate .rs from .proto" ;; esac cargo build --manifest-path=../protobuf-codegen/Cargo.toml +cargo build --manifest-path=../protoc-bin-vendored/Cargo.toml --bin protoc-bin-which -where_am_i=$(cd ..; pwd) +PROTOC=$(cargo run --manifest-path=../protoc-bin-vendored/Cargo.toml --bin protoc-bin-which) + +where_am_i=$( + cd .. + pwd +) rm -rf tmp-generated mkdir tmp-generated -case `uname` in - Linux) - exe_suffix="" +case $(uname) in +Linux) + exe_suffix="" ;; - MSYS_NT*) - exe_suffix=".exe" +MSYS_NT*) + exe_suffix=".exe" ;; esac -protoc \ +"$PROTOC" \ --plugin=protoc-gen-rust="$where_am_i/target/debug/protoc-gen-rust$exe_suffix" \ --rust_out tmp-generated \ --rust_opt 'serde_derive=true inside_protobuf=true' \ @@ -45,13 +51,14 @@ mv tmp-generated/descriptor.rs tmp-generated/plugin.rs tmp-generated/rustproto.r mv tmp-generated/*.rs src/well_known_types/ ( cd src/well_known_types - exec > mod.rs + exec >mod.rs echo "// This file is generated. Do not edit" echo '//! Generated code for "well known types"' echo "//!" echo "//! [This document](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf) describes these types." mod_list() { + # shellcheck disable=SC2010 ls | grep -v mod.rs | sed -e 's,\.rs$,,' } @@ -59,7 +66,7 @@ mv tmp-generated/*.rs src/well_known_types/ mod_list | sed -e 's,^,mod ,; s,$,;,' echo - mod_list | while read mod; do + mod_list | while read -r mod; do echo "pub use self::$mod::*;" done ) diff --git a/src/buf_read_iter.rs b/src/buf_read_iter.rs index 37bc353..ff1fce2 100644 --- a/src/buf_read_iter.rs +++ b/src/buf_read_iter.rs @@ -3,6 +3,7 @@ use std::io::BufRead; use std::io::BufReader; use std::io::Read; use std::mem; +use std::mem::MaybeUninit; use std::u64; #[cfg(feature = "bytes")] @@ -14,8 +15,11 @@ use bytes::Bytes; #[cfg(feature = "bytes")] use bytes::BytesMut; +use crate::buf_read_or_reader::BufReadOrReader; use crate::coded_input_stream::READ_RAW_BYTES_MAX_ALLOC; use crate::error::WireError; +use crate::misc::maybe_uninit_write_slice; +use crate::misc::vec_spare_capacity_mut; use crate::ProtobufError; use crate::ProtobufResult; @@ -29,8 +33,7 @@ const NO_LIMIT: u64 = u64::MAX; /// Hold all possible combinations of input source enum InputSource<'a> { - BufRead(&'a mut dyn BufRead), - Read(BufReader<&'a mut dyn Read>), + Read(BufReadOrReader<'a>), Slice(&'a [u8]), #[cfg(feature = "bytes")] Bytes(&'a Bytes), @@ -50,7 +53,7 @@ enum InputSource<'a> { /// It is important for `CodedInputStream` performance that small reads /// (e. g. 4 bytes reads) do not involve virtual calls or switches. /// This is achievable with `BufReadIter`. -pub struct BufReadIter<'a> { +pub(crate) struct BufReadIter<'a> { input_source: InputSource<'a>, buf: &'a [u8], pos_within_buf: usize, @@ -62,22 +65,19 @@ pub struct BufReadIter<'a> { impl<'a> Drop for BufReadIter<'a> { fn drop(&mut self) { match self.input_source { - InputSource::BufRead(ref mut buf_read) => buf_read.consume(self.pos_within_buf), - InputSource::Read(_) => { - // Nothing to flush, because we own BufReader - } + InputSource::Read(ref mut buf_read) => buf_read.consume(self.pos_within_buf), _ => {} } } } impl<'ignore> BufReadIter<'ignore> { - pub fn from_read<'a>(read: &'a mut dyn Read) -> BufReadIter<'a> { + pub(crate) fn from_read<'a>(read: &'a mut dyn Read) -> BufReadIter<'a> { BufReadIter { - input_source: InputSource::Read(BufReader::with_capacity( + input_source: InputSource::Read(BufReadOrReader::BufReader(BufReader::with_capacity( INPUT_STREAM_BUFFER_SIZE, read, - )), + ))), buf: &[], pos_within_buf: 0, limit_within_buf: 0, @@ -86,9 +86,9 @@ impl<'ignore> BufReadIter<'ignore> { } } - pub fn from_buf_read<'a>(buf_read: &'a mut dyn BufRead) -> BufReadIter<'a> { + pub(crate) fn from_buf_read<'a>(buf_read: &'a mut dyn BufRead) -> BufReadIter<'a> { BufReadIter { - input_source: InputSource::BufRead(buf_read), + input_source: InputSource::Read(BufReadOrReader::BufRead(buf_read)), buf: &[], pos_within_buf: 0, limit_within_buf: 0, @@ -97,7 +97,7 @@ impl<'ignore> BufReadIter<'ignore> { } } - pub fn from_byte_slice<'a>(bytes: &'a [u8]) -> BufReadIter<'a> { + pub(crate) fn from_byte_slice<'a>(bytes: &'a [u8]) -> BufReadIter<'a> { BufReadIter { input_source: InputSource::Slice(bytes), buf: bytes, @@ -109,7 +109,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[cfg(feature = "bytes")] - pub fn from_bytes<'a>(bytes: &'a Bytes) -> BufReadIter<'a> { + pub(crate) fn from_bytes<'a>(bytes: &'a Bytes) -> BufReadIter<'a> { BufReadIter { input_source: InputSource::Bytes(bytes), buf: &bytes, @@ -128,7 +128,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline(always)] - pub fn pos(&self) -> u64 { + pub(crate) fn pos(&self) -> u64 { self.pos_of_buf_start + self.pos_within_buf as u64 } @@ -144,7 +144,7 @@ impl<'ignore> BufReadIter<'ignore> { self.assertions(); } - pub fn push_limit(&mut self, limit: u64) -> ProtobufResult<u64> { + pub(crate) fn push_limit(&mut self, limit: u64) -> ProtobufResult<u64> { let new_limit = match self.pos().checked_add(limit) { Some(new_limit) => new_limit, None => return Err(ProtobufError::WireError(WireError::Other)), @@ -162,7 +162,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline] - pub fn pop_limit(&mut self, limit: u64) { + pub(crate) fn pop_limit(&mut self, limit: u64) { assert!(limit >= self.limit); self.limit = limit; @@ -171,7 +171,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline] - pub fn remaining_in_buf(&self) -> &[u8] { + pub(crate) fn remaining_in_buf(&self) -> &[u8] { if USE_UNSAFE_FOR_SPEED { unsafe { &self @@ -184,12 +184,12 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline(always)] - pub fn remaining_in_buf_len(&self) -> usize { + pub(crate) fn remaining_in_buf_len(&self) -> usize { self.limit_within_buf - self.pos_within_buf } #[inline(always)] - pub fn bytes_until_limit(&self) -> u64 { + pub(crate) fn bytes_until_limit(&self) -> u64 { if self.limit == NO_LIMIT { NO_LIMIT } else { @@ -198,7 +198,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline(always)] - pub fn eof(&mut self) -> ProtobufResult<bool> { + pub(crate) fn eof(&mut self) -> ProtobufResult<bool> { if self.pos_within_buf == self.limit_within_buf { Ok(self.fill_buf()?.is_empty()) } else { @@ -207,7 +207,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline(always)] - pub fn read_byte(&mut self) -> ProtobufResult<u8> { + pub(crate) fn read_byte(&mut self) -> ProtobufResult<u8> { if self.pos_within_buf == self.limit_within_buf { self.do_fill_buf()?; if self.remaining_in_buf_len() == 0 { @@ -239,52 +239,8 @@ impl<'ignore> BufReadIter<'ignore> { Ok(len) } - /// Read exact number of bytes into `Vec`. - /// - /// `Vec` is cleared in the beginning. - pub fn read_exact_to_vec(&mut self, count: usize, target: &mut Vec<u8>) -> ProtobufResult<()> { - // TODO: also do some limits when reading from unlimited source - if count as u64 > self.bytes_until_limit() { - return Err(ProtobufError::WireError(WireError::TruncatedMessage)); - } - - target.clear(); - - if count >= READ_RAW_BYTES_MAX_ALLOC && count > target.capacity() { - // avoid calling `reserve` on buf with very large buffer: could be a malformed message - - target.reserve(READ_RAW_BYTES_MAX_ALLOC); - - while target.len() < count { - let need_to_read = count - target.len(); - if need_to_read <= target.len() { - target.reserve_exact(need_to_read); - } else { - target.reserve(1); - } - - let max = cmp::min(target.capacity() - target.len(), need_to_read); - let read = self.read_to_vec(target, max)?; - if read == 0 { - return Err(ProtobufError::WireError(WireError::TruncatedMessage)); - } - } - } else { - target.reserve_exact(count); - - unsafe { - self.read_exact(&mut target.get_unchecked_mut(..count))?; - target.set_len(count); - } - } - - debug_assert_eq!(count, target.len()); - - Ok(()) - } - #[cfg(feature = "bytes")] - pub fn read_exact_bytes(&mut self, len: usize) -> ProtobufResult<Bytes> { + pub(crate) fn read_exact_bytes(&mut self, len: usize) -> ProtobufResult<Bytes> { if let InputSource::Bytes(bytes) = self.input_source { let end = match self.pos_within_buf.checked_add(len) { Some(end) => end, @@ -318,13 +274,13 @@ impl<'ignore> BufReadIter<'ignore> { } #[cfg(feature = "bytes")] - unsafe fn uninit_slice_as_mut_slice(slice: &mut UninitSlice) -> &mut [u8] { + unsafe fn uninit_slice_as_mut_slice(slice: &mut UninitSlice) -> &mut [MaybeUninit<u8>] { use std::slice; - slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len()) + slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut MaybeUninit<u8>, slice.len()) } /// Returns 0 when EOF or limit reached. - pub fn read(&mut self, buf: &mut [u8]) -> ProtobufResult<usize> { + pub(crate) fn read(&mut self, buf: &mut [u8]) -> ProtobufResult<usize> { self.fill_buf()?; let rem = &self.buf[self.pos_within_buf..self.limit_within_buf]; @@ -335,14 +291,7 @@ impl<'ignore> BufReadIter<'ignore> { Ok(len) } - pub fn read_exact(&mut self, buf: &mut [u8]) -> ProtobufResult<()> { - if self.remaining_in_buf_len() >= buf.len() { - let buf_len = buf.len(); - buf.copy_from_slice(&self.buf[self.pos_within_buf..self.pos_within_buf + buf_len]); - self.pos_within_buf += buf_len; - return Ok(()); - } - + fn read_exact_slow(&mut self, buf: &mut [MaybeUninit<u8>]) -> ProtobufResult<()> { if self.bytes_until_limit() < buf.len() as u64 { return Err(ProtobufError::WireError(WireError::UnexpectedEof)); } @@ -356,11 +305,7 @@ impl<'ignore> BufReadIter<'ignore> { match self.input_source { InputSource::Read(ref mut buf_read) => { buf_read.consume(consume); - buf_read.read_exact(buf)?; - } - InputSource::BufRead(ref mut buf_read) => { - buf_read.consume(consume); - buf_read.read_exact(buf)?; + buf_read.read_exact_uninit(buf)?; } _ => { return Err(ProtobufError::WireError(WireError::UnexpectedEof)); @@ -374,6 +319,65 @@ impl<'ignore> BufReadIter<'ignore> { Ok(()) } + #[inline] + pub(crate) fn read_exact(&mut self, buf: &mut [MaybeUninit<u8>]) -> ProtobufResult<()> { + if self.remaining_in_buf_len() >= buf.len() { + let buf_len = buf.len(); + maybe_uninit_write_slice( + buf, + &self.buf[self.pos_within_buf..self.pos_within_buf + buf_len], + ); + self.pos_within_buf += buf_len; + return Ok(()); + } + + self.read_exact_slow(buf) + } + + /// Read exact number of bytes into `Vec`. + /// + /// `Vec` is cleared in the beginning. + pub fn read_exact_to_vec(&mut self, count: usize, target: &mut Vec<u8>) -> ProtobufResult<()> { + // TODO: also do some limits when reading from unlimited source + if count as u64 > self.bytes_until_limit() { + return Err(ProtobufError::WireError(WireError::TruncatedMessage)); + } + + target.clear(); + + if count >= READ_RAW_BYTES_MAX_ALLOC && count > target.capacity() { + // avoid calling `reserve` on buf with very large buffer: could be a malformed message + + target.reserve(READ_RAW_BYTES_MAX_ALLOC); + + while target.len() < count { + let need_to_read = count - target.len(); + if need_to_read <= target.len() { + target.reserve_exact(need_to_read); + } else { + target.reserve(1); + } + + let max = cmp::min(target.capacity() - target.len(), need_to_read); + let read = self.read_to_vec(target, max)?; + if read == 0 { + return Err(ProtobufError::WireError(WireError::TruncatedMessage)); + } + } + } else { + target.reserve_exact(count); + + unsafe { + self.read_exact(&mut vec_spare_capacity_mut(target)[..count])?; + target.set_len(count); + } + } + + debug_assert_eq!(count, target.len()); + + Ok(()) + } + fn do_fill_buf(&mut self) -> ProtobufResult<()> { debug_assert!(self.pos_within_buf == self.limit_within_buf); @@ -394,10 +398,6 @@ impl<'ignore> BufReadIter<'ignore> { buf_read.consume(consume); self.buf = unsafe { mem::transmute(buf_read.fill_buf()?) }; } - InputSource::BufRead(ref mut buf_read) => { - buf_read.consume(consume); - self.buf = unsafe { mem::transmute(buf_read.fill_buf()?) }; - } _ => { return Ok(()); } @@ -409,7 +409,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline(always)] - pub fn fill_buf(&mut self) -> ProtobufResult<&[u8]> { + pub(crate) fn fill_buf(&mut self) -> ProtobufResult<&[u8]> { if self.pos_within_buf == self.limit_within_buf { self.do_fill_buf()?; } @@ -425,7 +425,7 @@ impl<'ignore> BufReadIter<'ignore> { } #[inline(always)] - pub fn consume(&mut self, amt: usize) { + pub(crate) fn consume(&mut self, amt: usize) { assert!(amt <= self.limit_within_buf - self.pos_within_buf); self.pos_within_buf += amt; } @@ -433,9 +433,10 @@ impl<'ignore> BufReadIter<'ignore> { #[cfg(all(test, feature = "bytes"))] mod test_bytes { - use super::*; use std::io::Write; + use super::*; + fn make_long_string(len: usize) -> Vec<u8> { let mut s = Vec::new(); while s.len() < len { @@ -467,11 +468,12 @@ mod test_bytes { #[cfg(test)] mod test { - use super::*; use std::io; use std::io::BufRead; use std::io::Read; + use super::*; + #[test] fn eof_at_limit() { struct Read5ThenPanic { @@ -509,7 +511,12 @@ mod test { let _prev_limit = buf_read_iter.push_limit(5); buf_read_iter.read_byte().expect("read_byte"); buf_read_iter - .read_exact(&mut [1, 2, 3, 4]) + .read_exact(&mut [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]) .expect("read_exact"); assert!(buf_read_iter.eof().expect("eof")); } diff --git a/src/buf_read_or_reader.rs b/src/buf_read_or_reader.rs new file mode 100644 index 0000000..6a47c76 --- /dev/null +++ b/src/buf_read_or_reader.rs @@ -0,0 +1,85 @@ +//! `BufRead` pointer or `BufReader` owned. + +use std::cmp; +use std::io; +use std::io::BufRead; +use std::io::BufReader; +use std::io::Read; +use std::mem::MaybeUninit; + +use crate::misc::maybe_uninit_write_slice; + +/// Helper type to simplify `BufReadIter` implementation. +pub(crate) enum BufReadOrReader<'a> { + BufReader(BufReader<&'a mut dyn Read>), + BufRead(&'a mut dyn BufRead), +} + +impl<'a> Read for BufReadOrReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> { + match self { + BufReadOrReader::BufReader(r) => r.read(buf), + BufReadOrReader::BufRead(r) => r.read(buf), + } + } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, io::Error> { + match self { + BufReadOrReader::BufReader(r) => r.read_to_end(buf), + BufReadOrReader::BufRead(r) => r.read_to_end(buf), + } + } + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), io::Error> { + match self { + BufReadOrReader::BufReader(r) => r.read_exact(buf), + BufReadOrReader::BufRead(r) => r.read_exact(buf), + } + } +} + +impl<'a> BufReadOrReader<'a> { + /// Similar to `read_exact` but reads into `MaybeUninit`. + pub(crate) fn read_exact_uninit( + &mut self, + buf: &mut [MaybeUninit<u8>], + ) -> Result<(), io::Error> { + let mut pos = 0; + while pos != buf.len() { + let fill_buf = match self { + BufReadOrReader::BufReader(r) => r.fill_buf()?, + BufReadOrReader::BufRead(r) => r.fill_buf()?, + }; + if fill_buf.is_empty() { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "Unexpected end of file", + )); + } + let consume = cmp::min(fill_buf.len(), buf.len() - pos); + maybe_uninit_write_slice(&mut buf[pos..pos + consume], &fill_buf[..consume]); + match self { + BufReadOrReader::BufReader(r) => r.consume(consume), + BufReadOrReader::BufRead(r) => r.consume(consume), + } + pos += consume; + } + Ok(()) + } +} + +impl<'a> BufRead for BufReadOrReader<'a> { + fn fill_buf(&mut self) -> Result<&[u8], io::Error> { + match self { + BufReadOrReader::BufReader(r) => r.fill_buf(), + BufReadOrReader::BufRead(r) => r.fill_buf(), + } + } + + fn consume(&mut self, amt: usize) { + match self { + BufReadOrReader::BufReader(r) => r.consume(amt), + BufReadOrReader::BufRead(r) => r.consume(amt), + } + } +} diff --git a/src/coded_input_stream.rs b/src/coded_input_stream.rs index 52a13a6..a49563c 100644 --- a/src/coded_input_stream.rs +++ b/src/coded_input_stream.rs @@ -6,19 +6,21 @@ use std::io; use std::io::BufRead; use std::io::Read; use std::mem; +use std::mem::MaybeUninit; use std::slice; #[cfg(feature = "bytes")] -use crate::chars::Chars; -#[cfg(feature = "bytes")] use bytes::Bytes; use crate::buf_read_iter::BufReadIter; +#[cfg(feature = "bytes")] +use crate::chars::Chars; use crate::enums::ProtobufEnum; use crate::error::ProtobufError; use crate::error::ProtobufResult; use crate::error::WireError; use crate::message::Message; +use crate::misc::maybe_ununit_array_assume_init; use crate::unknown::UnknownValue; use crate::wire_format; use crate::zigzag::decode_zig_zag_32; @@ -105,12 +107,21 @@ impl<'a> CodedInputStream<'a> { } /// Read bytes into given `buf`. + #[inline] + fn read_exact_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> ProtobufResult<()> { + self.source.read_exact(buf) + } + + /// Read bytes into given `buf`. /// /// Return `0` on EOF. // TODO: overload with `Read::read` pub fn read(&mut self, buf: &mut [u8]) -> ProtobufResult<()> { - self.source.read_exact(buf)?; - Ok(()) + // SAFETY: same layout + let buf = unsafe { + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut MaybeUninit<u8>, buf.len()) + }; + self.read_exact_uninit(buf) } /// Read exact number of bytes as `Bytes` object. @@ -248,24 +259,20 @@ impl<'a> CodedInputStream<'a> { /// Read little-endian 32-bit integer pub fn read_raw_little_endian32(&mut self) -> ProtobufResult<u32> { - let mut r = 0u32; - let bytes: &mut [u8] = unsafe { - let p: *mut u8 = mem::transmute(&mut r); - slice::from_raw_parts_mut(p, mem::size_of::<u32>()) - }; - self.read(bytes)?; - Ok(r.to_le()) + let mut bytes = [MaybeUninit::uninit(); 4]; + self.read_exact_uninit(&mut bytes)?; + // SAFETY: `read_exact` guarantees that the buffer is filled. + let bytes = unsafe { maybe_ununit_array_assume_init(bytes) }; + Ok(u32::from_le_bytes(bytes)) } /// Read little-endian 64-bit integer pub fn read_raw_little_endian64(&mut self) -> ProtobufResult<u64> { - let mut r = 0u64; - let bytes: &mut [u8] = unsafe { - let p: *mut u8 = mem::transmute(&mut r); - slice::from_raw_parts_mut(p, mem::size_of::<u64>()) - }; - self.read(bytes)?; - Ok(r.to_le()) + let mut bytes = [MaybeUninit::uninit(); 8]; + self.read_exact_uninit(&mut bytes)?; + // SAFETY: `read_exact` guarantees that the buffer is filled. + let bytes = unsafe { maybe_ununit_array_assume_init(bytes) }; + Ok(u64::from_le_bytes(bytes)) } /// Read tag @@ -596,41 +603,7 @@ impl<'a> CodedInputStream<'a> { /// Read raw bytes into the supplied vector. The vector will be resized as needed and /// overwritten. pub fn read_raw_bytes_into(&mut self, count: u32, target: &mut Vec<u8>) -> ProtobufResult<()> { - if false { - // Master uses this version, but keep existing version for a while - // to avoid possible breakages. - return self.source.read_exact_to_vec(count as usize, target); - } - - let count = count as usize; - - // TODO: also do some limits when reading from unlimited source - if count as u64 > self.source.bytes_until_limit() { - return Err(ProtobufError::WireError(WireError::TruncatedMessage)); - } - - unsafe { - target.set_len(0); - } - - if count >= READ_RAW_BYTES_MAX_ALLOC { - // avoid calling `reserve` on buf with very large buffer: could be a malformed message - - let mut take = self.by_ref().take(count as u64); - take.read_to_end(target)?; - - if target.len() != count { - return Err(ProtobufError::WireError(WireError::TruncatedMessage)); - } - } else { - target.reserve(count); - unsafe { - target.set_len(count); - } - - self.source.read_exact(target)?; - } - Ok(()) + self.source.read_exact_to_vec(count as usize, target) } /// Read exact number of bytes @@ -795,13 +768,12 @@ mod test { use std::io::BufRead; use std::io::Read; + use super::CodedInputStream; + use super::READ_RAW_BYTES_MAX_ALLOC; use crate::error::ProtobufError; use crate::error::ProtobufResult; use crate::hex::decode_hex; - use super::CodedInputStream; - use super::READ_RAW_BYTES_MAX_ALLOC; - fn test_read_partial<F>(hex: &str, mut callback: F) where F: FnMut(&mut CodedInputStream), diff --git a/src/coded_output_stream.rs b/src/coded_output_stream.rs index bbfe228..2bbe0a3 100644 --- a/src/coded_output_stream.rs +++ b/src/coded_output_stream.rs @@ -1,17 +1,23 @@ -use crate::misc::remaining_capacity_as_slice_mut; -use crate::misc::remove_lifetime_mut; +use std::io; +use std::io::Write; +use std::mem; +use std::mem::MaybeUninit; +use std::ptr; +use std::slice; + +use crate::misc::maybe_uninit_write; +use crate::misc::maybe_uninit_write_slice; +use crate::misc::vec_spare_capacity_mut; use crate::varint; use crate::wire_format; use crate::zigzag::encode_zig_zag_32; use crate::zigzag::encode_zig_zag_64; use crate::Message; use crate::ProtobufEnum; +use crate::ProtobufError; use crate::ProtobufResult; use crate::UnknownFields; use crate::UnknownValueRef; -use std::io; -use std::io::Write; -use std::mem; /// Equal to the default buffer size of `BufWriter`, so when /// `CodedOutputStream` wraps `BufWriter`, it often skips double buffering. @@ -58,17 +64,27 @@ where Ok(v) } +/// Output buffer/writer for `CodedOutputStream`. enum OutputTarget<'a> { Write(&'a mut dyn Write, Vec<u8>), Vec(&'a mut Vec<u8>), + /// The buffer is passed as `&[u8]` to `CodedOutputStream` constructor + /// and immediately converted to `buffer` field of `CodedOutputStream`, + /// it is not needed to be stored here. + /// Lifetime parameter of `CodedOutputStream` guarantees the buffer is valid + /// during the lifetime of `CodedOutputStream`. Bytes, } /// Buffered write with handy utilities pub struct CodedOutputStream<'a> { target: OutputTarget<'a>, - // alias to buf from target - buffer: &'a mut [u8], + // Actual buffer is owned by `OutputTarget`, + // and here we alias the buffer so access to the buffer is branchless: + // access does not require switch by actual target type: `&[], `Vec`, `Write` etc. + // We don't access the actual buffer in `OutputTarget` except when + // we initialize `buffer` field here. + buffer: *mut [MaybeUninit<u8>], // within buffer position: usize, } @@ -81,15 +97,16 @@ impl<'a> CodedOutputStream<'a> { let buffer_len = OUTPUT_STREAM_BUFFER_SIZE; let mut buffer_storage = Vec::with_capacity(buffer_len); - unsafe { - buffer_storage.set_len(buffer_len); - } - let buffer = unsafe { remove_lifetime_mut(&mut buffer_storage as &mut [u8]) }; + // SAFETY: we are not using the `buffer_storage` + // except for initializing the `buffer` field. + // See `buffer` field documentation. + let buffer = vec_spare_capacity_mut(&mut buffer_storage); + let buffer: *mut [MaybeUninit<u8>] = buffer; CodedOutputStream { target: OutputTarget::Write(writer, buffer_storage), - buffer: buffer, + buffer, position: 0, } } @@ -98,9 +115,12 @@ impl<'a> CodedOutputStream<'a> { /// /// Attempt to write more than bytes capacity results in error. pub fn bytes(bytes: &'a mut [u8]) -> CodedOutputStream<'a> { + // SAFETY: it is safe to cast from &mut [u8] to &mut [MaybeUninit<u8>]. + let buffer = + ptr::slice_from_raw_parts_mut(bytes.as_mut_ptr() as *mut MaybeUninit<u8>, bytes.len()); CodedOutputStream { target: OutputTarget::Bytes, - buffer: bytes, + buffer, position: 0, } } @@ -110,9 +130,10 @@ impl<'a> CodedOutputStream<'a> { /// Caller should call `flush` at the end to guarantee vec contains /// all written data. pub fn vec(vec: &'a mut Vec<u8>) -> CodedOutputStream<'a> { + let buffer: *mut [MaybeUninit<u8>] = &mut []; CodedOutputStream { target: OutputTarget::Vec(vec), - buffer: &mut [], + buffer, position: 0, } } @@ -125,7 +146,7 @@ impl<'a> CodedOutputStream<'a> { pub fn check_eof(&self) { match self.target { OutputTarget::Bytes => { - assert_eq!(self.buffer.len() as u64, self.position as u64); + assert_eq!(self.buffer().len() as u64, self.position as u64); } OutputTarget::Write(..) | OutputTarget::Vec(..) => { panic!("must not be called with Writer or Vec"); @@ -133,10 +154,25 @@ impl<'a> CodedOutputStream<'a> { } } + #[inline(always)] + fn buffer(&self) -> &[MaybeUninit<u8>] { + // SAFETY: see the `buffer` field documentation about invariants. + unsafe { &*(self.buffer as *mut [MaybeUninit<u8>]) } + } + + #[inline(always)] + fn filled_buffer_impl<'s>(buffer: *mut [MaybeUninit<u8>], position: usize) -> &'s [u8] { + // SAFETY: this function is safe assuming `buffer` and `position` + // are `self.buffer` and `safe.position`: + // * `CodedOutputStream` has invariant that `position <= buffer.len()`. + // * `buffer` is filled up to `position`. + unsafe { slice::from_raw_parts_mut(buffer as *mut u8, position) } + } + fn refresh_buffer(&mut self) -> ProtobufResult<()> { match self.target { OutputTarget::Write(ref mut write, _) => { - write.write_all(&self.buffer[0..self.position as usize])?; + write.write_all(Self::filled_buffer_impl(self.buffer, self.position))?; self.position = 0; } OutputTarget::Vec(ref mut vec) => unsafe { @@ -144,11 +180,14 @@ impl<'a> CodedOutputStream<'a> { assert!(vec_len + self.position <= vec.capacity()); vec.set_len(vec_len + self.position); vec.reserve(1); - self.buffer = remove_lifetime_mut(remaining_capacity_as_slice_mut(vec)); + self.buffer = vec_spare_capacity_mut(vec); self.position = 0; }, OutputTarget::Bytes => { - panic!("refresh_buffer must not be called on CodedOutputStream create from slice"); + return Err(ProtobufError::IoError(io::Error::new( + io::ErrorKind::Other, + "given slice is too small to serialize the message", + ))); } } Ok(()) @@ -167,20 +206,22 @@ impl<'a> CodedOutputStream<'a> { /// Write a byte pub fn write_raw_byte(&mut self, byte: u8) -> ProtobufResult<()> { - if self.position as usize == self.buffer.len() { + if self.position as usize == self.buffer().len() { self.refresh_buffer()?; } - self.buffer[self.position as usize] = byte; + unsafe { maybe_uninit_write(&mut (&mut *self.buffer)[self.position as usize], byte) }; self.position += 1; Ok(()) } /// Write bytes pub fn write_raw_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> { - if bytes.len() <= self.buffer.len() - self.position { + if bytes.len() <= self.buffer().len() - self.position { let bottom = self.position as usize; let top = bottom + (bytes.len() as usize); - self.buffer[bottom..top].copy_from_slice(bytes); + // SAFETY: see the `buffer` field documentation about invariants. + let buffer = unsafe { &mut (&mut *self.buffer)[bottom..top] }; + maybe_uninit_write_slice(buffer, bytes); self.position += bytes.len(); return Ok(()); } @@ -189,8 +230,11 @@ impl<'a> CodedOutputStream<'a> { assert!(self.position == 0); - if self.position + bytes.len() < self.buffer.len() { - self.buffer[self.position..self.position + bytes.len()].copy_from_slice(bytes); + if self.position + bytes.len() < self.buffer().len() { + // SAFETY: see the `buffer` field documentation about invariants. + let buffer = + unsafe { &mut (&mut *self.buffer)[self.position..self.position + bytes.len()] }; + maybe_uninit_write_slice(buffer, bytes); self.position += bytes.len(); return Ok(()); } @@ -204,9 +248,7 @@ impl<'a> CodedOutputStream<'a> { } OutputTarget::Vec(ref mut vec) => { vec.extend(bytes); - unsafe { - self.buffer = remove_lifetime_mut(remaining_capacity_as_slice_mut(vec)); - } + self.buffer = vec_spare_capacity_mut(vec) } } Ok(()) @@ -223,30 +265,38 @@ impl<'a> CodedOutputStream<'a> { /// Write varint pub fn write_raw_varint32(&mut self, value: u32) -> ProtobufResult<()> { - if self.buffer.len() - self.position >= 5 { + if self.buffer().len() - self.position >= 5 { // fast path - let len = varint::encode_varint32(value, &mut self.buffer[self.position..]); + let len = unsafe { + varint::encode_varint32(value, &mut (&mut *self.buffer)[self.position..]) + }; self.position += len; Ok(()) } else { // slow path let buf = &mut [0u8; 5]; - let len = varint::encode_varint32(value, buf); + let len = varint::encode_varint32(value, unsafe { + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut MaybeUninit<u8>, buf.len()) + }); self.write_raw_bytes(&buf[..len]) } } /// Write varint pub fn write_raw_varint64(&mut self, value: u64) -> ProtobufResult<()> { - if self.buffer.len() - self.position >= 10 { + if self.buffer().len() - self.position >= 10 { // fast path - let len = varint::encode_varint64(value, &mut self.buffer[self.position..]); + let len = unsafe { + varint::encode_varint64(value, &mut (&mut *self.buffer)[self.position..]) + }; self.position += len; Ok(()) } else { // slow path let buf = &mut [0u8; 10]; - let len = varint::encode_varint64(value, buf); + let len = varint::encode_varint64(value, unsafe { + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut MaybeUninit<u8>, buf.len()) + }); self.write_raw_bytes(&buf[..len]) } } @@ -532,13 +582,14 @@ impl<'a> Write for CodedOutputStream<'a> { #[cfg(test)] mod test { + use std::io::Write; + use std::iter; + use crate::coded_output_stream::CodedOutputStream; use crate::hex::decode_hex; use crate::hex::encode_hex; use crate::wire_format; use crate::ProtobufResult; - use std::io::Write; - use std::iter; fn test_write<F>(expected: &str, mut gen: F) where diff --git a/src/compiler_plugin.rs b/src/compiler_plugin.rs index e056071..122eeb3 100644 --- a/src/compiler_plugin.rs +++ b/src/compiler_plugin.rs @@ -1,13 +1,14 @@ // TODO: move into separate crate #![doc(hidden)] -use crate::descriptor::FileDescriptorProto; -use crate::plugin::*; -use crate::Message; use std::io::stdin; use std::io::stdout; use std::str; +use crate::descriptor::FileDescriptorProto; +use crate::plugin::*; +use crate::Message; + pub struct GenRequest<'a> { pub file_descriptors: &'a [FileDescriptorProto], pub files_to_generate: &'a [String], diff --git a/src/descriptor.rs b/src/descriptor.rs index 8f3dd2f..7ca155d 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/descriptorx.rs b/src/descriptorx.rs index 82baab8..7b046ec 100644 --- a/src/descriptorx.rs +++ b/src/descriptorx.rs @@ -8,7 +8,6 @@ use crate::descriptor::FieldDescriptorProto; /// utilities to work with descriptor use crate::descriptor::FileDescriptorProto; use crate::descriptor::OneofDescriptorProto; - use crate::rust; use crate::strx; diff --git a/src/lazy.rs b/src/lazy.rs index 5b01502..3575dd0 100644 --- a/src/lazy.rs +++ b/src/lazy.rs @@ -56,13 +56,14 @@ pub const ONCE_INIT: sync::Once = sync::Once::new(); #[cfg(test)] mod test { - use super::Lazy; use std::sync::atomic::AtomicIsize; use std::sync::atomic::Ordering; use std::sync::Arc; use std::sync::Barrier; use std::thread; + use super::Lazy; + #[test] fn many_threads_calling_get() { const N_THREADS: usize = 32; diff --git a/src/lazy_v2.rs b/src/lazy_v2.rs index 4ba10a5..6f9ac1e 100644 --- a/src/lazy_v2.rs +++ b/src/lazy_v2.rs @@ -33,13 +33,14 @@ impl<T: Sync> LazyV2<T> { #[cfg(test)] mod test { - use super::LazyV2; use std::sync::atomic::AtomicIsize; use std::sync::atomic::Ordering; use std::sync::Arc; use std::sync::Barrier; use std::thread; + use super::LazyV2; + #[test] fn many_threads_calling_get() { const N_THREADS: usize = 32; @@ -1,7 +1,97 @@ -//! Library to read and write protocol buffers data. +//! # Library to read and write protocol buffers data +//! +//! # Version 2 is stable +//! +//! Currently developed branch of rust-protobuf [is 3](https://docs.rs/protobuf/%3E=3.0.0-alpha). +//! It has the same spirit as version 2, but contains numerous improvements like: +//! * runtime reflection for mutability, not just for access +//! * protobuf text format and JSON parsing (which rely on reflection) +//! * dynamic message support: work with protobuf data without generating code from schema +//! +//! Stable version of rust-protobuf will be supported until version 3 released. +//! +//! [Tracking issue for version 3](https://github.com/stepancheg/rust-protobuf/issues/518). +//! +//! # How to generate rust code +//! +//! There are several ways to generate rust code from `.proto` files +//! +//! ## Invoke `protoc` programmatically with protoc-rust crate (recommended) +//! +//! Have a look at readme in [protoc-rust crate](https://docs.rs/protoc-rust/=2). +//! +//! ## Use pure rust protobuf parser and code generator +//! +//! Readme should be in +//! [protobuf-codegen-pure crate](https://docs.rs/protobuf-codegen-pure/=2). +//! +//! ## Use protoc-gen-rust plugin +//! +//! Readme is [here](https://docs.rs/protobuf-codegen/=2). +//! +//! ## Generated code +//! +//! Have a look at generated files (for current development version), +//! used internally in rust-protobuf: +//! +//! * [descriptor.rs](https://github.com/stepancheg/rust-protobuf/blob/master/protobuf/src/descriptor.rs) +//! for [descriptor.proto](https://github.com/stepancheg/rust-protobuf/blob/master/protoc-bin-vendored/include/google/protobuf/descriptor.proto) +//! (that is part of Google protobuf) +//! +//! # Copy on write +//! +//! Rust-protobuf can be used with [bytes crate](https://github.com/tokio-rs/bytes). +//! +//! To enable `Bytes` you need to: +//! +//! 1. Enable `with-bytes` feature in rust-protobuf: +//! +//! ``` +//! [dependencies] +//! protobuf = { version = "~2.0", features = ["with-bytes"] } +//! ``` +//! +//! 2. Enable bytes option +//! +//! with `Customize` when codegen is invoked programmatically: +//! +//! ```ignore +//! protoc_rust::run(protoc_rust::Args { +//! ... +//! customize: Customize { +//! carllerche_bytes_for_bytes: Some(true), +//! carllerche_bytes_for_string: Some(true), +//! ..Default::default() +//! }, +//! }); +//! ``` +//! +//! or in `.proto` file: +//! +//! ```ignore +//! import "rustproto.proto"; +//! +//! option (rustproto.carllerche_bytes_for_bytes_all) = true; +//! option (rustproto.carllerche_bytes_for_string_all) = true; +//! ``` +//! +//! With these options enabled, fields of type `bytes` or `string` are +//! generated as `Bytes` or `Chars` respectively. When `CodedInputStream` is constructed +//! from `Bytes` object, fields of these types get subslices of original `Bytes` object, +//! instead of being allocated on heap. +//! +//! # Accompanying crates +//! +//! * [`protoc-rust`](https://docs.rs/protoc-rust/=2) +//! and [`protobuf-codegen-pure`](https://docs.rs/protobuf-codegen-pure/=2) +//! can be used to rust code from `.proto` crates. +//! * [`protobuf-codegen`](https://docs.rs/protobuf-codegen/=2) for `protoc-gen-rust` protoc plugin. +//! * [`protoc`](https://docs.rs/protoc/=2) crate can be used to invoke `protoc` programmatically. +//! * [`protoc-bin-vendored`](https://docs.rs/protoc-bin-vendored/=2) contains `protoc` command +//! packed into the crate. #![deny(missing_docs)] -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] #[cfg(feature = "bytes")] extern crate bytes; @@ -90,6 +180,7 @@ mod zigzag; mod misc; mod buf_read_iter; +mod buf_read_or_reader; /// This symbol is in generated `version.rs`, include here for IDE #[cfg(never)] diff --git a/src/misc.rs b/src/misc.rs index d923d58..faef34f 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,37 +1,52 @@ use std::mem; +use std::mem::MaybeUninit; use std::slice; -/// Slice from `vec[vec.len()..vec.capacity()]` -pub unsafe fn remaining_capacity_as_slice_mut<A>(vec: &mut Vec<A>) -> &mut [A] { - slice::from_raw_parts_mut( - vec.as_mut_slice().as_mut_ptr().offset(vec.len() as isize), - vec.capacity() - vec.len(), - ) +/// `Vec::spare_capacity_mut` is not stable until Rust 1.60. +pub(crate) fn vec_spare_capacity_mut<A>(vec: &mut Vec<A>) -> &mut [MaybeUninit<A>] { + // SAFETY: copy-paste from rust stdlib. + unsafe { + slice::from_raw_parts_mut( + vec.as_mut_ptr().add(vec.len()) as *mut MaybeUninit<A>, + vec.capacity() - vec.len(), + ) + } } -pub unsafe fn remove_lifetime_mut<A: ?Sized>(a: &mut A) -> &'static mut A { - mem::transmute(a) +/// `MaybeUninit::write_slice` is not stable. +pub(crate) fn maybe_uninit_write_slice<'a, T>( + this: &'a mut [MaybeUninit<T>], + src: &[T], +) -> &'a mut [T] +where + T: Copy, +{ + // SAFETY: copy-paste from rust stdlib. + + let uninit_src: &[MaybeUninit<T>] = unsafe { mem::transmute(src) }; + + this.copy_from_slice(uninit_src); + + unsafe { &mut *(this as *mut [MaybeUninit<T>] as *mut [T]) } } -#[cfg(test)] -mod test { - use super::*; +/// `MaybeUninit::array_assume_init` is not stable. +#[inline] +pub(crate) unsafe fn maybe_ununit_array_assume_init<T, const N: usize>( + array: [MaybeUninit<T>; N], +) -> [T; N] { + // SAFETY: + // * The caller guarantees that all elements of the array are initialized + // * `MaybeUninit<T>` and T are guaranteed to have the same layout + // * `MaybeUninit` does not drop, so there are no double-frees + // And thus the conversion is safe + (&array as *const _ as *const [T; N]).read() +} - #[test] - fn test_remaining_capacity_as_slice_mut() { - let mut v = Vec::with_capacity(5); - v.push(10); - v.push(11); - v.push(12); - unsafe { - { - let s = remaining_capacity_as_slice_mut(&mut v); - assert_eq!(2, s.len()); - s[0] = 13; - s[1] = 14; - } - v.set_len(5); - } - assert_eq!(vec![10, 11, 12, 13, 14], v); - } +/// `MaybeUninit::write` is stable since 1.55. +#[inline] +pub(crate) fn maybe_uninit_write<T>(uninit: &mut MaybeUninit<T>, val: T) -> &mut T { + // SAFETY: copy-paste from rust stdlib. + *uninit = MaybeUninit::new(val); + unsafe { &mut *uninit.as_mut_ptr() } } diff --git a/src/plugin.rs b/src/plugin.rs index 77e1666..93f2ca8 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/reflect/acc/v1.rs b/src/reflect/acc/v1.rs index d6bd3d3..4c55f8f 100644 --- a/src/reflect/acc/v1.rs +++ b/src/reflect/acc/v1.rs @@ -9,21 +9,20 @@ use std::hash::Hash; use crate::enums::ProtobufEnum; use crate::message::message_down_cast; use crate::message::Message; -use crate::reflect::EnumValueDescriptor; -use crate::reflect::ProtobufValue; -use crate::reflect::ReflectFieldRef; -use crate::reflect::ReflectValueRef; -use crate::types::*; - use crate::reflect::map::ReflectMap; use crate::reflect::optional::ReflectOptional; use crate::reflect::repeated::ReflectRepeated; use crate::reflect::repeated::ReflectRepeatedEnum; use crate::reflect::repeated::ReflectRepeatedMessage; use crate::reflect::rt::FieldAccessor; +use crate::reflect::EnumValueDescriptor; +use crate::reflect::ProtobufValue; +use crate::reflect::ReflectFieldRef; +use crate::reflect::ReflectValueRef; use crate::repeated::RepeatedField; use crate::singular::SingularField; use crate::singular::SingularPtrField; +use crate::types::*; /// this trait should not be used directly, use `FieldDescriptor` instead pub trait FieldAccessorTrait: Sync + 'static { diff --git a/src/reflect/enums.rs b/src/reflect/enums.rs index f1ad901..a25be6f 100644 --- a/src/reflect/enums.rs +++ b/src/reflect/enums.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::descriptor::EnumDescriptorProto; use crate::descriptor::EnumValueDescriptorProto; use crate::descriptor::FileDescriptorProto; @@ -5,7 +7,6 @@ use crate::descriptorx::find_enum_by_rust_name; use crate::reflect::find_message_or_enum::find_message_or_enum; use crate::reflect::find_message_or_enum::MessageOrEnum; use crate::ProtobufEnum; -use std::collections::HashMap; /// Description for enum variant. /// diff --git a/src/reflect/message.rs b/src/reflect/message.rs index 53ea2ce..0db9821 100644 --- a/src/reflect/message.rs +++ b/src/reflect/message.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; +use std::marker; + use crate::descriptor::DescriptorProto; use crate::descriptor::FileDescriptorProto; use crate::descriptorx::find_message_by_rust_name; @@ -6,8 +9,6 @@ use crate::reflect::find_message_or_enum::find_message_or_enum; use crate::reflect::find_message_or_enum::MessageOrEnum; use crate::reflect::FieldDescriptor; use crate::Message; -use std::collections::HashMap; -use std::marker; trait MessageFactory: Send + Sync + 'static { fn new_instance(&self) -> Box<dyn Message>; diff --git a/src/reflect/mod.rs b/src/reflect/mod.rs index 392f629..e120e16 100644 --- a/src/reflect/mod.rs +++ b/src/reflect/mod.rs @@ -23,8 +23,6 @@ pub mod rt; pub use self::enums::EnumDescriptor; pub use self::enums::EnumValueDescriptor; - -pub use self::message::MessageDescriptor; - pub use self::field::FieldDescriptor; pub use self::field::ReflectFieldRef; +pub use self::message::MessageDescriptor; diff --git a/src/reflect/optional.rs b/src/reflect/optional.rs index f81f973..f719a2c 100644 --- a/src/reflect/optional.rs +++ b/src/reflect/optional.rs @@ -1,7 +1,6 @@ use std::mem; use super::value::ProtobufValue; - use crate::singular::*; pub trait ReflectOptional: 'static { diff --git a/src/reflect/repeated.rs b/src/reflect/repeated.rs index be232f4..710de3e 100644 --- a/src/reflect/repeated.rs +++ b/src/reflect/repeated.rs @@ -2,7 +2,6 @@ use std::slice; use super::value::ProtobufValue; use super::value::ReflectValueRef; - use crate::repeated::RepeatedField; pub trait ReflectRepeated: 'static { diff --git a/src/reflect/value.rs b/src/reflect/value.rs index 16d5266..9598b9f 100644 --- a/src/reflect/value.rs +++ b/src/reflect/value.rs @@ -1,11 +1,11 @@ use std::any::Any; #[cfg(feature = "bytes")] -use crate::chars::Chars; -#[cfg(feature = "bytes")] use bytes::Bytes; use super::*; +#[cfg(feature = "bytes")] +use crate::chars::Chars; /// Type implemented by all protobuf elementary types /// (ints, floats, bool, string, bytes, enums, messages). diff --git a/src/repeated.rs b/src/repeated.rs index d157f0c..0b749d9 100644 --- a/src/repeated.rs +++ b/src/repeated.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "with-serde")] -use serde; - use std::borrow::Borrow; use std::cmp::Ordering; use std::default::Default; @@ -16,6 +13,9 @@ use std::ops::IndexMut; use std::slice; use std::vec; +#[cfg(feature = "with-serde")] +use serde; + use crate::clear::Clear; /// Wrapper around vector to avoid deallocations on clear. @@ -6,27 +6,26 @@ use std::default::Default; use std::hash::Hash; #[cfg(feature = "bytes")] -use crate::chars::Chars; -#[cfg(feature = "bytes")] use bytes::Bytes; +#[cfg(feature = "bytes")] +use crate::chars::Chars; use crate::coded_input_stream::CodedInputStream; use crate::coded_output_stream::CodedOutputStream; use crate::enums::ProtobufEnum; use crate::error::ProtobufError; use crate::error::ProtobufResult; use crate::error::WireError; +pub use crate::lazy_v2::LazyV2; use crate::message::*; use crate::repeated::RepeatedField; use crate::singular::SingularField; use crate::singular::SingularPtrField; use crate::types::*; -use crate::zigzag::*; - -pub use crate::lazy_v2::LazyV2; use crate::unknown::UnknownFields; use crate::wire_format; use crate::wire_format::WireType; +use crate::zigzag::*; /// Given `u64` value compute varint encoded length. pub fn compute_raw_varint64_size(value: u64) -> u32 { diff --git a/src/rustproto.rs b/src/rustproto.rs index 83854e4..75df067 100644 --- a/src/rustproto.rs +++ b/src/rustproto.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 @@ -59,6 +59,8 @@ pub mod exts { pub const carllerche_bytes_for_bytes_field: crate::ext::ExtFieldOptional<crate::descriptor::FieldOptions, crate::types::ProtobufTypeBool> = crate::ext::ExtFieldOptional { field_number: 17011, phantom: ::std::marker::PhantomData }; pub const carllerche_bytes_for_string_field: crate::ext::ExtFieldOptional<crate::descriptor::FieldOptions, crate::types::ProtobufTypeBool> = crate::ext::ExtFieldOptional { field_number: 17012, phantom: ::std::marker::PhantomData }; + + pub const serde_rename_all: crate::ext::ExtFieldOptional<crate::descriptor::EnumOptions, crate::types::ProtobufTypeString> = crate::ext::ExtFieldOptional { field_number: 17032, phantom: ::std::marker::PhantomData }; } static file_descriptor_proto_data: &'static [u8] = b"\ @@ -94,92 +96,98 @@ static file_descriptor_proto_data: &'static [u8] = b"\ s_for_bytes_field\x18\xf3\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.F\ ieldOptionsR\x1ccarllercheBytesForBytesField:i\n!carllerche_bytes_for_st\ ring_field\x18\xf4\x84\x01\x20\x01(\x08\x12\x1d.google.protobuf.FieldOpt\ - ionsR\x1dcarllercheBytesForStringFieldJ\xf2\x13\n\x06\x12\x04\0\07\x01\n\ - \x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\0\x12\x03\x02\0*\nh\n\x01\ - \x02\x12\x03\x07\0\x122^\x20see\x20https://github.com/gogo/protobuf/blob\ - /master/gogoproto/gogo.proto\n\x20for\x20the\x20original\x20idea\n\n\t\n\ - \x01\x07\x12\x04\t\0\x1b\x01\n7\n\x02\x07\0\x12\x03\x0b\x04+\x1a,\x20Whe\ - n\x20true,\x20oneof\x20field\x20is\x20generated\x20public\n\n\n\n\x03\ - \x07\0\x02\x12\x03\t\x07\"\n\n\n\x03\x07\0\x04\x12\x03\x0b\x04\x0c\n\n\n\ - \x03\x07\0\x05\x12\x03\x0b\r\x11\n\n\n\x03\x07\0\x01\x12\x03\x0b\x12\"\n\ - \n\n\x03\x07\0\x03\x12\x03\x0b%*\nI\n\x02\x07\x01\x12\x03\r\x04,\x1a>\ - \x20When\x20true\x20all\x20fields\x20are\x20public,\x20and\x20not\x20acc\ - essors\x20generated\n\n\n\n\x03\x07\x01\x02\x12\x03\t\x07\"\n\n\n\x03\ - \x07\x01\x04\x12\x03\r\x04\x0c\n\n\n\x03\x07\x01\x05\x12\x03\r\r\x11\n\n\ - \n\x03\x07\x01\x01\x12\x03\r\x12#\n\n\n\x03\x07\x01\x03\x12\x03\r&+\nP\n\ - \x02\x07\x02\x12\x03\x0f\x041\x1aE\x20When\x20false,\x20`get_`,\x20`set_\ - `,\x20`mut_`\x20etc.\x20accessors\x20are\x20not\x20generated\n\n\n\n\x03\ - \x07\x02\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x02\x04\x12\x03\x0f\x04\x0c\n\ - \n\n\x03\x07\x02\x05\x12\x03\x0f\r\x11\n\n\n\x03\x07\x02\x01\x12\x03\x0f\ - \x12(\n\n\n\x03\x07\x02\x03\x12\x03\x0f+0\n2\n\x02\x07\x03\x12\x03\x11\ - \x049\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20fields\n\n\n\n\ - \x03\x07\x03\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x03\x04\x12\x03\x11\x04\ - \x0c\n\n\n\x03\x07\x03\x05\x12\x03\x11\r\x11\n\n\n\x03\x07\x03\x01\x12\ - \x03\x11\x120\n\n\n\x03\x07\x03\x03\x12\x03\x1138\n3\n\x02\x07\x04\x12\ - \x03\x13\x04:\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`string`\x20fields\ - \n\n\n\n\x03\x07\x04\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x04\x04\x12\x03\ - \x13\x04\x0c\n\n\n\x03\x07\x04\x05\x12\x03\x13\r\x11\n\n\n\x03\x07\x04\ - \x01\x12\x03\x13\x121\n\n\n\x03\x07\x04\x03\x12\x03\x1349\nJ\n\x02\x07\ - \x05\x12\x03\x15\x04+\x1a?\x20Use\x20`serde_derive`\x20to\x20implement\ - \x20`Serialize`\x20and\x20`Deserialize`\n\n\n\n\x03\x07\x05\x02\x12\x03\ - \t\x07\"\n\n\n\x03\x07\x05\x04\x12\x03\x15\x04\x0c\n\n\n\x03\x07\x05\x05\ - \x12\x03\x15\r\x11\n\n\n\x03\x07\x05\x01\x12\x03\x15\x12\"\n\n\n\x03\x07\ - \x05\x03\x12\x03\x15%*\n3\n\x02\x07\x06\x12\x03\x17\x041\x1a(\x20Guard\ - \x20serde\x20annotations\x20with\x20cfg\x20attr.\n\n\n\n\x03\x07\x06\x02\ - \x12\x03\t\x07\"\n\n\n\x03\x07\x06\x04\x12\x03\x17\x04\x0c\n\n\n\x03\x07\ - \x06\x05\x12\x03\x17\r\x13\n\n\n\x03\x07\x06\x01\x12\x03\x17\x14(\n\n\n\ - \x03\x07\x06\x03\x12\x03\x17+0\nN\n\x02\x07\x07\x12\x03\x1a\x04+\x1aC\ - \x20When\x20true,\x20will\x20only\x20generate\x20codes\x20that\x20works\ - \x20with\x20lite\x20runtime.\n\n\n\n\x03\x07\x07\x02\x12\x03\t\x07\"\n\n\ - \n\x03\x07\x07\x04\x12\x03\x1a\x04\x0c\n\n\n\x03\x07\x07\x05\x12\x03\x1a\ - \r\x11\n\n\n\x03\x07\x07\x01\x12\x03\x1a\x12\"\n\n\n\x03\x07\x07\x03\x12\ - \x03\x1a%*\n\t\n\x01\x07\x12\x04\x1d\0,\x01\n7\n\x02\x07\x08\x12\x03\x1f\ - \x04'\x1a,\x20When\x20true,\x20oneof\x20field\x20is\x20generated\x20publ\ - ic\n\n\n\n\x03\x07\x08\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\x08\x04\x12\ - \x03\x1f\x04\x0c\n\n\n\x03\x07\x08\x05\x12\x03\x1f\r\x11\n\n\n\x03\x07\ - \x08\x01\x12\x03\x1f\x12\x1e\n\n\n\x03\x07\x08\x03\x12\x03\x1f!&\nI\n\ - \x02\x07\t\x12\x03!\x04(\x1a>\x20When\x20true\x20all\x20fields\x20are\ - \x20public,\x20and\x20not\x20accessors\x20generated\n\n\n\n\x03\x07\t\ - \x02\x12\x03\x1d\x07%\n\n\n\x03\x07\t\x04\x12\x03!\x04\x0c\n\n\n\x03\x07\ - \t\x05\x12\x03!\r\x11\n\n\n\x03\x07\t\x01\x12\x03!\x12\x1f\n\n\n\x03\x07\ - \t\x03\x12\x03!\"'\nP\n\x02\x07\n\x12\x03#\x04-\x1aE\x20When\x20false,\ - \x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\x20are\x20not\x20g\ - enerated\n\n\n\n\x03\x07\n\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\n\x04\x12\ - \x03#\x04\x0c\n\n\n\x03\x07\n\x05\x12\x03#\r\x11\n\n\n\x03\x07\n\x01\x12\ - \x03#\x12$\n\n\n\x03\x07\n\x03\x12\x03#',\n2\n\x02\x07\x0b\x12\x03%\x045\ - \x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20fields\n\n\n\n\x03\ - \x07\x0b\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\x0b\x04\x12\x03%\x04\x0c\n\n\ - \n\x03\x07\x0b\x05\x12\x03%\r\x11\n\n\n\x03\x07\x0b\x01\x12\x03%\x12,\n\ - \n\n\x03\x07\x0b\x03\x12\x03%/4\n3\n\x02\x07\x0c\x12\x03'\x046\x1a(\x20U\ - se\x20`bytes::Bytes`\x20for\x20`string`\x20fields\n\n\n\n\x03\x07\x0c\ - \x02\x12\x03\x1d\x07%\n\n\n\x03\x07\x0c\x04\x12\x03'\x04\x0c\n\n\n\x03\ - \x07\x0c\x05\x12\x03'\r\x11\n\n\n\x03\x07\x0c\x01\x12\x03'\x12-\n\n\n\ - \x03\x07\x0c\x03\x12\x03'05\nJ\n\x02\x07\r\x12\x03)\x04'\x1a?\x20Use\x20\ + ionsR\x1dcarllercheBytesForStringField:H\n\x10serde_rename_all\x18\x88\ + \x85\x01\x20\x01(\t\x12\x1c.google.protobuf.EnumOptionsR\x0eserdeRenameA\ + llJ\xea\x14\n\x06\x12\x04\0\0<\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\ + \x02\x03\0\x12\x03\x02\0*\nh\n\x01\x02\x12\x03\x07\0\x122^\x20see\x20htt\ + ps://github.com/gogo/protobuf/blob/master/gogoproto/gogo.proto\n\x20for\ + \x20the\x20original\x20idea\n\n\t\n\x01\x07\x12\x04\t\0\x1b\x01\n7\n\x02\ + \x07\0\x12\x03\x0b\x04+\x1a,\x20When\x20true,\x20oneof\x20field\x20is\ + \x20generated\x20public\n\n\n\n\x03\x07\0\x02\x12\x03\t\x07\"\n\n\n\x03\ + \x07\0\x04\x12\x03\x0b\x04\x0c\n\n\n\x03\x07\0\x05\x12\x03\x0b\r\x11\n\n\ + \n\x03\x07\0\x01\x12\x03\x0b\x12\"\n\n\n\x03\x07\0\x03\x12\x03\x0b%*\nI\ + \n\x02\x07\x01\x12\x03\r\x04,\x1a>\x20When\x20true\x20all\x20fields\x20a\ + re\x20public,\x20and\x20not\x20accessors\x20generated\n\n\n\n\x03\x07\ + \x01\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x01\x04\x12\x03\r\x04\x0c\n\n\n\ + \x03\x07\x01\x05\x12\x03\r\r\x11\n\n\n\x03\x07\x01\x01\x12\x03\r\x12#\n\ + \n\n\x03\x07\x01\x03\x12\x03\r&+\nP\n\x02\x07\x02\x12\x03\x0f\x041\x1aE\ + \x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\ + \x20are\x20not\x20generated\n\n\n\n\x03\x07\x02\x02\x12\x03\t\x07\"\n\n\ + \n\x03\x07\x02\x04\x12\x03\x0f\x04\x0c\n\n\n\x03\x07\x02\x05\x12\x03\x0f\ + \r\x11\n\n\n\x03\x07\x02\x01\x12\x03\x0f\x12(\n\n\n\x03\x07\x02\x03\x12\ + \x03\x0f+0\n2\n\x02\x07\x03\x12\x03\x11\x049\x1a'\x20Use\x20`bytes::Byte\ + s`\x20for\x20`bytes`\x20fields\n\n\n\n\x03\x07\x03\x02\x12\x03\t\x07\"\n\ + \n\n\x03\x07\x03\x04\x12\x03\x11\x04\x0c\n\n\n\x03\x07\x03\x05\x12\x03\ + \x11\r\x11\n\n\n\x03\x07\x03\x01\x12\x03\x11\x120\n\n\n\x03\x07\x03\x03\ + \x12\x03\x1138\n3\n\x02\x07\x04\x12\x03\x13\x04:\x1a(\x20Use\x20`bytes::\ + Bytes`\x20for\x20`string`\x20fields\n\n\n\n\x03\x07\x04\x02\x12\x03\t\ + \x07\"\n\n\n\x03\x07\x04\x04\x12\x03\x13\x04\x0c\n\n\n\x03\x07\x04\x05\ + \x12\x03\x13\r\x11\n\n\n\x03\x07\x04\x01\x12\x03\x13\x121\n\n\n\x03\x07\ + \x04\x03\x12\x03\x1349\nJ\n\x02\x07\x05\x12\x03\x15\x04+\x1a?\x20Use\x20\ `serde_derive`\x20to\x20implement\x20`Serialize`\x20and\x20`Deserialize`\ - \n\n\n\n\x03\x07\r\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\r\x04\x12\x03)\x04\ - \x0c\n\n\n\x03\x07\r\x05\x12\x03)\r\x11\n\n\n\x03\x07\r\x01\x12\x03)\x12\ - \x1e\n\n\n\x03\x07\r\x03\x12\x03)!&\n3\n\x02\x07\x0e\x12\x03+\x04-\x1a(\ - \x20Guard\x20serde\x20annotations\x20with\x20cfg\x20attr.\n\n\n\n\x03\ - \x07\x0e\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\x0e\x04\x12\x03+\x04\x0c\n\n\ - \n\x03\x07\x0e\x05\x12\x03+\r\x13\n\n\n\x03\x07\x0e\x01\x12\x03+\x14$\n\ - \n\n\x03\x07\x0e\x03\x12\x03+',\n\t\n\x01\x07\x12\x04.\07\x01\nI\n\x02\ - \x07\x0f\x12\x030\x04.\x1a>\x20When\x20true\x20all\x20fields\x20are\x20p\ - ublic,\x20and\x20not\x20accessors\x20generated\n\n\n\n\x03\x07\x0f\x02\ - \x12\x03.\x07#\n\n\n\x03\x07\x0f\x04\x12\x030\x04\x0c\n\n\n\x03\x07\x0f\ - \x05\x12\x030\r\x11\n\n\n\x03\x07\x0f\x01\x12\x030\x12%\n\n\n\x03\x07\ - \x0f\x03\x12\x030(-\nP\n\x02\x07\x10\x12\x032\x043\x1aE\x20When\x20false\ - ,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20accessors\x20are\x20not\x20\ - generated\n\n\n\n\x03\x07\x10\x02\x12\x03.\x07#\n\n\n\x03\x07\x10\x04\ - \x12\x032\x04\x0c\n\n\n\x03\x07\x10\x05\x12\x032\r\x11\n\n\n\x03\x07\x10\ - \x01\x12\x032\x12*\n\n\n\x03\x07\x10\x03\x12\x032-2\n2\n\x02\x07\x11\x12\ - \x034\x04;\x1a'\x20Use\x20`bytes::Bytes`\x20for\x20`bytes`\x20fields\n\n\ - \n\n\x03\x07\x11\x02\x12\x03.\x07#\n\n\n\x03\x07\x11\x04\x12\x034\x04\ - \x0c\n\n\n\x03\x07\x11\x05\x12\x034\r\x11\n\n\n\x03\x07\x11\x01\x12\x034\ - \x122\n\n\n\x03\x07\x11\x03\x12\x0345:\n3\n\x02\x07\x12\x12\x036\x04<\ - \x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`string`\x20fields\n\n\n\n\x03\ - \x07\x12\x02\x12\x03.\x07#\n\n\n\x03\x07\x12\x04\x12\x036\x04\x0c\n\n\n\ - \x03\x07\x12\x05\x12\x036\r\x11\n\n\n\x03\x07\x12\x01\x12\x036\x123\n\n\ - \n\x03\x07\x12\x03\x12\x0366;\ + \n\n\n\n\x03\x07\x05\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x05\x04\x12\x03\ + \x15\x04\x0c\n\n\n\x03\x07\x05\x05\x12\x03\x15\r\x11\n\n\n\x03\x07\x05\ + \x01\x12\x03\x15\x12\"\n\n\n\x03\x07\x05\x03\x12\x03\x15%*\n3\n\x02\x07\ + \x06\x12\x03\x17\x041\x1a(\x20Guard\x20serde\x20annotations\x20with\x20c\ + fg\x20attr.\n\n\n\n\x03\x07\x06\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x06\ + \x04\x12\x03\x17\x04\x0c\n\n\n\x03\x07\x06\x05\x12\x03\x17\r\x13\n\n\n\ + \x03\x07\x06\x01\x12\x03\x17\x14(\n\n\n\x03\x07\x06\x03\x12\x03\x17+0\nN\ + \n\x02\x07\x07\x12\x03\x1a\x04+\x1aC\x20When\x20true,\x20will\x20only\ + \x20generate\x20codes\x20that\x20works\x20with\x20lite\x20runtime.\n\n\n\ + \n\x03\x07\x07\x02\x12\x03\t\x07\"\n\n\n\x03\x07\x07\x04\x12\x03\x1a\x04\ + \x0c\n\n\n\x03\x07\x07\x05\x12\x03\x1a\r\x11\n\n\n\x03\x07\x07\x01\x12\ + \x03\x1a\x12\"\n\n\n\x03\x07\x07\x03\x12\x03\x1a%*\n\t\n\x01\x07\x12\x04\ + \x1d\0,\x01\n7\n\x02\x07\x08\x12\x03\x1f\x04'\x1a,\x20When\x20true,\x20o\ + neof\x20field\x20is\x20generated\x20public\n\n\n\n\x03\x07\x08\x02\x12\ + \x03\x1d\x07%\n\n\n\x03\x07\x08\x04\x12\x03\x1f\x04\x0c\n\n\n\x03\x07\ + \x08\x05\x12\x03\x1f\r\x11\n\n\n\x03\x07\x08\x01\x12\x03\x1f\x12\x1e\n\n\ + \n\x03\x07\x08\x03\x12\x03\x1f!&\nI\n\x02\x07\t\x12\x03!\x04(\x1a>\x20Wh\ + en\x20true\x20all\x20fields\x20are\x20public,\x20and\x20not\x20accessors\ + \x20generated\n\n\n\n\x03\x07\t\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\t\x04\ + \x12\x03!\x04\x0c\n\n\n\x03\x07\t\x05\x12\x03!\r\x11\n\n\n\x03\x07\t\x01\ + \x12\x03!\x12\x1f\n\n\n\x03\x07\t\x03\x12\x03!\"'\nP\n\x02\x07\n\x12\x03\ + #\x04-\x1aE\x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\ + \x20accessors\x20are\x20not\x20generated\n\n\n\n\x03\x07\n\x02\x12\x03\ + \x1d\x07%\n\n\n\x03\x07\n\x04\x12\x03#\x04\x0c\n\n\n\x03\x07\n\x05\x12\ + \x03#\r\x11\n\n\n\x03\x07\n\x01\x12\x03#\x12$\n\n\n\x03\x07\n\x03\x12\ + \x03#',\n2\n\x02\x07\x0b\x12\x03%\x045\x1a'\x20Use\x20`bytes::Bytes`\x20\ + for\x20`bytes`\x20fields\n\n\n\n\x03\x07\x0b\x02\x12\x03\x1d\x07%\n\n\n\ + \x03\x07\x0b\x04\x12\x03%\x04\x0c\n\n\n\x03\x07\x0b\x05\x12\x03%\r\x11\n\ + \n\n\x03\x07\x0b\x01\x12\x03%\x12,\n\n\n\x03\x07\x0b\x03\x12\x03%/4\n3\n\ + \x02\x07\x0c\x12\x03'\x046\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`stri\ + ng`\x20fields\n\n\n\n\x03\x07\x0c\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\x0c\ + \x04\x12\x03'\x04\x0c\n\n\n\x03\x07\x0c\x05\x12\x03'\r\x11\n\n\n\x03\x07\ + \x0c\x01\x12\x03'\x12-\n\n\n\x03\x07\x0c\x03\x12\x03'05\nJ\n\x02\x07\r\ + \x12\x03)\x04'\x1a?\x20Use\x20`serde_derive`\x20to\x20implement\x20`Seri\ + alize`\x20and\x20`Deserialize`\n\n\n\n\x03\x07\r\x02\x12\x03\x1d\x07%\n\ + \n\n\x03\x07\r\x04\x12\x03)\x04\x0c\n\n\n\x03\x07\r\x05\x12\x03)\r\x11\n\ + \n\n\x03\x07\r\x01\x12\x03)\x12\x1e\n\n\n\x03\x07\r\x03\x12\x03)!&\n3\n\ + \x02\x07\x0e\x12\x03+\x04-\x1a(\x20Guard\x20serde\x20annotations\x20with\ + \x20cfg\x20attr.\n\n\n\n\x03\x07\x0e\x02\x12\x03\x1d\x07%\n\n\n\x03\x07\ + \x0e\x04\x12\x03+\x04\x0c\n\n\n\x03\x07\x0e\x05\x12\x03+\r\x13\n\n\n\x03\ + \x07\x0e\x01\x12\x03+\x14$\n\n\n\x03\x07\x0e\x03\x12\x03+',\n\t\n\x01\ + \x07\x12\x04.\07\x01\nI\n\x02\x07\x0f\x12\x030\x04.\x1a>\x20When\x20true\ + \x20all\x20fields\x20are\x20public,\x20and\x20not\x20accessors\x20genera\ + ted\n\n\n\n\x03\x07\x0f\x02\x12\x03.\x07#\n\n\n\x03\x07\x0f\x04\x12\x030\ + \x04\x0c\n\n\n\x03\x07\x0f\x05\x12\x030\r\x11\n\n\n\x03\x07\x0f\x01\x12\ + \x030\x12%\n\n\n\x03\x07\x0f\x03\x12\x030(-\nP\n\x02\x07\x10\x12\x032\ + \x043\x1aE\x20When\x20false,\x20`get_`,\x20`set_`,\x20`mut_`\x20etc.\x20\ + accessors\x20are\x20not\x20generated\n\n\n\n\x03\x07\x10\x02\x12\x03.\ + \x07#\n\n\n\x03\x07\x10\x04\x12\x032\x04\x0c\n\n\n\x03\x07\x10\x05\x12\ + \x032\r\x11\n\n\n\x03\x07\x10\x01\x12\x032\x12*\n\n\n\x03\x07\x10\x03\ + \x12\x032-2\n2\n\x02\x07\x11\x12\x034\x04;\x1a'\x20Use\x20`bytes::Bytes`\ + \x20for\x20`bytes`\x20fields\n\n\n\n\x03\x07\x11\x02\x12\x03.\x07#\n\n\n\ + \x03\x07\x11\x04\x12\x034\x04\x0c\n\n\n\x03\x07\x11\x05\x12\x034\r\x11\n\ + \n\n\x03\x07\x11\x01\x12\x034\x122\n\n\n\x03\x07\x11\x03\x12\x0345:\n3\n\ + \x02\x07\x12\x12\x036\x04<\x1a(\x20Use\x20`bytes::Bytes`\x20for\x20`stri\ + ng`\x20fields\n\n\n\n\x03\x07\x12\x02\x12\x03.\x07#\n\n\n\x03\x07\x12\ + \x04\x12\x036\x04\x0c\n\n\n\x03\x07\x12\x05\x12\x036\r\x11\n\n\n\x03\x07\ + \x12\x01\x12\x036\x123\n\n\n\x03\x07\x12\x03\x12\x0366;\n\t\n\x01\x07\ + \x12\x049\0<\x01\n/\n\x02\x07\x13\x12\x03;\x04-\x1a$\x20use\x20rename_al\ + l\x20attribute\x20for\x20serde\n\n\n\n\x03\x07\x13\x02\x12\x039\x07\"\n\ + \n\n\x03\x07\x13\x04\x12\x03;\x04\x0c\n\n\n\x03\x07\x13\x05\x12\x03;\r\ + \x13\n\n\n\x03\x07\x13\x01\x12\x03;\x14$\n\n\n\x03\x07\x13\x03\x12\x03;'\ + ,\ "; static file_descriptor_proto_lazy: crate::rt::LazyV2<crate::descriptor::FileDescriptorProto> = crate::rt::LazyV2::INIT; diff --git a/src/singular.rs b/src/singular.rs index ef04d2f..1b7e28d 100644 --- a/src/singular.rs +++ b/src/singular.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "with-serde")] -use serde; - use std::default::Default; use std::fmt; use std::hash::Hash; @@ -8,6 +5,9 @@ use std::hash::Hasher; use std::mem; use std::option; +#[cfg(feature = "with-serde")] +use serde; + use crate::clear::Clear; /// Like `Option<T>`, but keeps the actual element on `clear`. @@ -341,7 +341,9 @@ impl<T: Default + Clear> SingularField<T> { /// Get contained data, consume self. Return default value for type if this is empty. #[inline] pub fn unwrap_or_default(mut self) -> T { - self.value.clear(); + if !self.set { + self.value.clear(); + } self.value } @@ -577,4 +579,16 @@ mod test { x.set_default(); assert_eq!(0, x.as_ref().unwrap().b); } + + #[test] + fn unwrap_or_default() { + assert_eq!( + "abc", + SingularField::some("abc".to_owned()).unwrap_or_default() + ); + assert_eq!("", SingularField::<String>::none().unwrap_or_default()); + let mut some = SingularField::some("abc".to_owned()); + some.clear(); + assert_eq!("", some.unwrap_or_default()); + } } diff --git a/src/text_format/lexer/str_lit.rs b/src/text_format/lexer/str_lit.rs index caa98f1..15ffa5b 100644 --- a/src/text_format/lexer/str_lit.rs +++ b/src/text_format/lexer/str_lit.rs @@ -1,8 +1,9 @@ +use std::fmt; +use std::string::FromUtf8Error; + use super::lexer_impl::Lexer; use super::lexer_impl::LexerError; use crate::text_format::lexer::ParserLanguage; -use std::fmt; -use std::string::FromUtf8Error; #[derive(Debug)] pub enum StrLitDecodeError { diff --git a/src/text_format/mod.rs b/src/text_format/mod.rs index 7af03e4..2fa9a16 100644 --- a/src/text_format/mod.rs +++ b/src/text_format/mod.rs @@ -19,13 +19,14 @@ //! protobuf implementations, including `protoc` command which can decode //! and encode messages using text format. -use crate::message::Message; -use crate::reflect::ReflectFieldRef; -use crate::reflect::ReflectValueRef; use std; use std::fmt; use std::fmt::Write; +use crate::message::Message; +use crate::reflect::ReflectFieldRef; +use crate::reflect::ReflectValueRef; + mod print; // Used by text format parser and by pure-rust codegen parsed diff --git a/src/types.rs b/src/types.rs index d9bbb10..20244a1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -4,10 +4,10 @@ use std::marker; use std::mem; #[cfg(feature = "bytes")] -use crate::chars::Chars; -#[cfg(feature = "bytes")] use bytes::Bytes; +#[cfg(feature = "bytes")] +use crate::chars::Chars; use crate::coded_input_stream::CodedInputStream; use crate::coded_output_stream::CodedOutputStream; use crate::enums::ProtobufEnum; diff --git a/src/unknown.rs b/src/unknown.rs index 8e9da12..dd67033 100644 --- a/src/unknown.rs +++ b/src/unknown.rs @@ -1,7 +1,3 @@ -use crate::clear::Clear; -use crate::wire_format; -use crate::zigzag::encode_zig_zag_32; -use crate::zigzag::encode_zig_zag_64; use std::collections::hash_map; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; @@ -11,6 +7,11 @@ use std::hash::Hash; use std::hash::Hasher; use std::slice; +use crate::clear::Clear; +use crate::wire_format; +use crate::zigzag::encode_zig_zag_32; +use crate::zigzag::encode_zig_zag_64; + /// Unknown value. /// /// See [`UnknownFields`](crate::UnknownFields) for the explanations. @@ -311,11 +312,12 @@ impl<'s> Iterator for UnknownFieldsIter<'s> { #[cfg(test)] mod test { - use super::UnknownFields; use std::collections::hash_map::DefaultHasher; use std::hash::Hash; use std::hash::Hasher; + use super::UnknownFields; + #[test] fn unknown_fields_hash() { let mut unknown_fields_1 = UnknownFields::new(); diff --git a/src/varint.rs b/src/varint.rs index 1f1cb1c..8e542bc 100644 --- a/src/varint.rs +++ b/src/varint.rs @@ -1,17 +1,21 @@ +use std::mem::MaybeUninit; + +use crate::misc::maybe_uninit_write; + /// Encode u64 as varint. /// Panics if buffer length is less than 10. #[inline] -pub fn encode_varint64(mut value: u64, buf: &mut [u8]) -> usize { +pub fn encode_varint64(mut value: u64, buf: &mut [MaybeUninit<u8>]) -> usize { assert!(buf.len() >= 10); unsafe { let mut i = 0; while (value & !0x7F) > 0 { - *buf.get_unchecked_mut(i) = ((value & 0x7F) | 0x80) as u8; + maybe_uninit_write(buf.get_unchecked_mut(i), ((value & 0x7F) | 0x80) as u8); value >>= 7; i += 1; } - *buf.get_unchecked_mut(i) = value as u8; + maybe_uninit_write(buf.get_unchecked_mut(i), value as u8); i + 1 } } @@ -19,17 +23,17 @@ pub fn encode_varint64(mut value: u64, buf: &mut [u8]) -> usize { /// Encode u32 value as varint. /// Panics if buffer length is less than 5. #[inline] -pub fn encode_varint32(mut value: u32, buf: &mut [u8]) -> usize { +pub fn encode_varint32(mut value: u32, buf: &mut [MaybeUninit<u8>]) -> usize { assert!(buf.len() >= 5); unsafe { let mut i = 0; while (value & !0x7F) > 0 { - *buf.get_unchecked_mut(i) = ((value & 0x7F) | 0x80) as u8; + maybe_uninit_write(buf.get_unchecked_mut(i), ((value & 0x7F) | 0x80) as u8); value >>= 7; i += 1; } - *buf.get_unchecked_mut(i) = value as u8; + maybe_uninit_write(buf.get_unchecked_mut(i), value as u8); i + 1 } } diff --git a/src/well_known_types/any.rs b/src/well_known_types/any.rs index f306202..e46065f 100644 --- a/src/well_known_types/any.rs +++ b/src/well_known_types/any.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/api.rs b/src/well_known_types/api.rs index 34798b4..ef97015 100644 --- a/src/well_known_types/api.rs +++ b/src/well_known_types/api.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/duration.rs b/src/well_known_types/duration.rs index ec82f78..822061a 100644 --- a/src/well_known_types/duration.rs +++ b/src/well_known_types/duration.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/empty.rs b/src/well_known_types/empty.rs index 5c69487..d55e517 100644 --- a/src/well_known_types/empty.rs +++ b/src/well_known_types/empty.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/field_mask.rs b/src/well_known_types/field_mask.rs index 9d1f8f6..e98eb53 100644 --- a/src/well_known_types/field_mask.rs +++ b/src/well_known_types/field_mask.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/source_context.rs b/src/well_known_types/source_context.rs index 55c1ab4..646e87d 100644 --- a/src/well_known_types/source_context.rs +++ b/src/well_known_types/source_context.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/struct_pb.rs b/src/well_known_types/struct_pb.rs index 222d712..5f18a42 100644 --- a/src/well_known_types/struct_pb.rs +++ b/src/well_known_types/struct_pb.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/timestamp.rs b/src/well_known_types/timestamp.rs index d0f7903..25e7acf 100644 --- a/src/well_known_types/timestamp.rs +++ b/src/well_known_types/timestamp.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/type_pb.rs b/src/well_known_types/type_pb.rs index d6c06cc..14bfdb2 100644 --- a/src/well_known_types/type_pb.rs +++ b/src/well_known_types/type_pb.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 diff --git a/src/well_known_types/wrappers.rs b/src/well_known_types/wrappers.rs index 11edf4c..4e056c7 100644 --- a/src/well_known_types/wrappers.rs +++ b/src/well_known_types/wrappers.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 2.22.0. Do not edit +// This file is generated by rust-protobuf 2.26.0. Do not edit // @generated // https://github.com/rust-lang/rust-clippy/issues/702 |