diff -Nru rust-prost-types-0.12.6/Cargo.toml rust-prost-types-0.13.5/Cargo.toml --- rust-prost-types-0.12.6/Cargo.toml 1970-01-01 00:00:01.000000000 +0000 +++ rust-prost-types-0.13.5/Cargo.toml 1970-01-01 00:00:01.000000000 +0000 @@ -11,32 +11,50 @@ [package] edition = "2021" -rust-version = "1.70" +rust-version = "1.71.1" name = "prost-types" -version = "0.12.6" +version = "0.13.5" authors = [ "Dan Burkert ", "Lucio Franco ", "Casper Meijn ", "Tokio Contributors ", ] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false description = "Prost definitions of Protocol Buffers well known types." -documentation = "https://docs.rs/prost-types" readme = "README.md" license = "Apache-2.0" repository = "https://github.com/tokio-rs/prost" +[features] +arbitrary = ["dep:arbitrary"] +default = ["std"] +std = ["prost/std"] + [lib] +name = "prost_types" +path = "src/lib.rs" doctest = false +[dependencies.arbitrary] +version = "1.4" +features = ["derive"] +optional = true + [dependencies.prost] -version = "0.12.6" +version = "0.13.5" features = ["prost-derive"] default-features = false [dev-dependencies.proptest] version = "1" -[features] -default = ["std"] -std = ["prost/std"] +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(kani)"] diff -Nru rust-prost-types-0.12.6/Cargo.toml.orig rust-prost-types-0.13.5/Cargo.toml.orig --- rust-prost-types-0.12.6/Cargo.toml.orig 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/Cargo.toml.orig 2006-07-24 01:21:28.000000000 +0000 @@ -1,19 +1,13 @@ [package] name = "prost-types" -version = "0.12.6" -authors = [ - "Dan Burkert ", - "Lucio Franco ", - "Casper Meijn ", - "Tokio Contributors ", -] -license = "Apache-2.0" -repository = "https://github.com/tokio-rs/prost" -documentation = "https://docs.rs/prost-types" readme = "README.md" description = "Prost definitions of Protocol Buffers well known types." -edition = "2021" -rust-version = "1.70" +version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +edition.workspace = true +rust-version.workspace = true [lib] doctest = false @@ -21,9 +15,14 @@ [features] default = ["std"] std = ["prost/std"] +arbitrary = ["dep:arbitrary"] [dependencies] -prost = { version = "0.12.6", path = "../prost", default-features = false, features = ["prost-derive"] } +prost = { version = "0.13.5", path = "../prost", default-features = false, features = ["prost-derive"] } +arbitrary = { version = "1.4", features = ["derive"], optional = true } [dev-dependencies] proptest = "1" + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(kani)'] } diff -Nru rust-prost-types-0.12.6/.cargo_vcs_info.json rust-prost-types-0.13.5/.cargo_vcs_info.json --- rust-prost-types-0.12.6/.cargo_vcs_info.json 1970-01-01 00:00:01.000000000 +0000 +++ rust-prost-types-0.13.5/.cargo_vcs_info.json 1970-01-01 00:00:01.000000000 +0000 @@ -1,6 +1,6 @@ { "git": { - "sha1": "d42c85e790263f78f6c626ceb0dac5fda0edcb41" + "sha1": "d505b184e933e1f9ff5679106ffc51b7e3c2755e" }, "path_in_vcs": "prost-types" } \ No newline at end of file diff -Nru rust-prost-types-0.12.6/debian/cargo-checksum.json rust-prost-types-0.13.5/debian/cargo-checksum.json --- rust-prost-types-0.12.6/debian/cargo-checksum.json 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/cargo-checksum.json 2025-04-10 11:55:37.000000000 +0000 @@ -1 +1 @@ -{"package":"9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0","files":{}} +{"package":"Could not get crate checksum","files":{}} diff -Nru rust-prost-types-0.12.6/debian/changelog rust-prost-types-0.13.5/debian/changelog --- rust-prost-types-0.12.6/debian/changelog 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/changelog 2025-04-10 11:55:37.000000000 +0000 @@ -1,3 +1,10 @@ +rust-prost-types (0.13.5-1) UNRELEASED-FIXME-AUTOGENERATED-DEBCARGO; urgency=medium + + * Team upload. + * Package prost-types 0.13.5 from crates.io using debcargo 2.7.8 + + -- Blair Noctis Thu, 10 Apr 2025 11:55:37 +0000 + rust-prost-types (0.12.6-1) unstable; urgency=medium * Team upload. diff -Nru rust-prost-types-0.12.6/debian/compat rust-prost-types-0.13.5/debian/compat --- rust-prost-types-0.12.6/debian/compat 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -12 diff -Nru rust-prost-types-0.12.6/debian/control rust-prost-types-0.13.5/debian/control --- rust-prost-types-0.12.6/debian/control 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/control 2025-04-10 11:55:37.000000000 +0000 @@ -1,19 +1,20 @@ Source: rust-prost-types Section: rust Priority: optional -Build-Depends: debhelper (>= 12), - dh-cargo (>= 25), - cargo:native , - rustc:native (>= 1.70) , +Build-Depends: debhelper-compat (= 13), + dh-sequence-cargo +Build-Depends-Arch: cargo:native , + rustc:native (>= 1.71.1) , libstd-rust-dev , - librust-prost-0.12+prost-derive-dev (>= 0.12.6-~~) , - librust-prost-0.12+std-dev (>= 0.12.6-~~) + librust-prost-0.13+prost-derive-dev (>= 0.13.5-~~) , + librust-prost-0.13+std-dev (>= 0.13.5-~~) Maintainer: Debian Rust Maintainers Uploaders: Emanuele Rocca -Standards-Version: 4.6.2 +Standards-Version: 4.7.0 Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/prost-types] Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/prost-types +Homepage: https://github.com/tokio-rs/prost X-Cargo-Crate: prost-types Rules-Requires-Root: no @@ -22,19 +23,25 @@ Multi-Arch: same Depends: ${misc:Depends}, - librust-prost-0.12+prost-derive-dev (>= 0.12.6-~~), - librust-prost-0.12+std-dev (>= 0.12.6-~~) + librust-arbitrary-1+default-dev (>= 1.4-~~), + librust-arbitrary-1+derive-dev (>= 1.4-~~), + librust-prost-0.13+prost-derive-dev (>= 0.13.5-~~), + librust-prost-0.13+std-dev (>= 0.13.5-~~) Provides: + librust-prost-types+arbitrary-dev (= ${binary:Version}), librust-prost-types+default-dev (= ${binary:Version}), librust-prost-types+std-dev (= ${binary:Version}), librust-prost-types-0-dev (= ${binary:Version}), + librust-prost-types-0+arbitrary-dev (= ${binary:Version}), librust-prost-types-0+default-dev (= ${binary:Version}), librust-prost-types-0+std-dev (= ${binary:Version}), - librust-prost-types-0.12-dev (= ${binary:Version}), - librust-prost-types-0.12+default-dev (= ${binary:Version}), - librust-prost-types-0.12+std-dev (= ${binary:Version}), - librust-prost-types-0.12.6-dev (= ${binary:Version}), - librust-prost-types-0.12.6+default-dev (= ${binary:Version}), - librust-prost-types-0.12.6+std-dev (= ${binary:Version}) + librust-prost-types-0.13-dev (= ${binary:Version}), + librust-prost-types-0.13+arbitrary-dev (= ${binary:Version}), + librust-prost-types-0.13+default-dev (= ${binary:Version}), + librust-prost-types-0.13+std-dev (= ${binary:Version}), + librust-prost-types-0.13.5-dev (= ${binary:Version}), + librust-prost-types-0.13.5+arbitrary-dev (= ${binary:Version}), + librust-prost-types-0.13.5+default-dev (= ${binary:Version}), + librust-prost-types-0.13.5+std-dev (= ${binary:Version}) Description: Prost definitions of Protocol Buffers well known types - Rust source code Source code for Debianized Rust crate "prost-types" diff -Nru rust-prost-types-0.12.6/debian/copyright.debcargo.hint rust-prost-types-0.13.5/debian/copyright.debcargo.hint --- rust-prost-types-0.12.6/debian/copyright.debcargo.hint 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/copyright.debcargo.hint 2025-04-10 11:55:37.000000000 +0000 @@ -29,8 +29,8 @@ Files: debian/* Copyright: - 2023-2024 Debian Rust Maintainers - 2023-2024 Emanuele Rocca + 2023-2025 Debian Rust Maintainers + 2023-2025 Emanuele Rocca License: Apache-2.0 License: Apache-2.0 diff -Nru rust-prost-types-0.12.6/debian/patches/fix-feature-gates.patch rust-prost-types-0.13.5/debian/patches/fix-feature-gates.patch --- rust-prost-types-0.12.6/debian/patches/fix-feature-gates.patch 1970-01-01 00:00:00.000000000 +0000 +++ rust-prost-types-0.13.5/debian/patches/fix-feature-gates.patch 2025-04-10 11:55:37.000000000 +0000 @@ -0,0 +1,22 @@ +Description: Fix the arbitrary feature so it can find std + With a wave of errors like this: + . + error[E0433]: failed to resolve: could not find `std` in the list of imported crates + --> src/protobuf.rs:107:42 + | + 107 | #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + | ^^^^^^^^^^^^^^^^^^^^ could not find `std` in the list + of imported crates + | + = note: this error originates in the derive macro `arbitrary::Arbitrary` (in Nightly builds, run + . + it's clear that arbitrary::Arbitrary needs std. +Author: Blair Noctis +Last-Update: 2025-04-10 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -34,3 +34,3 @@ + [features] +-arbitrary = ["dep:arbitrary"] ++arbitrary = ["dep:arbitrary", "std"] + default = ["std"] diff -Nru rust-prost-types-0.12.6/debian/patches/series rust-prost-types-0.13.5/debian/patches/series --- rust-prost-types-0.12.6/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ rust-prost-types-0.13.5/debian/patches/series 2025-04-10 11:55:37.000000000 +0000 @@ -0,0 +1 @@ +fix-feature-gates.patch diff -Nru rust-prost-types-0.12.6/debian/tests/control rust-prost-types-0.13.5/debian/tests/control --- rust-prost-types-0.12.6/debian/tests/control 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/tests/control 2025-04-10 11:55:37.000000000 +0000 @@ -1,19 +1,24 @@ -Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.12.6 --all-targets --all-features +Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.13.5 --all-targets --all-features Features: test-name=rust-prost-types:@ -Depends: dh-cargo (>= 18), librust-proptest-1+default-dev, @ +Depends: dh-cargo (>= 31), rustc (>= 1.71.1), librust-proptest-1+default-dev, @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.12.6 --all-targets +Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.13.5 --all-targets --no-default-features --features arbitrary +Features: test-name=librust-prost-types-dev:arbitrary +Depends: dh-cargo (>= 31), rustc (>= 1.71.1), librust-proptest-1+default-dev, @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.13.5 --all-targets Features: test-name=librust-prost-types-dev:default -Depends: dh-cargo (>= 18), librust-proptest-1+default-dev, @ +Depends: dh-cargo (>= 31), rustc (>= 1.71.1), librust-proptest-1+default-dev, @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.12.6 --all-targets --no-default-features --features std +Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.13.5 --all-targets --no-default-features --features std Features: test-name=librust-prost-types-dev:std -Depends: dh-cargo (>= 18), librust-proptest-1+default-dev, @ +Depends: dh-cargo (>= 31), rustc (>= 1.71.1), librust-proptest-1+default-dev, @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.12.6 --all-targets --no-default-features +Test-Command: /usr/share/cargo/bin/cargo-auto-test prost-types 0.13.5 --all-targets --no-default-features Features: test-name=librust-prost-types-dev: -Depends: dh-cargo (>= 18), librust-proptest-1+default-dev, @ +Depends: dh-cargo (>= 31), rustc (>= 1.71.1), librust-proptest-1+default-dev, @ Restrictions: allow-stderr, skip-not-installable diff -Nru rust-prost-types-0.12.6/debian/watch rust-prost-types-0.13.5/debian/watch --- rust-prost-types-0.12.6/debian/watch 2024-07-05 12:47:46.000000000 +0000 +++ rust-prost-types-0.13.5/debian/watch 2025-04-10 11:55:37.000000000 +0000 @@ -1,4 +1,4 @@ version=4 opts=filenamemangle=s/.*\/(.*)\/download/prost-types-$1\.tar\.gz/g,\ -uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\.?\d*)$/$1~$2/ \ https://qa.debian.org/cgi-bin/fakeupstream.cgi?upstream=crates.io/prost-types .*/crates/prost-types/@ANY_VERSION@/download diff -Nru rust-prost-types-0.12.6/README.md rust-prost-types-0.13.5/README.md --- rust-prost-types-0.12.6/README.md 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/README.md 2006-07-24 01:21:28.000000000 +0000 @@ -11,7 +11,7 @@ ## License `prost-types` is distributed under the terms of the Apache License (Version 2.0). -`prost-types` includes code imported from the Protocol Buffers projet, which is +`prost-types` includes code imported from the Protocol Buffers project, which is included under its original ([BSD][2]) license. [2]: https://github.com/google/protobuf/blob/master/LICENSE diff -Nru rust-prost-types-0.12.6/src/compiler.rs rust-prost-types-0.13.5/src/compiler.rs --- rust-prost-types-0.12.6/src/compiler.rs 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/src/compiler.rs 2006-07-24 01:21:28.000000000 +0000 @@ -1,6 +1,6 @@ // This file is @generated by prost-build. /// The version number of protocol compiler. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Version { #[prost(int32, optional, tag = "1")] @@ -15,7 +15,7 @@ pub suffix: ::core::option::Option<::prost::alloc::string::String>, } /// An encoded CodeGeneratorRequest is written to the plugin's stdin. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CodeGeneratorRequest { /// The .proto files that were explicitly listed on the command-line. The @@ -47,7 +47,7 @@ pub compiler_version: ::core::option::Option, } /// The plugin writes an encoded CodeGeneratorResponse to stdout. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CodeGeneratorResponse { /// Error message. If non-empty, code generation failed. The plugin process @@ -70,7 +70,7 @@ /// Nested message and enum types in `CodeGeneratorResponse`. pub mod code_generator_response { /// Represents a single generated file. - #[allow(clippy::derive_partial_eq_without_eq)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct File { /// The file name, relative to the output directory. The name must not @@ -135,6 +135,7 @@ pub generated_code_info: ::core::option::Option, } /// Sync with code_generator.h. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -158,8 +159,8 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Feature::None => "FEATURE_NONE", - Feature::Proto3Optional => "FEATURE_PROTO3_OPTIONAL", + Self::None => "FEATURE_NONE", + Self::Proto3Optional => "FEATURE_PROTO3_OPTIONAL", } } /// Creates an enum from field names used in the ProtoBuf definition. diff -Nru rust-prost-types-0.12.6/src/conversions.rs rust-prost-types-0.13.5/src/conversions.rs --- rust-prost-types-0.12.6/src/conversions.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-prost-types-0.13.5/src/conversions.rs 2006-07-24 01:21:28.000000000 +0000 @@ -0,0 +1,62 @@ +use crate::protobuf::Value; +use crate::value; +use crate::String; +use crate::Vec; +use ::prost::alloc::collections::BTreeMap; + +impl From for Value { + fn from(value: value::Kind) -> Self { + Value { kind: Some(value) } + } +} + +macro_rules! impl_number_value { + ($t: ty) => { + impl From<$t> for Value { + fn from(value: $t) -> Self { + value::Kind::NumberValue(value.into()).into() + } + } + }; +} + +impl_number_value!(u8); +impl_number_value!(u16); +impl_number_value!(u32); + +impl_number_value!(i8); +impl_number_value!(i16); +impl_number_value!(i32); + +impl_number_value!(f32); +impl_number_value!(f64); + +impl From for Value { + fn from(value: bool) -> Self { + value::Kind::BoolValue(value).into() + } +} + +impl From for Value { + fn from(value: String) -> Self { + value::Kind::StringValue(value).into() + } +} + +impl From<&str> for Value { + fn from(value: &str) -> Self { + value::Kind::StringValue(value.into()).into() + } +} + +impl From> for Value { + fn from(value: Vec) -> Self { + value::Kind::ListValue(crate::protobuf::ListValue { values: value }).into() + } +} + +impl From> for Value { + fn from(value: BTreeMap) -> Self { + value::Kind::StructValue(crate::protobuf::Struct { fields: value }).into() + } +} diff -Nru rust-prost-types-0.12.6/src/datetime.rs rust-prost-types-0.13.5/src/datetime.rs --- rust-prost-types-0.12.6/src/datetime.rs 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/src/datetime.rs 2006-07-24 01:21:28.000000000 +0000 @@ -5,6 +5,7 @@ use crate::Duration; use crate::Timestamp; +use crate::TimestampError; /// A point in time, represented as a date and time in the UTC timezone. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -260,8 +261,10 @@ // Parse the nanoseconds, if present. let (nanos, s) = if let Some(s) = parse_char(s, b'.') { - let (digits, s) = parse_digits(s); - ensure!(digits.len() <= 9); + let (mut digits, s) = parse_digits(s); + if digits.len() > 9 { + digits = digits.split_at(9).0; + } let nanos = 10u32.pow(9 - digits.len() as u32) * digits.parse::().ok()?; (nanos, s) } else { @@ -307,9 +310,6 @@ (minute, s) }; - // '-00:00' indicates an unknown local offset. - ensure!(is_positive || hour > 0 || minute > 0); - ensure!(hour < 24 && minute < 60); let hour = hour as i8; @@ -327,7 +327,12 @@ /// string. fn parse_two_digit_numeric(s: &str) -> Option<(u8, &str)> { debug_assert!(s.is_ascii()); - + if s.len() < 2 { + return None; + } + if s.starts_with('+') { + return None; + } let (digits, s) = s.split_at(2); Some((digits.parse().ok()?, s)) } @@ -420,8 +425,8 @@ let is_leap; let year = year - 1900; - // Fast path for years 1900 - 2038. - if year as u64 <= 138 { + // Fast path for years 1901 - 2038. + if (1..=138).contains(&year) { let mut leaps: i64 = (year - 68) >> 2; if (year - 68).trailing_zeros() >= 2 { leaps -= 1; @@ -497,9 +502,7 @@ ..DateTime::default() }; - ensure!(date_time.is_valid()); - - return Some(Timestamp::from(date_time)); + return Timestamp::try_from(date_time).ok(); } // Accept either 'T' or ' ' as delimiter between date and time. @@ -529,9 +532,7 @@ nanos, }; - ensure!(date_time.is_valid()); - - let Timestamp { seconds, nanos } = Timestamp::from(date_time); + let Timestamp { seconds, nanos } = Timestamp::try_from(date_time).ok()?; let seconds = seconds.checked_sub(i64::from(offset_hour) * 3600 + i64::from(offset_minute) * 60)?; @@ -570,14 +571,19 @@ Some(Duration { seconds, nanos }) } -impl From for Timestamp { - fn from(date_time: DateTime) -> Timestamp { +impl TryFrom for Timestamp { + type Error = TimestampError; + + fn try_from(date_time: DateTime) -> Result { + if !date_time.is_valid() { + return Err(TimestampError::InvalidDateTime); + } let seconds = date_time_to_seconds(&date_time); let nanos = date_time.nanos; - Timestamp { + Ok(Timestamp { seconds, nanos: nanos as i32, - } + }) } } @@ -585,6 +591,7 @@ mod tests { use super::*; use proptest::prelude::*; + use prost::alloc::format; #[test] fn test_min_max() { @@ -614,7 +621,7 @@ }; assert_eq!( expected, - format!("{}", DateTime::from(timestamp.clone())), + format!("{}", DateTime::from(timestamp)), "timestamp: {:?}", timestamp ); @@ -729,8 +736,8 @@ // Leap day assert_eq!( - "2020-02-29T01:02:03.00Z".parse::().unwrap(), - Timestamp::from(DateTime { + "2020-02-29T01:02:03.00Z".parse::(), + Timestamp::try_from(DateTime { year: 2020, month: 2, day: 29, @@ -738,7 +745,7 @@ minute: 2, second: 3, nanos: 0, - }), + }) ); // Test extensions to RFC 3339. @@ -769,6 +776,30 @@ "2020-06-15 00:01:02.123 +0800".parse::(), Timestamp::date_time_nanos(2020, 6, 14, 16, 1, 2, 123_000_000), ); + + // Regression tests + assert_eq!( + "-11111111-z".parse::(), + Err(crate::TimestampError::ParseFailure), + ); + assert_eq!( + "1900-01-10".parse::(), + Ok(Timestamp { + seconds: -2208211200, + nanos: 0 + }), + ); + // Leading '+' in two-digit numbers + assert_eq!( + "19+1-+2-+3T+4:+5:+6Z".parse::(), + Err(crate::TimestampError::ParseFailure), + ); + + // Very long seconds fraction + assert_eq!( + "1343-08-16 18:33:44.1666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666660404z".parse::(), + Timestamp::date_time_nanos(1343, 8, 16, 18, 33, 44, 166_666_666), + ); } #[test] @@ -829,6 +860,94 @@ assert!("1️⃣s".parse::().is_err()); } + #[test] + fn check_invalid_datetimes() { + assert_eq!( + Timestamp::try_from(DateTime { + year: i64::from_le_bytes([178, 2, 0, 0, 0, 0, 0, 128]), + month: 2, + day: 2, + hour: 8, + minute: 58, + second: 8, + nanos: u32::from_le_bytes([0, 0, 0, 50]), + }), + Err(TimestampError::InvalidDateTime) + ); + assert_eq!( + Timestamp::try_from(DateTime { + year: i64::from_le_bytes([132, 7, 0, 0, 0, 0, 0, 128]), + month: 2, + day: 2, + hour: 8, + minute: 58, + second: 8, + nanos: u32::from_le_bytes([0, 0, 0, 50]), + }), + Err(TimestampError::InvalidDateTime) + ); + assert_eq!( + Timestamp::try_from(DateTime { + year: i64::from_le_bytes([80, 96, 32, 240, 99, 0, 32, 180]), + month: 1, + day: 18, + hour: 19, + minute: 26, + second: 8, + nanos: u32::from_le_bytes([0, 0, 0, 50]), + }), + Err(TimestampError::InvalidDateTime) + ); + assert_eq!( + Timestamp::try_from(DateTime { + year: DateTime::MIN.year - 1, + month: 0, + day: 0, + hour: 0, + minute: 0, + second: 0, + nanos: 0, + }), + Err(TimestampError::InvalidDateTime) + ); + assert_eq!( + Timestamp::try_from(DateTime { + year: i64::MIN, + month: 0, + day: 0, + hour: 0, + minute: 0, + second: 0, + nanos: 0, + }), + Err(TimestampError::InvalidDateTime) + ); + assert_eq!( + Timestamp::try_from(DateTime { + year: DateTime::MAX.year + 1, + month: u8::MAX, + day: u8::MAX, + hour: u8::MAX, + minute: u8::MAX, + second: u8::MAX, + nanos: u32::MAX, + }), + Err(TimestampError::InvalidDateTime) + ); + assert_eq!( + Timestamp::try_from(DateTime { + year: i64::MAX, + month: u8::MAX, + day: u8::MAX, + hour: u8::MAX, + minute: u8::MAX, + second: u8::MAX, + nanos: u32::MAX, + }), + Err(TimestampError::InvalidDateTime) + ); + } + proptest! { #[cfg(feature = "std")] #[test] @@ -860,5 +979,47 @@ "{}", duration.to_string() ); } + + #[test] + fn check_timestamp_roundtrip_with_date_time( + seconds in i64::arbitrary(), + nanos in i32::arbitrary(), + ) { + let timestamp = Timestamp { seconds, nanos }; + let date_time = DateTime::from(timestamp); + let roundtrip = Timestamp::try_from(date_time).unwrap(); + + prop_assert_eq!(timestamp.normalized(), roundtrip); + } + + #[test] + fn check_date_time_roundtrip_with_timestamp( + year in i64::arbitrary(), + month in u8::arbitrary(), + day in u8::arbitrary(), + hour in u8::arbitrary(), + minute in u8::arbitrary(), + second in u8::arbitrary(), + nanos in u32::arbitrary(), + ) { + let date_time = DateTime { + year, + month, + day, + hour, + minute, + second, + nanos + }; + + if date_time.is_valid() { + let timestamp = Timestamp::try_from(date_time).unwrap(); + let roundtrip = DateTime::from(timestamp); + + prop_assert_eq!(date_time, roundtrip); + } else { + prop_assert_eq!(Timestamp::try_from(date_time), Err(TimestampError::InvalidDateTime)); + } + } } } diff -Nru rust-prost-types-0.12.6/src/duration.rs rust-prost-types-0.13.5/src/duration.rs --- rust-prost-types-0.12.6/src/duration.rs 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/src/duration.rs 2006-07-24 01:21:28.000000000 +0000 @@ -58,6 +58,17 @@ // debug_assert!(self.seconds >= -315_576_000_000 && self.seconds <= 315_576_000_000, // "invalid duration: {:?}", self); } + + /// Returns a normalized copy of the duration to a canonical format. + /// + /// Based on [`google::protobuf::util::CreateNormalized`][1]. + /// + /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L79-L100 + pub fn normalized(&self) -> Self { + let mut result = *self; + result.normalize(); + result + } } impl Name for Duration { @@ -77,9 +88,8 @@ let seconds = i64::try_from(duration.as_secs()).map_err(|_| DurationError::OutOfRange)?; let nanos = duration.subsec_nanos() as i32; - let mut duration = Duration { seconds, nanos }; - duration.normalize(); - Ok(duration) + let duration = Duration { seconds, nanos }; + Ok(duration.normalized()) } } @@ -105,9 +115,8 @@ impl fmt::Display for Duration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut d = self.clone(); - d.normalize(); - if self.seconds < 0 && self.nanos < 0 { + let d = self.normalized(); + if self.seconds < 0 || self.nanos < 0 { write!(f, "-")?; } write!(f, "{}", d.seconds.abs())?; @@ -127,7 +136,6 @@ } /// A duration handling error. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Debug, PartialEq)] #[non_exhaustive] pub enum DurationError { @@ -174,68 +182,163 @@ datetime::parse_duration(s).ok_or(DurationError::ParseFailure) } } -#[cfg(test)] -mod tests { + +#[cfg(kani)] +mod proofs { use super::*; #[cfg(feature = "std")] - use proptest::prelude::*; + #[kani::proof] + fn check_duration_roundtrip() { + let seconds = kani::any(); + let nanos = kani::any(); + kani::assume(nanos < 1_000_000_000); + let std_duration = std::time::Duration::new(seconds, nanos); + let Ok(prost_duration) = Duration::try_from(std_duration) else { + // Test case not valid: duration out of range + return; + }; + assert_eq!( + time::Duration::try_from(prost_duration).unwrap(), + std_duration + ); + + if std_duration != time::Duration::default() { + let neg_prost_duration = Duration { + seconds: -prost_duration.seconds, + nanos: -prost_duration.nanos, + }; + + assert!(matches!( + time::Duration::try_from(neg_prost_duration), + Err(DurationError::NegativeDuration(d)) if d == std_duration, + )) + } + } #[cfg(feature = "std")] - proptest! { - #[test] - fn check_duration_roundtrip( - seconds in u64::arbitrary(), - nanos in 0u32..1_000_000_000u32, - ) { - let std_duration = time::Duration::new(seconds, nanos); - let prost_duration = match Duration::try_from(std_duration) { - Ok(duration) => duration, - Err(_) => return Err(TestCaseError::reject("duration out of range")), + #[kani::proof] + fn check_duration_roundtrip_nanos() { + let seconds = 0; + let nanos = kani::any(); + let std_duration = std::time::Duration::new(seconds, nanos); + let Ok(prost_duration) = Duration::try_from(std_duration) else { + // Test case not valid: duration out of range + return; + }; + assert_eq!( + time::Duration::try_from(prost_duration).unwrap(), + std_duration + ); + + if std_duration != time::Duration::default() { + let neg_prost_duration = Duration { + seconds: -prost_duration.seconds, + nanos: -prost_duration.nanos, }; - prop_assert_eq!(time::Duration::try_from(prost_duration.clone()).unwrap(), std_duration); - if std_duration != time::Duration::default() { - let neg_prost_duration = Duration { - seconds: -prost_duration.seconds, - nanos: -prost_duration.nanos, - }; - - prop_assert!( - matches!( - time::Duration::try_from(neg_prost_duration), - Err(DurationError::NegativeDuration(d)) if d == std_duration, - ) - ) - } + assert!(matches!( + time::Duration::try_from(neg_prost_duration), + Err(DurationError::NegativeDuration(d)) if d == std_duration, + )) } + } +} - #[test] - fn check_duration_roundtrip_nanos( - nanos in u32::arbitrary(), - ) { - let seconds = 0; - let std_duration = std::time::Duration::new(seconds, nanos); - let prost_duration = match Duration::try_from(std_duration) { - Ok(duration) => duration, - Err(_) => return Err(TestCaseError::reject("duration out of range")), - }; - prop_assert_eq!(time::Duration::try_from(prost_duration.clone()).unwrap(), std_duration); +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "std")] + #[test] + fn test_duration_from_str() { + assert_eq!( + Duration::from_str("0s"), + Ok(Duration { + seconds: 0, + nanos: 0 + }) + ); + assert_eq!( + Duration::from_str("123s"), + Ok(Duration { + seconds: 123, + nanos: 0 + }) + ); + assert_eq!( + Duration::from_str("0.123s"), + Ok(Duration { + seconds: 0, + nanos: 123_000_000 + }) + ); + assert_eq!( + Duration::from_str("-123s"), + Ok(Duration { + seconds: -123, + nanos: 0 + }) + ); + assert_eq!( + Duration::from_str("-0.123s"), + Ok(Duration { + seconds: 0, + nanos: -123_000_000 + }) + ); + assert_eq!( + Duration::from_str("22041211.6666666666666s"), + Ok(Duration { + seconds: 22041211, + nanos: 666_666_666 + }) + ); + } - if std_duration != time::Duration::default() { - let neg_prost_duration = Duration { - seconds: -prost_duration.seconds, - nanos: -prost_duration.nanos, - }; - - prop_assert!( - matches!( - time::Duration::try_from(neg_prost_duration), - Err(DurationError::NegativeDuration(d)) if d == std_duration, - ) - ) + #[cfg(feature = "std")] + #[test] + fn test_format_duration() { + assert_eq!( + "0s", + Duration { + seconds: 0, + nanos: 0 } - } + .to_string() + ); + assert_eq!( + "123s", + Duration { + seconds: 123, + nanos: 0 + } + .to_string() + ); + assert_eq!( + "0.123s", + Duration { + seconds: 0, + nanos: 123_000_000 + } + .to_string() + ); + assert_eq!( + "-123s", + Duration { + seconds: -123, + nanos: 0 + } + .to_string() + ); + assert_eq!( + "-0.123s", + Duration { + seconds: 0, + nanos: -123_000_000 + } + .to_string() + ); } #[cfg(feature = "std")] @@ -313,14 +416,13 @@ ]; for case in cases.iter() { - let mut test_duration = Duration { + let test_duration = Duration { seconds: case.1, nanos: case.2, }; - test_duration.normalize(); assert_eq!( - test_duration, + test_duration.normalized(), Duration { seconds: case.3, nanos: case.4, diff -Nru rust-prost-types-0.12.6/src/lib.rs rust-prost-types-0.13.5/src/lib.rs --- rust-prost-types-0.12.6/src/lib.rs 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/src/lib.rs 2006-07-24 01:21:28.000000000 +0000 @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://docs.rs/prost-types/0.12.6")] +#![doc(html_root_url = "https://docs.rs/prost-types/0.13.5")] //! Protocol Buffers well-known types. //! @@ -7,8 +7,35 @@ //! //! See the [Protobuf reference][1] for more information about well-known types. //! +//! ## Any +//! +//! The well-known [`Any`] type contains an arbitrary serialized message along with a URL that +//! describes the type of the serialized message. Every message that also implements [`Name`] +//! can be serialized to and deserialized from [`Any`]. +//! +//! ### Serialization +//! +//! A message can be serialized using [`Any::from_msg`]. +//! +//! ```rust +//! let message = Timestamp::date(2000, 1, 1).unwrap(); +//! let any = Any::from_msg(&message).unwrap(); +//! ``` +//! +//! ### Deserialization +//! +//! A message can be deserialized using [`Any::to_msg`]. +//! +//! ```rust +//! # let message = Timestamp::date(2000, 1, 1).unwrap(); +//! # let any = Any::from_msg(&message).unwrap(); +//! # +//! let message = any.to_msg::().unwrap(); +//! ``` +//! //! ## Feature Flags //! - `std`: Enable integration with standard library. Disable this feature for `no_std` support. This feature is enabled by default. +//! - `arbitrary`: Enable integration with crate `arbitrary`. All types on this crate will implement `trait Arbitrary`. //! //! [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf @@ -22,8 +49,6 @@ use core::convert::TryFrom; use core::fmt; -use core::i32; -use core::i64; use core::str::FromStr; use core::time; @@ -53,3 +78,5 @@ mod type_url; pub(crate) use type_url::{type_url_for, TypeUrl}; + +mod conversions; diff -Nru rust-prost-types-0.12.6/src/protobuf.rs rust-prost-types-0.13.5/src/protobuf.rs --- rust-prost-types-0.12.6/src/protobuf.rs 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/src/protobuf.rs 2006-07-24 01:21:28.000000000 +0000 @@ -1,14 +1,14 @@ // This file is @generated by prost-build. /// The protocol compiler can output a FileDescriptorSet containing the .proto /// files it parses. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FileDescriptorSet { #[prost(message, repeated, tag = "1")] pub file: ::prost::alloc::vec::Vec, } /// Describes a complete .proto file. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FileDescriptorProto { /// file name, relative to root of source tree @@ -50,7 +50,7 @@ pub syntax: ::core::option::Option<::prost::alloc::string::String>, } /// Describes a message type. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct DescriptorProto { #[prost(string, optional, tag = "1")] @@ -78,7 +78,7 @@ } /// Nested message and enum types in `DescriptorProto`. pub mod descriptor_proto { - #[allow(clippy::derive_partial_eq_without_eq)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExtensionRange { /// Inclusive. @@ -93,8 +93,8 @@ /// Range of reserved tag numbers. Reserved tag numbers may not be used by /// fields or extension ranges in the same message. Reserved ranges may /// not overlap. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ReservedRange { /// Inclusive. #[prost(int32, optional, tag = "1")] @@ -104,7 +104,7 @@ pub end: ::core::option::Option, } } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExtensionRangeOptions { /// The parser stores options it doesn't recognize here. See above. @@ -112,7 +112,7 @@ pub uninterpreted_option: ::prost::alloc::vec::Vec, } /// Describes a field within a message. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FieldDescriptorProto { #[prost(string, optional, tag = "1")] @@ -181,6 +181,7 @@ } /// Nested message and enum types in `FieldDescriptorProto`. pub mod field_descriptor_proto { + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -234,24 +235,24 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Type::Double => "TYPE_DOUBLE", - Type::Float => "TYPE_FLOAT", - Type::Int64 => "TYPE_INT64", - Type::Uint64 => "TYPE_UINT64", - Type::Int32 => "TYPE_INT32", - Type::Fixed64 => "TYPE_FIXED64", - Type::Fixed32 => "TYPE_FIXED32", - Type::Bool => "TYPE_BOOL", - Type::String => "TYPE_STRING", - Type::Group => "TYPE_GROUP", - Type::Message => "TYPE_MESSAGE", - Type::Bytes => "TYPE_BYTES", - Type::Uint32 => "TYPE_UINT32", - Type::Enum => "TYPE_ENUM", - Type::Sfixed32 => "TYPE_SFIXED32", - Type::Sfixed64 => "TYPE_SFIXED64", - Type::Sint32 => "TYPE_SINT32", - Type::Sint64 => "TYPE_SINT64", + Self::Double => "TYPE_DOUBLE", + Self::Float => "TYPE_FLOAT", + Self::Int64 => "TYPE_INT64", + Self::Uint64 => "TYPE_UINT64", + Self::Int32 => "TYPE_INT32", + Self::Fixed64 => "TYPE_FIXED64", + Self::Fixed32 => "TYPE_FIXED32", + Self::Bool => "TYPE_BOOL", + Self::String => "TYPE_STRING", + Self::Group => "TYPE_GROUP", + Self::Message => "TYPE_MESSAGE", + Self::Bytes => "TYPE_BYTES", + Self::Uint32 => "TYPE_UINT32", + Self::Enum => "TYPE_ENUM", + Self::Sfixed32 => "TYPE_SFIXED32", + Self::Sfixed64 => "TYPE_SFIXED64", + Self::Sint32 => "TYPE_SINT32", + Self::Sint64 => "TYPE_SINT64", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -279,6 +280,7 @@ } } } + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -304,9 +306,9 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Label::Optional => "LABEL_OPTIONAL", - Label::Required => "LABEL_REQUIRED", - Label::Repeated => "LABEL_REPEATED", + Self::Optional => "LABEL_OPTIONAL", + Self::Required => "LABEL_REQUIRED", + Self::Repeated => "LABEL_REPEATED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -321,7 +323,7 @@ } } /// Describes a oneof. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OneofDescriptorProto { #[prost(string, optional, tag = "1")] @@ -330,7 +332,7 @@ pub options: ::core::option::Option, } /// Describes an enum type. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EnumDescriptorProto { #[prost(string, optional, tag = "1")] @@ -359,8 +361,8 @@ /// Note that this is distinct from DescriptorProto.ReservedRange in that it /// is inclusive such that it can appropriately represent the entire int32 /// domain. - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] + #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct EnumReservedRange { /// Inclusive. #[prost(int32, optional, tag = "1")] @@ -371,7 +373,7 @@ } } /// Describes a value within an enum. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EnumValueDescriptorProto { #[prost(string, optional, tag = "1")] @@ -382,7 +384,7 @@ pub options: ::core::option::Option, } /// Describes a service. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ServiceDescriptorProto { #[prost(string, optional, tag = "1")] @@ -393,7 +395,7 @@ pub options: ::core::option::Option, } /// Describes a method of a service. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MethodDescriptorProto { #[prost(string, optional, tag = "1")] @@ -442,7 +444,7 @@ /// /// If this turns out to be popular, a web service will be set up /// to automatically assign option numbers. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FileOptions { /// Sets the Java package where classes generated from this .proto will be @@ -561,6 +563,7 @@ /// Nested message and enum types in `FileOptions`. pub mod file_options { /// Generated classes can be optimized for speed or code size. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -590,9 +593,9 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - OptimizeMode::Speed => "SPEED", - OptimizeMode::CodeSize => "CODE_SIZE", - OptimizeMode::LiteRuntime => "LITE_RUNTIME", + Self::Speed => "SPEED", + Self::CodeSize => "CODE_SIZE", + Self::LiteRuntime => "LITE_RUNTIME", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -606,7 +609,7 @@ } } } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MessageOptions { /// Set true to use the old proto1 MessageSet wire format for extensions. @@ -667,7 +670,7 @@ #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FieldOptions { /// The ctype option instructs the C++ code generator to use a different @@ -750,6 +753,7 @@ } /// Nested message and enum types in `FieldOptions`. pub mod field_options { + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -775,9 +779,9 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - CType::String => "STRING", - CType::Cord => "CORD", - CType::StringPiece => "STRING_PIECE", + Self::String => "STRING", + Self::Cord => "CORD", + Self::StringPiece => "STRING_PIECE", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -790,6 +794,7 @@ } } } + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -817,9 +822,9 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - JsType::JsNormal => "JS_NORMAL", - JsType::JsString => "JS_STRING", - JsType::JsNumber => "JS_NUMBER", + Self::JsNormal => "JS_NORMAL", + Self::JsString => "JS_STRING", + Self::JsNumber => "JS_NUMBER", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -833,14 +838,14 @@ } } } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OneofOptions { /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EnumOptions { /// Set this option to true to allow mapping different tag names to the same @@ -857,7 +862,7 @@ #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EnumValueOptions { /// Is this enum value deprecated? @@ -870,7 +875,7 @@ #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ServiceOptions { /// Is this service deprecated? @@ -883,7 +888,7 @@ #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MethodOptions { /// Is this method deprecated? @@ -908,6 +913,7 @@ /// 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. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -934,9 +940,9 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - IdempotencyLevel::IdempotencyUnknown => "IDEMPOTENCY_UNKNOWN", - IdempotencyLevel::NoSideEffects => "NO_SIDE_EFFECTS", - IdempotencyLevel::Idempotent => "IDEMPOTENT", + Self::IdempotencyUnknown => "IDEMPOTENCY_UNKNOWN", + Self::NoSideEffects => "NO_SIDE_EFFECTS", + Self::Idempotent => "IDEMPOTENT", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -956,7 +962,7 @@ /// options protos in descriptor objects (e.g. returned by Descriptor::options(), /// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions /// in them. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UninterpretedOption { #[prost(message, repeated, tag = "2")] @@ -983,7 +989,7 @@ /// extension (denoted with parentheses in options specs in .proto files). /// E.g.,{ \["foo", false\], \["bar.baz", true\], \["qux", false\] } represents /// "foo.(bar.baz).qux". - #[allow(clippy::derive_partial_eq_without_eq)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct NamePart { #[prost(string, required, tag = "1")] @@ -994,7 +1000,7 @@ } /// Encapsulates information about the original source file from which a /// FileDescriptorProto was generated. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SourceCodeInfo { /// A Location identifies a piece of source code in a .proto file which @@ -1046,7 +1052,7 @@ } /// Nested message and enum types in `SourceCodeInfo`. pub mod source_code_info { - #[allow(clippy::derive_partial_eq_without_eq)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Location { /// Identifies which part of the FileDescriptorProto was defined at this @@ -1141,7 +1147,7 @@ /// Describes the relationship between generated code and its original source /// file. A GeneratedCodeInfo message is associated with only one generated /// source file, but may contain references to different source .proto files. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GeneratedCodeInfo { /// An Annotation connects some span of text in generated code to an element @@ -1151,7 +1157,7 @@ } /// Nested message and enum types in `GeneratedCodeInfo`. pub mod generated_code_info { - #[allow(clippy::derive_partial_eq_without_eq)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Annotation { /// Identifies the element in the original source .proto file. This field @@ -1265,7 +1271,7 @@ /// "value": "1.212s" /// } /// ``` -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Any { /// A URL/resource name that uniquely identifies the type of the serialized @@ -1303,7 +1309,7 @@ } /// `SourceContext` represents information about the source of a /// protobuf element, like the file in which it is defined. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct SourceContext { /// The path-qualified name of the .proto file that contained the associated @@ -1312,7 +1318,7 @@ pub file_name: ::prost::alloc::string::String, } /// A protocol buffer message type. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Type { /// The fully qualified message name. @@ -1335,7 +1341,7 @@ pub syntax: i32, } /// A single field of a message type. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Field { /// The field type. @@ -1374,6 +1380,7 @@ /// Nested message and enum types in `Field`. pub mod field { /// Basic field types. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -1433,25 +1440,25 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Kind::TypeUnknown => "TYPE_UNKNOWN", - Kind::TypeDouble => "TYPE_DOUBLE", - Kind::TypeFloat => "TYPE_FLOAT", - Kind::TypeInt64 => "TYPE_INT64", - Kind::TypeUint64 => "TYPE_UINT64", - Kind::TypeInt32 => "TYPE_INT32", - Kind::TypeFixed64 => "TYPE_FIXED64", - Kind::TypeFixed32 => "TYPE_FIXED32", - Kind::TypeBool => "TYPE_BOOL", - Kind::TypeString => "TYPE_STRING", - Kind::TypeGroup => "TYPE_GROUP", - Kind::TypeMessage => "TYPE_MESSAGE", - Kind::TypeBytes => "TYPE_BYTES", - Kind::TypeUint32 => "TYPE_UINT32", - Kind::TypeEnum => "TYPE_ENUM", - Kind::TypeSfixed32 => "TYPE_SFIXED32", - Kind::TypeSfixed64 => "TYPE_SFIXED64", - Kind::TypeSint32 => "TYPE_SINT32", - Kind::TypeSint64 => "TYPE_SINT64", + Self::TypeUnknown => "TYPE_UNKNOWN", + Self::TypeDouble => "TYPE_DOUBLE", + Self::TypeFloat => "TYPE_FLOAT", + Self::TypeInt64 => "TYPE_INT64", + Self::TypeUint64 => "TYPE_UINT64", + Self::TypeInt32 => "TYPE_INT32", + Self::TypeFixed64 => "TYPE_FIXED64", + Self::TypeFixed32 => "TYPE_FIXED32", + Self::TypeBool => "TYPE_BOOL", + Self::TypeString => "TYPE_STRING", + Self::TypeGroup => "TYPE_GROUP", + Self::TypeMessage => "TYPE_MESSAGE", + Self::TypeBytes => "TYPE_BYTES", + Self::TypeUint32 => "TYPE_UINT32", + Self::TypeEnum => "TYPE_ENUM", + Self::TypeSfixed32 => "TYPE_SFIXED32", + Self::TypeSfixed64 => "TYPE_SFIXED64", + Self::TypeSint32 => "TYPE_SINT32", + Self::TypeSint64 => "TYPE_SINT64", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1481,6 +1488,7 @@ } } /// Whether a field is optional, required, or repeated. + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive( Clone, Copy, @@ -1510,10 +1518,10 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Cardinality::Unknown => "CARDINALITY_UNKNOWN", - Cardinality::Optional => "CARDINALITY_OPTIONAL", - Cardinality::Required => "CARDINALITY_REQUIRED", - Cardinality::Repeated => "CARDINALITY_REPEATED", + Self::Unknown => "CARDINALITY_UNKNOWN", + Self::Optional => "CARDINALITY_OPTIONAL", + Self::Required => "CARDINALITY_REQUIRED", + Self::Repeated => "CARDINALITY_REPEATED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1529,7 +1537,7 @@ } } /// Enum type definition. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Enum { /// Enum type name. @@ -1549,7 +1557,7 @@ pub syntax: i32, } /// Enum value definition. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EnumValue { /// Enum value name. @@ -1564,7 +1572,7 @@ } /// A protocol buffer option, which can be attached to a message, field, /// enumeration, etc. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Option { /// The option's name. For protobuf built-in options (options defined in @@ -1581,6 +1589,7 @@ pub value: ::core::option::Option, } /// The syntax in which a protocol buffer element is defined. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Syntax { @@ -1596,8 +1605,8 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Syntax::Proto2 => "SYNTAX_PROTO2", - Syntax::Proto3 => "SYNTAX_PROTO3", + Self::Proto2 => "SYNTAX_PROTO2", + Self::Proto3 => "SYNTAX_PROTO3", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1618,7 +1627,7 @@ /// sometimes simply referred to as "APIs" in other contexts, such as the name of /// this message itself. See for /// detailed terminology. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Api { /// The fully qualified name of this interface, including package name @@ -1664,7 +1673,7 @@ pub syntax: i32, } /// Method represents a method of an API interface. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Method { /// The simple name of this method. @@ -1777,7 +1786,7 @@ /// ... /// } /// ``` -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Mixin { /// The fully qualified name of the interface which is included. @@ -1852,8 +1861,8 @@ /// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should /// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 /// microsecond should be expressed in JSON format as "3.000001s". -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct 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: @@ -2091,7 +2100,7 @@ /// 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. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FieldMask { /// The set of field mask paths. @@ -2106,7 +2115,7 @@ /// with the proto support for the language. /// /// The JSON representation for `Struct` is JSON object. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Struct { /// Unordered map of dynamically typed values. @@ -2122,7 +2131,7 @@ /// variants. Absence of any variant indicates an error. /// /// The JSON representation for `Value` is JSON value. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Value { /// The kind of value. @@ -2132,7 +2141,7 @@ /// Nested message and enum types in `Value`. pub mod value { /// The kind of value. - #[allow(clippy::derive_partial_eq_without_eq)] + #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Kind { /// Represents a null value. @@ -2158,7 +2167,7 @@ /// `ListValue` is a wrapper around a repeated field of values. /// /// The JSON representation for `ListValue` is JSON array. -#[allow(clippy::derive_partial_eq_without_eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListValue { /// Repeated field of dynamically typed values. @@ -2169,6 +2178,7 @@ /// `Value` type union. /// /// The JSON representation for `NullValue` is JSON `null`. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum NullValue { @@ -2182,7 +2192,7 @@ /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - NullValue::NullValue => "NULL_VALUE", + Self::NullValue => "NULL_VALUE", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -2292,8 +2302,8 @@ /// [`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 obtain a formatter capable of generating timestamps in this format. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct Timestamp { /// Represents seconds of UTC time since Unix epoch /// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to diff -Nru rust-prost-types-0.12.6/src/timestamp.rs rust-prost-types-0.13.5/src/timestamp.rs --- rust-prost-types-0.12.6/src/timestamp.rs 2006-07-24 01:21:28.000000000 +0000 +++ rust-prost-types-0.13.5/src/timestamp.rs 2006-07-24 01:21:28.000000000 +0000 @@ -50,7 +50,7 @@ /// /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77 pub fn try_normalize(mut self) -> Result { - let before = self.clone(); + let before = self; self.normalize(); // If the seconds value has changed, and is either i64::MIN or i64::MAX, then the timestamp // normalization overflowed. @@ -62,6 +62,17 @@ } } + /// Return a normalized copy of the timestamp to a canonical format. + /// + /// Based on [`google::protobuf::util::CreateNormalized`][1]. + /// + /// [1]: https://github.com/google/protobuf/blob/v3.3.2/src/google/protobuf/util/time_util.cc#L59-L77 + pub fn normalized(&self) -> Self { + let mut result = *self; + result.normalize(); + result + } + /// Creates a new `Timestamp` at the start of the provided UTC date. pub fn date(year: i64, month: u8, day: u8) -> Result { Timestamp::date_time_nanos(year, month, day, 0, 0, 0, 0) @@ -99,11 +110,7 @@ nanos, }; - if date_time.is_valid() { - Ok(Timestamp::from(date_time)) - } else { - Err(TimestampError::InvalidDateTime) - } + Timestamp::try_from(date_time) } } @@ -153,7 +160,6 @@ } /// A timestamp handling error. -#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Debug, PartialEq)] #[non_exhaustive] pub enum TimestampError { @@ -201,7 +207,7 @@ type Error = TimestampError; fn try_from(mut timestamp: Timestamp) -> Result { - let orig_timestamp = timestamp.clone(); + let orig_timestamp = timestamp; timestamp.normalize(); let system_time = if timestamp.seconds >= 0 { @@ -211,8 +217,7 @@ timestamp .seconds .checked_neg() - .ok_or_else(|| TimestampError::OutOfSystemRange(timestamp.clone()))? - as u64, + .ok_or(TimestampError::OutOfSystemRange(timestamp))? as u64, )) }; @@ -234,9 +239,30 @@ impl fmt::Display for Timestamp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - datetime::DateTime::from(self.clone()).fmt(f) + datetime::DateTime::from(*self).fmt(f) } } + +#[cfg(kani)] +mod proofs { + use super::*; + + #[cfg(feature = "std")] + #[kani::proof] + #[kani::unwind(3)] + fn check_timestamp_roundtrip_via_system_time() { + let seconds = kani::any(); + let nanos = kani::any(); + + let mut timestamp = Timestamp { seconds, nanos }; + timestamp.normalize(); + + if let Ok(system_time) = std::time::SystemTime::try_from(timestamp) { + assert_eq!(Timestamp::from(system_time), timestamp); + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -254,18 +280,6 @@ ) { prop_assert_eq!(SystemTime::try_from(Timestamp::from(system_time)).unwrap(), system_time); } - - #[test] - fn check_timestamp_roundtrip_via_system_time( - seconds in i64::arbitrary(), - nanos in i32::arbitrary(), - ) { - let mut timestamp = Timestamp { seconds, nanos }; - timestamp.normalize(); - if let Ok(system_time) = SystemTime::try_from(timestamp.clone()) { - prop_assert_eq!(Timestamp::from(system_time), timestamp); - } - } } #[cfg(feature = "std")] @@ -396,14 +410,13 @@ ]; for case in cases.iter() { - let mut test_timestamp = crate::Timestamp { + let test_timestamp = crate::Timestamp { seconds: case.1, nanos: case.2, }; - test_timestamp.normalize(); assert_eq!( - test_timestamp, + test_timestamp.normalized(), crate::Timestamp { seconds: case.3, nanos: case.4, @@ -413,4 +426,20 @@ ); } } + + #[cfg(feature = "arbitrary")] + #[test] + fn check_timestamp_implements_arbitrary() { + use arbitrary::{Arbitrary, Unstructured}; + + let mut unstructured = Unstructured::new(&[]); + + assert_eq!( + Timestamp::arbitrary(&mut unstructured), + Ok(Timestamp { + seconds: 0, + nanos: 0 + }) + ); + } }