From 660956b8d0a7a4ffad19f707756df060f2e8bea2 Mon Sep 17 00:00:00 2001 From: Tin Rabzelj Date: Tue, 14 Nov 2023 04:06:26 +0100 Subject: [PATCH] Update structure --- Cargo.toml | 37 +- bomboni/Cargo.toml | 43 -- bomboni/src/lib.rs | 17 - bomboni/src/proto/error.rs | 5 - bomboni/src/proto/google.protobuf.plus.rs | 238 +++++++ bomboni/src/proto/google.protobuf.rs | 673 ++++++++++++++++++ bomboni/src/proto/google.rpc.plus.rs | 397 +++++++++++ bomboni/src/proto/google.rpc.rs | 520 ++++++++++++++ bomboni/src/proto/google/any.rs | 157 ---- bomboni/src/proto/google/mod.rs | 17 - bomboni/src/proto/google/status.rs | 160 ----- bomboni/src/proto/mod.rs | 3 - bomboni/tests/proto/fd.pb | Bin 0 -> 1716 bytes bomboni/tests/proto/tools.command.plus.rs | 113 +++ bomboni/tests/proto/tools.command.rs | 38 + bomboni/tests/proto/tools.perms.plus.rs | 17 + bomboni/tests/proto/tools.perms.rs | 6 + bomboni/tests/proto/tools.plus.rs | 133 ++++ bomboni/tests/proto/tools.rs | 41 ++ bomboni_common/Cargo.toml | 17 + bomboni_common/src/lib.rs | 1 + .../src/macros/collections.rs | 24 +- {bomboni => bomboni_common}/src/macros/mod.rs | 3 +- bomboni_derive/Cargo.toml | 4 +- bomboni_prost/Cargo.toml | 4 +- bomboni_prost/src/enums.rs | 4 +- bomboni_prost/src/messages.rs | 10 +- bomboni_proto/Cargo.toml | 32 + {bomboni => bomboni_proto}/build.rs | 32 +- .../proto/google/api/annotations.proto | 0 .../proto/google/api/client.proto | 0 .../proto/google/api/field_behavior.proto | 0 .../proto/google/api/http.proto | 0 .../proto/google/api/httpbody.proto | 0 .../proto/google/api/resource.proto | 0 .../proto/google/protobuf/any.proto | 0 .../proto/google/protobuf/api.proto | 0 .../proto/google/protobuf/descriptor.proto | 0 .../proto/google/protobuf/duration.proto | 0 .../proto/google/protobuf/empty.proto | 0 .../proto/google/protobuf/field_mask.proto | 0 .../google/protobuf/source_context.proto | 0 .../proto/google/protobuf/struct.proto | 0 .../proto/google/protobuf/timestamp.proto | 0 .../proto/google/protobuf/type.proto | 0 .../proto/google/protobuf/wrappers.proto | 0 .../proto/google/rpc/code.proto | 0 .../proto/google/rpc/error_details.proto | 0 .../proto/google/rpc/status.proto | 0 .../proto/google/type/calendar_period.proto | 0 .../proto/google/type/color.proto | 0 .../proto/google/type/date.proto | 0 .../proto/google/type/datetime.proto | 0 .../proto/google/type/dayofweek.proto | 0 .../proto/google/type/decimal.proto | 0 .../proto/google/type/expr.proto | 0 .../proto/google/type/fraction.proto | 0 .../proto/google/type/interval.proto | 0 .../proto/google/type/latlng.proto | 0 .../proto/google/type/localized_text.proto | 0 .../proto/google/type/money.proto | 0 .../proto/google/type/month.proto | 0 .../proto/google/type/phone_number.proto | 0 .../proto/google/type/postal_address.proto | 0 .../proto/google/type/quaternion.proto | 0 .../proto/google/type/timeofday.proto | 0 .../proto => bomboni_proto/src}/.gitignore | 0 .../src/proto => bomboni_proto/src}/fd.pb | Bin bomboni_proto/src/google/mod.rs | 2 + bomboni_proto/src/google/protobuf/any.rs | 177 +++++ .../src/google/protobuf}/duration.rs | 66 +- .../src/google/protobuf}/empty.rs | 2 +- .../src/google/protobuf}/field_mask.rs | 5 +- bomboni_proto/src/google/protobuf/mod.rs | 9 + .../src/google/protobuf}/timestamp.rs | 3 +- .../src/google/protobuf}/wrappers.rs | 12 +- bomboni_proto/src/google/rpc/mod.rs | 4 + bomboni_proto/src/google/rpc/status.rs | 106 +++ bomboni_proto/src/lib.rs | 2 + .../src/serde/helpers.rs | 48 +- bomboni_proto/src/serde/mod.rs | 1 + {bomboni => bomboni_proto}/tests/prost.rs | 0 .../tests/proto/.gitignore | 0 .../tests/proto/command/command.proto | 0 .../tests/proto/perms/perms.proto | 0 .../tests/proto/tools.proto | 0 bomboni_request/Cargo.toml | 26 + .../src}/filter/error.rs | 2 +- .../src}/filter/grammar.pest | 0 .../src}/filter/mod.rs | 2 +- bomboni_request/src/lib.rs | 10 + .../request => bomboni_request/src}/mod.rs | 0 .../src}/ordering/error.rs | 0 .../src}/ordering/mod.rs | 2 +- .../request => bomboni_request/src}/query.rs | 0 .../src}/resource.rs | 1 - .../request => bomboni_request/src}/schema.rs | 2 +- .../src/testing/mod.rs | 0 .../src/testing/schema.rs | 6 +- .../request => bomboni_request/src}/value.rs | 7 +- src/lib.rs | 22 + 101 files changed, 2752 insertions(+), 511 deletions(-) delete mode 100644 bomboni/Cargo.toml delete mode 100644 bomboni/src/lib.rs delete mode 100644 bomboni/src/proto/error.rs create mode 100644 bomboni/src/proto/google.protobuf.plus.rs create mode 100644 bomboni/src/proto/google.protobuf.rs create mode 100644 bomboni/src/proto/google.rpc.plus.rs create mode 100644 bomboni/src/proto/google.rpc.rs delete mode 100644 bomboni/src/proto/google/any.rs delete mode 100644 bomboni/src/proto/google/mod.rs delete mode 100644 bomboni/src/proto/google/status.rs delete mode 100644 bomboni/src/proto/mod.rs create mode 100644 bomboni/tests/proto/fd.pb create mode 100644 bomboni/tests/proto/tools.command.plus.rs create mode 100644 bomboni/tests/proto/tools.command.rs create mode 100644 bomboni/tests/proto/tools.perms.plus.rs create mode 100644 bomboni/tests/proto/tools.perms.rs create mode 100644 bomboni/tests/proto/tools.plus.rs create mode 100644 bomboni/tests/proto/tools.rs create mode 100644 bomboni_common/Cargo.toml create mode 100644 bomboni_common/src/lib.rs rename {bomboni => bomboni_common}/src/macros/collections.rs (93%) rename {bomboni => bomboni_common}/src/macros/mod.rs (91%) create mode 100644 bomboni_proto/Cargo.toml rename {bomboni => bomboni_proto}/build.rs (74%) rename {bomboni => bomboni_proto}/proto/google/api/annotations.proto (100%) rename {bomboni => bomboni_proto}/proto/google/api/client.proto (100%) rename {bomboni => bomboni_proto}/proto/google/api/field_behavior.proto (100%) rename {bomboni => bomboni_proto}/proto/google/api/http.proto (100%) rename {bomboni => bomboni_proto}/proto/google/api/httpbody.proto (100%) rename {bomboni => bomboni_proto}/proto/google/api/resource.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/any.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/api.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/descriptor.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/duration.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/empty.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/field_mask.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/source_context.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/struct.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/timestamp.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/type.proto (100%) rename {bomboni => bomboni_proto}/proto/google/protobuf/wrappers.proto (100%) rename {bomboni => bomboni_proto}/proto/google/rpc/code.proto (100%) rename {bomboni => bomboni_proto}/proto/google/rpc/error_details.proto (100%) rename {bomboni => bomboni_proto}/proto/google/rpc/status.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/calendar_period.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/color.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/date.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/datetime.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/dayofweek.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/decimal.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/expr.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/fraction.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/interval.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/latlng.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/localized_text.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/money.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/month.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/phone_number.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/postal_address.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/quaternion.proto (100%) rename {bomboni => bomboni_proto}/proto/google/type/timeofday.proto (100%) rename {bomboni/src/proto => bomboni_proto/src}/.gitignore (100%) rename {bomboni/src/proto => bomboni_proto/src}/fd.pb (100%) create mode 100644 bomboni_proto/src/google/mod.rs create mode 100644 bomboni_proto/src/google/protobuf/any.rs rename {bomboni/src/proto/google => bomboni_proto/src/google/protobuf}/duration.rs (75%) rename {bomboni/src/proto/google => bomboni_proto/src/google/protobuf}/empty.rs (95%) rename {bomboni/src/proto/google => bomboni_proto/src/google/protobuf}/field_mask.rs (96%) create mode 100644 bomboni_proto/src/google/protobuf/mod.rs rename {bomboni/src/proto/google => bomboni_proto/src/google/protobuf}/timestamp.rs (99%) rename {bomboni/src/proto/google => bomboni_proto/src/google/protobuf}/wrappers.rs (95%) create mode 100644 bomboni_proto/src/google/rpc/mod.rs create mode 100644 bomboni_proto/src/google/rpc/status.rs create mode 100644 bomboni_proto/src/lib.rs rename bomboni/src/proto/serde_helpers.rs => bomboni_proto/src/serde/helpers.rs (86%) create mode 100644 bomboni_proto/src/serde/mod.rs rename {bomboni => bomboni_proto}/tests/prost.rs (100%) rename {bomboni => bomboni_proto}/tests/proto/.gitignore (100%) rename {bomboni => bomboni_proto}/tests/proto/command/command.proto (100%) rename {bomboni => bomboni_proto}/tests/proto/perms/perms.proto (100%) rename {bomboni => bomboni_proto}/tests/proto/tools.proto (100%) create mode 100644 bomboni_request/Cargo.toml rename {bomboni/src/request => bomboni_request/src}/filter/error.rs (96%) rename {bomboni/src/request => bomboni_request/src}/filter/grammar.pest (100%) rename {bomboni/src/request => bomboni_request/src}/filter/mod.rs (99%) create mode 100644 bomboni_request/src/lib.rs rename {bomboni/src/request => bomboni_request/src}/mod.rs (100%) rename {bomboni/src/request => bomboni_request/src}/ordering/error.rs (100%) rename {bomboni/src/request => bomboni_request/src}/ordering/mod.rs (98%) rename {bomboni/src/request => bomboni_request/src}/query.rs (100%) rename {bomboni/src/request => bomboni_request/src}/resource.rs (97%) rename {bomboni/src/request => bomboni_request/src}/schema.rs (99%) rename {bomboni => bomboni_request}/src/testing/mod.rs (100%) rename {bomboni => bomboni_request}/src/testing/schema.rs (97%) rename {bomboni/src/request => bomboni_request/src}/value.rs (98%) create mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index fc29655..c0b0875 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,38 @@ +[package] +name = "bomboni" +version = "0.1.3" +authors = ["Tin Rabzelj "] +description = "Utility Library for Rust" +repository = "https://github.com/tinrab/bomboni" +homepage = "https://github.com/tinrab/bomboni" +license-file = "LICENSE" +readme = "README.md" +edition = "2021" + +[lib] +name = "bomboni" +path = "src/lib.rs" + [workspace] resolver = "2" -members = ["bomboni", "bomboni_derive", "bomboni_prost"] +members = [ + "bomboni_common", + "bomboni_derive", + "bomboni_prost", + "bomboni_proto", + "bomboni_request", +] + +[features] +default = ["prost", "proto", "request"] +prost = ["dep:bomboni_prost"] +proto = ["prost", "dep:bomboni_proto"] +request = ["dep:bomboni_request"] + +[dependencies] +bomboni_common = { path = "bomboni_common", version = "0.1.3" } +bomboni_derive = { path = "bomboni_derive", version = "0.1.3" } + +bomboni_prost = { path = "bomboni_prost", version = "0.1.3", optional = true } +bomboni_proto = { path = "bomboni_proto", version = "0.1.3", optional = true } +bomboni_request = { path = "bomboni_request", version = "0.1.3", optional = true } diff --git a/bomboni/Cargo.toml b/bomboni/Cargo.toml deleted file mode 100644 index 9a0a862..0000000 --- a/bomboni/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -name = "bomboni" -version = "0.1.2" -authors = ["Tin Rabzelj "] -description = "Utility Library for Rust" -repository = "https://github.com/tinrab/bomboni" -homepage = "https://github.com/tinrab/bomboni" -license-file = "../LICENSE" -readme = "../README.md" -edition = "2021" - -[lib] -name = "bomboni" -path = "src/lib.rs" - -[features] -default = ["macros", "request", "proto"] -macros = ["dep:bomboni_derive", "dep:regex"] -request = ["dep:pest", "dep:pest_derive"] -proto = ["dep:bomboni_prost", "dep:serde", "dep:serde_json"] -testing = ["dep:bomboni_prost", "dep:prost"] - -[dependencies] -itertools = "0.11.0" -chrono = { version = "0.4.31", features = ["serde"] } -thiserror = "1.0.50" - -bomboni_derive = { version = "*", path = "../bomboni_derive", optional = true } -bomboni_prost = { version = "*", path = "../bomboni_prost", optional = true } -regex = { version = "1.10.2", optional = true } -pest = { version = "2.7.5", optional = true } -pest_derive = { version = "2.7.5", optional = true } -prost = { version = "0.12.1", optional = true } -serde = { version = "1.0", features = ["derive"], optional = true } -serde_json = { version = "1.0", optional = true } - -[dev-dependencies] -bomboni_derive = { path = "../bomboni_derive" } -bomboni_prost = { path = "../bomboni_prost" } - -[build-dependencies] -bomboni_prost = { path = "../bomboni_prost" } -prost-build = "0.12.1" diff --git a/bomboni/src/lib.rs b/bomboni/src/lib.rs deleted file mode 100644 index d6b51a1..0000000 --- a/bomboni/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Common utilities for Rust. -//! - -//! A collection of common utilities for Rust. - -#[cfg(feature = "macros")] -pub mod macros; - -#[cfg(feature = "request")] -pub mod request; - -#[cfg(feature = "proto")] -pub mod proto; - -#[cfg(feature = "testing")] -#[allow(clippy::all, missing_docs)] -pub mod testing; diff --git a/bomboni/src/proto/error.rs b/bomboni/src/proto/error.rs deleted file mode 100644 index 810280f..0000000 --- a/bomboni/src/proto/error.rs +++ /dev/null @@ -1,5 +0,0 @@ -use thiserror::Error; - -use crate::request::{filter::error::FilterError, ordering::error::OrderingError}; - -// pub type ProtoResult = Result; diff --git a/bomboni/src/proto/google.protobuf.plus.rs b/bomboni/src/proto/google.protobuf.plus.rs new file mode 100644 index 0000000..d3a8802 --- /dev/null +++ b/bomboni/src/proto/google.protobuf.plus.rs @@ -0,0 +1,238 @@ +///Implement [`prost::Name`] for `Timestamp`. +impl ::prost::Name for Timestamp { + const NAME: &'static str = "Timestamp"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Timestamp { + pub const TYPE_URL: &'static str = "type.googleapis.com/Timestamp"; +} +impl Timestamp { + pub const SECONDS_FIELD_NAME: &'static str = "seconds"; + pub const NANOS_FIELD_NAME: &'static str = "nanos"; +} +///Implement [`prost::Name`] for `DoubleValue`. +impl ::prost::Name for DoubleValue { + const NAME: &'static str = "DoubleValue"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl DoubleValue { + pub const TYPE_URL: &'static str = "type.googleapis.com/DoubleValue"; +} +impl DoubleValue { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `FloatValue`. +impl ::prost::Name for FloatValue { + const NAME: &'static str = "FloatValue"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl FloatValue { + pub const TYPE_URL: &'static str = "type.googleapis.com/FloatValue"; +} +impl FloatValue { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `Int64Value`. +impl ::prost::Name for Int64Value { + const NAME: &'static str = "Int64Value"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Int64Value { + pub const TYPE_URL: &'static str = "type.googleapis.com/Int64Value"; +} +impl Int64Value { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `UInt64Value`. +impl ::prost::Name for UInt64Value { + const NAME: &'static str = "UInt64Value"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl UInt64Value { + pub const TYPE_URL: &'static str = "type.googleapis.com/UInt64Value"; +} +impl UInt64Value { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `Int32Value`. +impl ::prost::Name for Int32Value { + const NAME: &'static str = "Int32Value"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Int32Value { + pub const TYPE_URL: &'static str = "type.googleapis.com/Int32Value"; +} +impl Int32Value { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `UInt32Value`. +impl ::prost::Name for UInt32Value { + const NAME: &'static str = "UInt32Value"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl UInt32Value { + pub const TYPE_URL: &'static str = "type.googleapis.com/UInt32Value"; +} +impl UInt32Value { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `BoolValue`. +impl ::prost::Name for BoolValue { + const NAME: &'static str = "BoolValue"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl BoolValue { + pub const TYPE_URL: &'static str = "type.googleapis.com/BoolValue"; +} +impl BoolValue { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `StringValue`. +impl ::prost::Name for StringValue { + const NAME: &'static str = "StringValue"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl StringValue { + pub const TYPE_URL: &'static str = "type.googleapis.com/StringValue"; +} +impl StringValue { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `BytesValue`. +impl ::prost::Name for BytesValue { + const NAME: &'static str = "BytesValue"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl BytesValue { + pub const TYPE_URL: &'static str = "type.googleapis.com/BytesValue"; +} +impl BytesValue { + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `Any`. +impl ::prost::Name for Any { + const NAME: &'static str = "Any"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Any { + pub const TYPE_URL: &'static str = "type.googleapis.com/Any"; +} +impl Any { + pub const TYPE_URL_FIELD_NAME: &'static str = "type_url"; + pub const VALUE_FIELD_NAME: &'static str = "value"; +} +///Implement [`prost::Name`] for `FieldMask`. +impl ::prost::Name for FieldMask { + const NAME: &'static str = "FieldMask"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl FieldMask { + pub const TYPE_URL: &'static str = "type.googleapis.com/FieldMask"; +} +impl FieldMask { + pub const PATHS_FIELD_NAME: &'static str = "paths"; +} +///Implement [`prost::Name`] for `Empty`. +impl ::prost::Name for Empty { + const NAME: &'static str = "Empty"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Empty { + pub const TYPE_URL: &'static str = "type.googleapis.com/Empty"; +} +///Implement [`prost::Name`] for `Duration`. +impl ::prost::Name for Duration { + const NAME: &'static str = "Duration"; + const PACKAGE: &'static str = "google.protobuf"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Duration { + pub const TYPE_URL: &'static str = "type.googleapis.com/Duration"; +} +impl Duration { + pub const SECONDS_FIELD_NAME: &'static str = "seconds"; + pub const NANOS_FIELD_NAME: &'static str = "nanos"; +} diff --git a/bomboni/src/proto/google.protobuf.rs b/bomboni/src/proto/google.protobuf.rs new file mode 100644 index 0000000..9d4c386 --- /dev/null +++ b/bomboni/src/proto/google.protobuf.rs @@ -0,0 +1,673 @@ +/// A Timestamp represents a point in time independent of any time zone or local +/// calendar, encoded as a count of seconds and fractions of seconds at +/// nanosecond resolution. The count is relative to an epoch at UTC midnight on +/// January 1, 1970, in the proleptic Gregorian calendar which extends the +/// Gregorian calendar backwards to year one. +/// +/// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +/// second table is needed for interpretation, using a [24-hour linear +/// smear](). +/// +/// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +/// restricting to that range, we ensure that we can convert to and from [RFC +/// 3339]() date strings. +/// +/// # Examples +/// +/// Example 1: Compute Timestamp from POSIX `time()`. +/// +/// ```text +/// Timestamp timestamp; +/// timestamp.set_seconds(time(NULL)); +/// timestamp.set_nanos(0); +/// ``` +/// +/// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +/// +/// ```text +/// struct timeval tv; +/// gettimeofday(&tv, NULL); +/// +/// Timestamp timestamp; +/// timestamp.set_seconds(tv.tv_sec); +/// timestamp.set_nanos(tv.tv_usec * 1000); +/// ``` +/// +/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +/// +/// ```text +/// FILETIME ft; +/// GetSystemTimeAsFileTime(&ft); +/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +/// +/// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +/// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +/// Timestamp timestamp; +/// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +/// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +/// ``` +/// +/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +/// +/// ```text +/// long millis = System.currentTimeMillis(); +/// +/// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +/// .setNanos((int) ((millis % 1000) * 1000000)).build(); +/// ``` +/// +/// Example 5: Compute Timestamp from Java `Instant.now()`. +/// +/// ```text +/// Instant now = Instant.now(); +/// +/// Timestamp timestamp = +/// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) +/// .setNanos(now.getNano()).build(); +/// ``` +/// +/// +/// Example 6: Compute Timestamp from current time in Python. +/// +/// ```text +/// timestamp = Timestamp() +/// timestamp.GetCurrentTime() +/// ``` +/// +/// # JSON Mapping +/// +/// In JSON format, the Timestamp type is encoded as a string in the +/// [RFC 3339]() format. That is, the +/// format is "{year}-{month}-{day}T{hour}:{min}:{sec}\[.{frac_sec}\]Z" +/// where {year} is always expressed using four digits while {month}, {day}, +/// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +/// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +/// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +/// is required. A proto3 JSON serializer should always use UTC (as indicated by +/// "Z") when printing the Timestamp type and a proto3 JSON parser should be +/// able to accept both UTC and other timezones (as indicated by an offset). +/// +/// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +/// 01:30 UTC on January 15, 2017. +/// +/// In JavaScript, one can convert a Date object to this format using the +/// standard +/// [toISOString()]() +/// method. In Python, a standard `datetime.datetime` object can be converted +/// to this format using +/// [`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. +/// +/// +#[derive(Copy)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, 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 + /// 9999-12-31T23:59:59Z inclusive. + #[prost(int64, tag = "1")] + pub seconds: i64, + /// Non-negative fractions of a second at nanosecond resolution. Negative + /// second values with fractions must still have non-negative nanos values + /// that count forward in time. Must be from 0 to 999,999,999 + /// inclusive. + #[prost(int32, tag = "2")] + pub nanos: i32, +} +/// Wrapper message for `double`. +/// +/// The JSON representation for `DoubleValue` is JSON number. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DoubleValue { + /// The double value. + #[prost(double, tag = "1")] + pub value: f64, +} +/// Wrapper message for `float`. +/// +/// The JSON representation for `FloatValue` is JSON number. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FloatValue { + /// The float value. + #[prost(float, tag = "1")] + pub value: f32, +} +/// Wrapper message for `int64`. +/// +/// The JSON representation for `Int64Value` is JSON string. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Int64Value { + /// The int64 value. + #[prost(int64, tag = "1")] + pub value: i64, +} +/// Wrapper message for `uint64`. +/// +/// The JSON representation for `UInt64Value` is JSON string. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UInt64Value { + /// The uint64 value. + #[prost(uint64, tag = "1")] + pub value: u64, +} +/// Wrapper message for `int32`. +/// +/// The JSON representation for `Int32Value` is JSON number. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Int32Value { + /// The int32 value. + #[prost(int32, tag = "1")] + pub value: i32, +} +/// Wrapper message for `uint32`. +/// +/// The JSON representation for `UInt32Value` is JSON number. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UInt32Value { + /// The uint32 value. + #[prost(uint32, tag = "1")] + pub value: u32, +} +/// Wrapper message for `bool`. +/// +/// The JSON representation for `BoolValue` is JSON `true` and `false`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BoolValue { + /// The bool value. + #[prost(bool, tag = "1")] + pub value: bool, +} +/// Wrapper message for `string`. +/// +/// The JSON representation for `StringValue` is JSON string. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StringValue { + /// The string value. + #[prost(string, tag = "1")] + pub value: ::prost::alloc::string::String, +} +/// Wrapper message for `bytes`. +/// +/// The JSON representation for `BytesValue` is JSON string. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BytesValue { + /// The bytes value. + #[prost(bytes = "vec", tag = "1")] + pub value: ::prost::alloc::vec::Vec, +} +/// `Any` contains an arbitrary serialized protocol buffer message along with a +/// URL that describes the type of the serialized message. +/// +/// Protobuf library provides support to pack/unpack Any values in the form +/// of utility functions or additional generated methods of the Any type. +/// +/// Example 1: Pack and unpack a message in C++. +/// +/// ```text +/// Foo foo = ...; +/// Any any; +/// any.PackFrom(foo); +/// ... +/// if (any.UnpackTo(&foo)) { +/// ... +/// } +/// ``` +/// +/// Example 2: Pack and unpack a message in Java. +/// +/// ```text +/// Foo foo = ...; +/// Any any = Any.pack(foo); +/// ... +/// if (any.is(Foo.class)) { +/// foo = any.unpack(Foo.class); +/// } +/// ``` +/// +/// Example 3: Pack and unpack a message in Python. +/// +/// ```text +/// foo = Foo(...) +/// any = Any() +/// any.Pack(foo) +/// ... +/// if any.Is(Foo.DESCRIPTOR): +/// any.Unpack(foo) +/// ... +/// ``` +/// +/// Example 4: Pack and unpack a message in Go +/// +/// ```text +/// foo := &pb.Foo{...} +/// any, err := anypb.New(foo) +/// if err != nil { +/// ... +/// } +/// ... +/// foo := &pb.Foo{} +/// if err := any.UnmarshalTo(foo); err != nil { +/// ... +/// } +/// ``` +/// +/// The pack methods provided by protobuf library will by default use +/// 'type.googleapis.com/full.type.name' as the type URL and the unpack +/// methods only use the fully qualified type name after the last '/' +/// in the type URL, for example "foo.bar.com/x/y.z" will yield type +/// name "y.z". +/// +/// +/// JSON +/// ==== +/// The JSON representation of an `Any` value uses the regular +/// representation of the deserialized, embedded message, with an +/// additional field `@type` which contains the type URL. Example: +/// +/// ```text +/// package google.profile; +/// message Person { +/// string first_name = 1; +/// string last_name = 2; +/// } +/// +/// { +/// "@type": "type.googleapis.com/google.profile.Person", +/// "firstName": , +/// "lastName": +/// } +/// ``` +/// +/// If the embedded message type is well-known and has a custom JSON +/// representation, that representation will be embedded adding a field +/// `value` which holds the custom JSON in addition to the `@type` +/// field. Example (for message [google.protobuf.Duration][]): +/// +/// ```text +/// { +/// "@type": "type.googleapis.com/google.protobuf.Duration", +/// "value": "1.212s" +/// } +/// ``` +/// +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Any { + /// A URL/resource name that uniquely identifies the type of the serialized + /// protocol buffer message. This string must contain at least + /// one "/" character. The last segment of the URL's path must represent + /// the fully qualified name of the type (as in + /// `path/google.protobuf.Duration`). The name should be in a canonical form + /// (e.g., leading "." is not accepted). + /// + /// In practice, teams usually precompile into the binary all types that they + /// expect it to use in the context of Any. However, for URLs which use the + /// scheme `http`, `https`, or no scheme, one can optionally set up a type + /// server that maps type URLs to message definitions as follows: + /// + /// * If no scheme is provided, `https` is assumed. + /// * An HTTP GET on the URL must yield a [google.protobuf.Type][] + /// value in binary format, or produce an error. + /// * Applications are allowed to cache lookup results based on the + /// URL, or have them precompiled into a binary to avoid any + /// lookup. Therefore, binary compatibility needs to be preserved + /// on changes to types. (Use versioned type names to manage + /// breaking changes.) + /// + /// Note: this functionality is not currently available in the official + /// protobuf release, and it is not used for type URLs beginning with + /// type.googleapis.com. + /// + /// Schemes other than `http`, `https` (or the empty scheme) might be + /// used with implementation specific semantics. + /// + #[prost(string, tag = "1")] + pub type_url: ::prost::alloc::string::String, + /// Must be a valid serialized protocol buffer of the above specified type. + #[prost(bytes = "vec", tag = "2")] + pub value: ::prost::alloc::vec::Vec, +} +/// `FieldMask` represents a set of symbolic field paths, for example: +/// +/// ```text +/// paths: "f.a" +/// paths: "f.b.d" +/// ``` +/// +/// Here `f` represents a field in some root message, `a` and `b` +/// fields in the message found in `f`, and `d` a field found in the +/// message in `f.b`. +/// +/// Field masks are used to specify a subset of fields that should be +/// returned by a get operation or modified by an update operation. +/// Field masks also have a custom JSON encoding (see below). +/// +/// # Field Masks in Projections +/// +/// When used in the context of a projection, a response message or +/// sub-message is filtered by the API to only contain those fields as +/// specified in the mask. For example, if the mask in the previous +/// example is applied to a response message as follows: +/// +/// ```text +/// f { +/// a : 22 +/// b { +/// d : 1 +/// x : 2 +/// } +/// y : 13 +/// } +/// z: 8 +/// ``` +/// +/// The result will not contain specific values for fields x,y and z +/// (their value will be set to the default, and omitted in proto text +/// output): +/// +/// +/// ```text +/// f { +/// a : 22 +/// b { +/// d : 1 +/// } +/// } +/// ``` +/// +/// A repeated field is not allowed except at the last position of a +/// paths string. +/// +/// If a FieldMask object is not present in a get operation, the +/// operation applies to all fields (as if a FieldMask of all fields +/// had been specified). +/// +/// Note that a field mask does not necessarily apply to the +/// top-level response message. In case of a REST get operation, the +/// field mask applies directly to the response, but in case of a REST +/// list operation, the mask instead applies to each individual message +/// in the returned resource list. In case of a REST custom method, +/// other definitions may be used. Where the mask applies will be +/// clearly documented together with its declaration in the API. In +/// any case, the effect on the returned resource/resources is required +/// behavior for APIs. +/// +/// # Field Masks in Update Operations +/// +/// A field mask in update operations specifies which fields of the +/// targeted resource are going to be updated. The API is required +/// to only change the values of the fields as specified in the mask +/// and leave the others untouched. If a resource is passed in to +/// describe the updated values, the API ignores the values of all +/// fields not covered by the mask. +/// +/// If a repeated field is specified for an update operation, new values will +/// be appended to the existing repeated field in the target resource. Note that +/// a repeated field is only allowed in the last position of a `paths` string. +/// +/// If a sub-message is specified in the last position of the field mask for an +/// update operation, then new value will be merged into the existing sub-message +/// in the target resource. +/// +/// For example, given the target message: +/// +/// ```text +/// f { +/// b { +/// d: 1 +/// x: 2 +/// } +/// c: \[1\] +/// } +/// ``` +/// +/// And an update message: +/// +/// ```text +/// f { +/// b { +/// d: 10 +/// } +/// c: \[2\] +/// } +/// ``` +/// +/// then if the field mask is: +/// +/// ```text +/// paths: \["f.b", "f.c"\] +/// ``` +/// +/// then the result will be: +/// +/// ```text +/// f { +/// b { +/// d: 10 +/// x: 2 +/// } +/// c: \[1, 2\] +/// } +/// ``` +/// +/// An implementation may provide options to override this default behavior for +/// repeated and message fields. +/// +/// In order to reset a field's value to the default, the field must +/// be in the mask and set to the default value in the provided resource. +/// Hence, in order to reset all fields of a resource, provide a default +/// instance of the resource and set all fields in the mask, or do +/// not provide a mask as described below. +/// +/// If a field mask is not present on update, the operation applies to +/// all fields (as if a field mask of all fields has been specified). +/// Note that in the presence of schema evolution, this may mean that +/// fields the client does not know and has therefore not filled into +/// the request will be reset to their default. If this is unwanted +/// behavior, a specific service may require a client to always specify +/// a field mask, producing an error if not. +/// +/// As with get operations, the location of the resource which +/// describes the updated values in the request message depends on the +/// operation kind. In any case, the effect of the field mask is +/// required to be honored by the API. +/// +/// ## Considerations for HTTP REST +/// +/// The HTTP kind of an update operation which uses a field mask must +/// be set to PATCH instead of PUT in order to satisfy HTTP semantics +/// (PUT must only be used for full updates). +/// +/// # JSON Encoding of Field Masks +/// +/// In JSON, a field mask is encoded as a single string where paths are +/// separated by a comma. Fields name in each path are converted +/// to/from lower-camel naming conventions. +/// +/// As an example, consider the following message declarations: +/// +/// ```text +/// message Profile { +/// User user = 1; +/// Photo photo = 2; +/// } +/// message User { +/// string display_name = 1; +/// string address = 2; +/// } +/// ``` +/// +/// In proto a field mask for `Profile` may look as such: +/// +/// ```text +/// mask { +/// paths: "user.display_name" +/// paths: "photo" +/// } +/// ``` +/// +/// In JSON, the same mask is represented as below: +/// +/// ```text +/// { +/// mask: "user.displayName,photo" +/// } +/// ``` +/// +/// # Field Masks and Oneof Fields +/// +/// Field masks treat fields in oneofs just as regular fields. Consider the +/// following message: +/// +/// ```text +/// message SampleMessage { +/// oneof test_oneof { +/// string name = 4; +/// SubMessage sub_message = 9; +/// } +/// } +/// ``` +/// +/// The field mask can be: +/// +/// ```text +/// mask { +/// paths: "name" +/// } +/// ``` +/// +/// Or: +/// +/// ```text +/// mask { +/// paths: "sub_message" +/// } +/// ``` +/// +/// Note that oneof type names ("test_oneof" in this case) cannot be used in +/// paths. +/// +/// ## Field Mask Verification +/// +/// 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)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FieldMask { + /// The set of field mask paths. + #[prost(string, repeated, tag = "1")] + pub paths: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +/// A generic empty message that you can re-use to avoid defining duplicated +/// empty messages in your APIs. A typical example is to use it as the request +/// or the response type of an API method. For instance: +/// +/// ```text +/// service Foo { +/// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +/// } +/// ``` +/// +/// The JSON representation for `Empty` is empty JSON object `{}`. +#[derive(Copy)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Empty {} +/// A Duration represents a signed, fixed-length span of time represented +/// as a count of seconds and fractions of seconds at nanosecond +/// resolution. It is independent of any calendar and concepts like "day" +/// or "month". It is related to Timestamp in that the difference between +/// two Timestamp values is a Duration and it can be added or subtracted +/// from a Timestamp. Range is approximately +-10,000 years. +/// +/// # Examples +/// +/// Example 1: Compute Duration from two Timestamps in pseudo code. +/// +/// ```text +/// Timestamp start = ...; +/// Timestamp end = ...; +/// Duration duration = ...; +/// +/// duration.seconds = end.seconds - start.seconds; +/// duration.nanos = end.nanos - start.nanos; +/// +/// if (duration.seconds < 0 && duration.nanos > 0) { +/// duration.seconds += 1; +/// duration.nanos -= 1000000000; +/// } else if (duration.seconds > 0 && duration.nanos < 0) { +/// duration.seconds -= 1; +/// duration.nanos += 1000000000; +/// } +/// ``` +/// +/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +/// +/// ```text +/// Timestamp start = ...; +/// Duration duration = ...; +/// Timestamp end = ...; +/// +/// end.seconds = start.seconds + duration.seconds; +/// end.nanos = start.nanos + duration.nanos; +/// +/// if (end.nanos < 0) { +/// end.seconds -= 1; +/// end.nanos += 1000000000; +/// } else if (end.nanos >= 1000000000) { +/// end.seconds += 1; +/// end.nanos -= 1000000000; +/// } +/// ``` +/// +/// Example 3: Compute Duration from datetime.timedelta in Python. +/// +/// ```text +/// td = datetime.timedelta(days=3, minutes=10) +/// duration = Duration() +/// duration.FromTimedelta(td) +/// ``` +/// +/// # JSON Mapping +/// +/// In JSON format, the Duration type is encoded as a string rather than an +/// object, where the string ends in the suffix "s" (indicating seconds) and +/// is preceded by the number of seconds, with nanoseconds expressed as +/// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +/// 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". +/// +/// +#[derive(Copy)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, 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: + /// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + #[prost(int64, tag = "1")] + pub seconds: i64, + /// Signed fractions of a second at nanosecond resolution of the span + /// of time. Durations less than one second are represented with a 0 + /// `seconds` field and a positive or negative `nanos` field. For durations + /// of one second or more, a non-zero value for the `nanos` field must be + /// of the same sign as the `seconds` field. Must be from -999,999,999 + /// to +999,999,999 inclusive. + #[prost(int32, tag = "2")] + pub nanos: i32, +} diff --git a/bomboni/src/proto/google.rpc.plus.rs b/bomboni/src/proto/google.rpc.plus.rs new file mode 100644 index 0000000..6553af7 --- /dev/null +++ b/bomboni/src/proto/google.rpc.plus.rs @@ -0,0 +1,397 @@ +///Implement [`prost::Name`] for `RetryInfo`. +impl ::prost::Name for RetryInfo { + const NAME: &'static str = "RetryInfo"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl RetryInfo { + pub const TYPE_URL: &'static str = "type.googleapis.com/RetryInfo"; +} +impl RetryInfo { + pub const RETRY_DELAY_FIELD_NAME: &'static str = "retry_delay"; +} +///Implement [`prost::Name`] for `DebugInfo`. +impl ::prost::Name for DebugInfo { + const NAME: &'static str = "DebugInfo"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl DebugInfo { + pub const TYPE_URL: &'static str = "type.googleapis.com/DebugInfo"; +} +impl DebugInfo { + pub const STACK_ENTRIES_FIELD_NAME: &'static str = "stack_entries"; + pub const DETAIL_FIELD_NAME: &'static str = "detail"; +} +///Implement [`prost::Name`] for `QuotaFailure`. +impl ::prost::Name for QuotaFailure { + const NAME: &'static str = "QuotaFailure"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl QuotaFailure { + pub const TYPE_URL: &'static str = "type.googleapis.com/QuotaFailure"; +} +impl QuotaFailure { + pub const VIOLATIONS_FIELD_NAME: &'static str = "violations"; +} +///Implement [`prost::Name`] for `QuotaFailure.Violation`. +impl ::prost::Name for quota_failure::Violation { + const NAME: &'static str = "QuotaFailure.Violation"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl quota_failure::Violation { + pub const TYPE_URL: &'static str = "type.googleapis.com/QuotaFailure.Violation"; +} +impl quota_failure::Violation { + pub const SUBJECT_FIELD_NAME: &'static str = "subject"; + pub const DESCRIPTION_FIELD_NAME: &'static str = "description"; +} +///Implement [`prost::Name`] for `ErrorInfo`. +impl ::prost::Name for ErrorInfo { + const NAME: &'static str = "ErrorInfo"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl ErrorInfo { + pub const TYPE_URL: &'static str = "type.googleapis.com/ErrorInfo"; +} +impl ErrorInfo { + pub const REASON_FIELD_NAME: &'static str = "reason"; + pub const DOMAIN_FIELD_NAME: &'static str = "domain"; + pub const METADATA_FIELD_NAME: &'static str = "metadata"; +} +///Implement [`prost::Name`] for `PreconditionFailure`. +impl ::prost::Name for PreconditionFailure { + const NAME: &'static str = "PreconditionFailure"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl PreconditionFailure { + pub const TYPE_URL: &'static str = "type.googleapis.com/PreconditionFailure"; +} +impl PreconditionFailure { + pub const VIOLATIONS_FIELD_NAME: &'static str = "violations"; +} +///Implement [`prost::Name`] for `PreconditionFailure.Violation`. +impl ::prost::Name for precondition_failure::Violation { + const NAME: &'static str = "PreconditionFailure.Violation"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl precondition_failure::Violation { + pub const TYPE_URL: &'static str = "type.googleapis.com/PreconditionFailure.Violation"; +} +impl precondition_failure::Violation { + pub const TYPE_FIELD_NAME: &'static str = "type"; + pub const SUBJECT_FIELD_NAME: &'static str = "subject"; + pub const DESCRIPTION_FIELD_NAME: &'static str = "description"; +} +///Implement [`prost::Name`] for `BadRequest`. +impl ::prost::Name for BadRequest { + const NAME: &'static str = "BadRequest"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl BadRequest { + pub const TYPE_URL: &'static str = "type.googleapis.com/BadRequest"; +} +impl BadRequest { + pub const FIELD_VIOLATIONS_FIELD_NAME: &'static str = "field_violations"; +} +///Implement [`prost::Name`] for `BadRequest.FieldViolation`. +impl ::prost::Name for bad_request::FieldViolation { + const NAME: &'static str = "BadRequest.FieldViolation"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl bad_request::FieldViolation { + pub const TYPE_URL: &'static str = "type.googleapis.com/BadRequest.FieldViolation"; +} +impl bad_request::FieldViolation { + pub const FIELD_FIELD_NAME: &'static str = "field"; + pub const DESCRIPTION_FIELD_NAME: &'static str = "description"; +} +///Implement [`prost::Name`] for `RequestInfo`. +impl ::prost::Name for RequestInfo { + const NAME: &'static str = "RequestInfo"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl RequestInfo { + pub const TYPE_URL: &'static str = "type.googleapis.com/RequestInfo"; +} +impl RequestInfo { + pub const REQUEST_ID_FIELD_NAME: &'static str = "request_id"; + pub const SERVING_DATA_FIELD_NAME: &'static str = "serving_data"; +} +///Implement [`prost::Name`] for `ResourceInfo`. +impl ::prost::Name for ResourceInfo { + const NAME: &'static str = "ResourceInfo"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl ResourceInfo { + pub const TYPE_URL: &'static str = "type.googleapis.com/ResourceInfo"; +} +impl ResourceInfo { + pub const RESOURCE_TYPE_FIELD_NAME: &'static str = "resource_type"; + pub const RESOURCE_NAME_FIELD_NAME: &'static str = "resource_name"; + pub const OWNER_FIELD_NAME: &'static str = "owner"; + pub const DESCRIPTION_FIELD_NAME: &'static str = "description"; +} +///Implement [`prost::Name`] for `Help`. +impl ::prost::Name for Help { + const NAME: &'static str = "Help"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Help { + pub const TYPE_URL: &'static str = "type.googleapis.com/Help"; +} +impl Help { + pub const LINKS_FIELD_NAME: &'static str = "links"; +} +///Implement [`prost::Name`] for `Help.Link`. +impl ::prost::Name for help::Link { + const NAME: &'static str = "Help.Link"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl help::Link { + pub const TYPE_URL: &'static str = "type.googleapis.com/Help.Link"; +} +impl help::Link { + pub const DESCRIPTION_FIELD_NAME: &'static str = "description"; + pub const URL_FIELD_NAME: &'static str = "url"; +} +///Implement [`prost::Name`] for `LocalizedMessage`. +impl ::prost::Name for LocalizedMessage { + const NAME: &'static str = "LocalizedMessage"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl LocalizedMessage { + pub const TYPE_URL: &'static str = "type.googleapis.com/LocalizedMessage"; +} +impl LocalizedMessage { + pub const LOCALE_FIELD_NAME: &'static str = "locale"; + pub const MESSAGE_FIELD_NAME: &'static str = "message"; +} +impl Code { + pub const NAME: &'static str = "Code"; + pub const PACKAGE: &'static str = "google.rpc"; +} +impl Code { + pub const OK_VALUE_NAME: &'static str = "OK"; + pub const CANCELLED_VALUE_NAME: &'static str = "CANCELLED"; + pub const UNKNOWN_VALUE_NAME: &'static str = "UNKNOWN"; + pub const INVALID_ARGUMENT_VALUE_NAME: &'static str = "INVALID_ARGUMENT"; + pub const DEADLINE_EXCEEDED_VALUE_NAME: &'static str = "DEADLINE_EXCEEDED"; + pub const NOT_FOUND_VALUE_NAME: &'static str = "NOT_FOUND"; + pub const ALREADY_EXISTS_VALUE_NAME: &'static str = "ALREADY_EXISTS"; + pub const PERMISSION_DENIED_VALUE_NAME: &'static str = "PERMISSION_DENIED"; + pub const UNAUTHENTICATED_VALUE_NAME: &'static str = "UNAUTHENTICATED"; + pub const RESOURCE_EXHAUSTED_VALUE_NAME: &'static str = "RESOURCE_EXHAUSTED"; + pub const FAILED_PRECONDITION_VALUE_NAME: &'static str = "FAILED_PRECONDITION"; + pub const ABORTED_VALUE_NAME: &'static str = "ABORTED"; + pub const OUT_OF_RANGE_VALUE_NAME: &'static str = "OUT_OF_RANGE"; + pub const UNIMPLEMENTED_VALUE_NAME: &'static str = "UNIMPLEMENTED"; + pub const INTERNAL_VALUE_NAME: &'static str = "INTERNAL"; + pub const UNAVAILABLE_VALUE_NAME: &'static str = "UNAVAILABLE"; + pub const DATA_LOSS_VALUE_NAME: &'static str = "DATA_LOSS"; + pub const VALUE_NAMES: &'static [&'static str] = &[ + Self::OK_VALUE_NAME, + Self::CANCELLED_VALUE_NAME, + Self::UNKNOWN_VALUE_NAME, + Self::INVALID_ARGUMENT_VALUE_NAME, + Self::DEADLINE_EXCEEDED_VALUE_NAME, + Self::NOT_FOUND_VALUE_NAME, + Self::ALREADY_EXISTS_VALUE_NAME, + Self::PERMISSION_DENIED_VALUE_NAME, + Self::UNAUTHENTICATED_VALUE_NAME, + Self::RESOURCE_EXHAUSTED_VALUE_NAME, + Self::FAILED_PRECONDITION_VALUE_NAME, + Self::ABORTED_VALUE_NAME, + Self::OUT_OF_RANGE_VALUE_NAME, + Self::UNIMPLEMENTED_VALUE_NAME, + Self::INTERNAL_VALUE_NAME, + Self::UNAVAILABLE_VALUE_NAME, + Self::DATA_LOSS_VALUE_NAME, + ]; +} +impl ::serde::Serialize for Code { + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + serializer.serialize_str(self.as_str_name()) + } +} +impl<'de> ::serde::Deserialize<'de> for Code { + fn deserialize(deserializer: D) -> Result + where + D: ::serde::Deserializer<'de>, + { + struct Visitor; + impl<'de> ::serde::de::Visitor<'de> for Visitor { + type Value = Code; + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", Code::VALUE_NAMES) + } + fn visit_i64(self, v: i64) -> Result + where + E: ::serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|v| Code::try_from(v).ok()) + .ok_or_else(|| { + ::serde::de::Error::invalid_value( + ::serde::de::Unexpected::Signed(v), + &self, + ) + }) + } + fn visit_u64(self, v: u64) -> Result + where + E: ::serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|v| Code::try_from(v).ok()) + .ok_or_else(|| { + ::serde::de::Error::invalid_value( + ::serde::de::Unexpected::Unsigned(v), + &self, + ) + }) + } + fn visit_str(self, value: &str) -> Result + where + E: ::serde::de::Error, + { + Code::from_str_name(value) + .ok_or_else(|| ::serde::de::Error::unknown_variant( + value, + Code::VALUE_NAMES, + )) + } + } + deserializer.deserialize_any(Visitor) + } +} +pub mod code_serde { + use super::*; + use ::serde::{Serialize, Deserialize}; + pub fn serialize( + value: &i32, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: ::serde::Serializer, + { + let value = Code::try_from(*value).unwrap(); + value.serialize(serializer) + } + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: ::serde::Deserializer<'de>, + { + let value = Code::deserialize(deserializer)?; + Ok(value as i32) + } +} +///Implement [`prost::Name`] for `Status`. +impl ::prost::Name for Status { + const NAME: &'static str = "Status"; + const PACKAGE: &'static str = "google.rpc"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Status { + pub const TYPE_URL: &'static str = "type.googleapis.com/Status"; +} +impl Status { + pub const CODE_FIELD_NAME: &'static str = "code"; + pub const MESSAGE_FIELD_NAME: &'static str = "message"; + pub const DETAILS_FIELD_NAME: &'static str = "details"; +} diff --git a/bomboni/src/proto/google.rpc.rs b/bomboni/src/proto/google.rpc.rs new file mode 100644 index 0000000..1cf283e --- /dev/null +++ b/bomboni/src/proto/google.rpc.rs @@ -0,0 +1,520 @@ +/// Describes when the clients can retry a failed request. Clients could ignore +/// the recommendation here or retry when this information is missing from error +/// responses. +/// +/// It's always recommended that clients should use exponential backoff when +/// retrying. +/// +/// Clients should wait until `retry_delay` amount of time has passed since +/// receiving the error response before retrying. If retrying requests also +/// fail, clients should use an exponential backoff scheme to gradually increase +/// the delay between retries based on `retry_delay`, until either a maximum +/// number of retries have been reached or a maximum retry delay cap has been +/// reached. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RetryInfo { + /// Clients should wait at least this long between retrying the same request. + #[prost(message, optional, tag = "1")] + pub retry_delay: ::core::option::Option, +} +/// Describes additional debugging info. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DebugInfo { + /// The stack trace entries indicating where the error occurred. + #[prost(string, repeated, tag = "1")] + pub stack_entries: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// Additional debugging information provided by the server. + #[prost(string, tag = "2")] + pub detail: ::prost::alloc::string::String, +} +/// Describes how a quota check failed. +/// +/// For example if a daily limit was exceeded for the calling project, +/// a service could respond with a QuotaFailure detail containing the project +/// id and the description of the quota limit that was exceeded. If the +/// calling project hasn't enabled the service in the developer console, then +/// a service could respond with the project id and set `service_disabled` +/// to true. +/// +/// Also see RetryInfo and Help types for other details about handling a +/// quota failure. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QuotaFailure { + /// Describes all quota violations. + #[prost(message, repeated, tag = "1")] + pub violations: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `QuotaFailure`. +pub mod quota_failure { + /// A message type used to describe a single quota violation. For example, a + /// daily quota or a custom quota that was exceeded. + #[derive(::serde::Serialize, ::serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Violation { + /// The subject on which the quota check failed. + /// For example, "clientip:" or "project:". + #[prost(string, tag = "1")] + pub subject: ::prost::alloc::string::String, + /// A description of how the quota check failed. Clients can use this + /// description to find more about the quota configuration in the service's + /// public documentation, or find the relevant quota limit to adjust through + /// developer console. + /// + /// For example: "Service disabled" or "Daily Limit for read operations + /// exceeded". + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, + } +} +/// Describes the cause of the error with structured details. +/// +/// Example of an error when contacting the "pubsub.googleapis.com" API when it +/// is not enabled: +/// +/// ```text +/// { "reason": "API_DISABLED" +/// "domain": "googleapis.com" +/// "metadata": { +/// "resource": "projects/123", +/// "service": "pubsub.googleapis.com" +/// } +/// } +/// ``` +/// +/// This response indicates that the pubsub.googleapis.com API is not enabled. +/// +/// Example of an error that is returned when attempting to create a Spanner +/// instance in a region that is out of stock: +/// +/// ```text +/// { "reason": "STOCKOUT" +/// "domain": "spanner.googleapis.com", +/// "metadata": { +/// "availableRegions": "us-central1,us-east2" +/// } +/// } +/// ``` +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ErrorInfo { + /// The reason of the error. This is a constant value that identifies the + /// proximate cause of the error. Error reasons are unique within a particular + /// domain of errors. This should be at most 63 characters and match + /// /\[A-Z0-9_\]+/. + #[prost(string, tag = "1")] + pub reason: ::prost::alloc::string::String, + /// The logical grouping to which the "reason" belongs. The error domain + /// is typically the registered service name of the tool or product that + /// generates the error. Example: "pubsub.googleapis.com". If the error is + /// generated by some common infrastructure, the error domain must be a + /// globally unique value that identifies the infrastructure. For Google API + /// infrastructure, the error domain is "googleapis.com". + #[prost(string, tag = "2")] + pub domain: ::prost::alloc::string::String, + /// Additional structured details about this error. + /// + /// Keys should match /\[a-zA-Z0-9-_\]/ and be limited to 64 characters in + /// length. When identifying the current value of an exceeded limit, the units + /// should be contained in the key, not the value. For example, rather than + /// {"instanceLimit": "100/request"}, should be returned as, + /// {"instanceLimitPerRequest": "100"}, if the client exceeds the number of + /// instances that can be created in a single (batch) request. + #[prost(btree_map = "string, string", tag = "3")] + pub metadata: ::prost::alloc::collections::BTreeMap< + ::prost::alloc::string::String, + ::prost::alloc::string::String, + >, +} +/// Describes what preconditions have failed. +/// +/// For example, if an RPC failed because it required the Terms of Service to be +/// acknowledged, it could list the terms of service violation in the +/// PreconditionFailure message. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PreconditionFailure { + /// Describes all precondition violations. + #[prost(message, repeated, tag = "1")] + pub violations: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `PreconditionFailure`. +pub mod precondition_failure { + /// A message type used to describe a single precondition failure. + #[derive(::serde::Serialize, ::serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Violation { + /// The type of PreconditionFailure. We recommend using a service-specific + /// enum type to define the supported precondition violation subjects. For + /// example, "TOS" for "Terms of Service violation". + #[prost(string, tag = "1")] + pub r#type: ::prost::alloc::string::String, + /// The subject, relative to the type, that failed. + /// For example, "google.com/cloud" relative to the "TOS" type would indicate + /// which terms of service is being referenced. + #[prost(string, tag = "2")] + pub subject: ::prost::alloc::string::String, + /// A description of how the precondition failed. Developers can use this + /// description to understand how to fix the failure. + /// + /// For example: "Terms of service not accepted". + #[prost(string, tag = "3")] + pub description: ::prost::alloc::string::String, + } +} +/// Describes violations in a client request. This error type focuses on the +/// syntactic aspects of the request. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BadRequest { + /// Describes all violations in a client request. + #[prost(message, repeated, tag = "1")] + pub field_violations: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `BadRequest`. +pub mod bad_request { + /// A message type used to describe a single bad request field. + #[derive(::serde::Serialize, ::serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct FieldViolation { + /// A path leading to a field in the request body. The value will be a + /// sequence of dot-separated identifiers that identify a protocol buffer + /// field. E.g., "field_violations.field" would identify this field. + #[prost(string, tag = "1")] + pub field: ::prost::alloc::string::String, + /// A description of why the request element is bad. + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, + } +} +/// Contains metadata about the request that clients can attach when filing a bug +/// or providing other forms of feedback. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RequestInfo { + /// An opaque string that should only be interpreted by the service generating + /// it. For example, it can be used to identify requests in the service's logs. + #[prost(string, tag = "1")] + pub request_id: ::prost::alloc::string::String, + /// Any data that was used to serve this request. For example, an encrypted + /// stack trace that can be sent back to the service provider for debugging. + #[prost(string, tag = "2")] + pub serving_data: ::prost::alloc::string::String, +} +/// Describes the resource that is being accessed. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResourceInfo { + /// A name for the type of resource being accessed, e.g. "sql table", + /// "cloud storage bucket", "file", "Google calendar"; or the type URL + /// of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic". + #[prost(string, tag = "1")] + pub resource_type: ::prost::alloc::string::String, + /// The name of the resource being accessed. For example, a shared calendar + /// name: "example.com_4fghdhgsrgh@group.calendar.google.com", if the current + /// error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED]. + #[prost(string, tag = "2")] + pub resource_name: ::prost::alloc::string::String, + /// The owner of the resource (optional). + /// For example, "user:" or "project:". + #[prost(string, tag = "3")] + pub owner: ::prost::alloc::string::String, + /// Describes what error is encountered when accessing this resource. + /// For example, updating a cloud project may require the `writer` permission + /// on the developer console project. + #[prost(string, tag = "4")] + pub description: ::prost::alloc::string::String, +} +/// Provides links to documentation or for performing an out of band action. +/// +/// For example, if a quota check failed with an error indicating the calling +/// project hasn't enabled the accessed service, this can contain a URL pointing +/// directly to the right place in the developer console to flip the bit. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Help { + /// URL(s) pointing to additional information on handling the current error. + #[prost(message, repeated, tag = "1")] + pub links: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `Help`. +pub mod help { + /// Describes a URL link. + #[derive(::serde::Serialize, ::serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Link { + /// Describes what the link offers. + #[prost(string, tag = "1")] + pub description: ::prost::alloc::string::String, + /// The URL of the link. + #[prost(string, tag = "2")] + pub url: ::prost::alloc::string::String, + } +} +/// Provides a localized error message that is safe to return to the user +/// which can be attached to an RPC error. +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LocalizedMessage { + /// The locale used following the specification defined at + /// + /// Examples are: "en-US", "fr-CH", "es-MX" + #[prost(string, tag = "1")] + pub locale: ::prost::alloc::string::String, + /// The localized error message in the above locale. + #[prost(string, tag = "2")] + pub message: ::prost::alloc::string::String, +} +/// The canonical error codes for gRPC APIs. +/// +/// +/// Sometimes multiple error codes may apply. Services should return +/// the most specific error code that applies. For example, prefer +/// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. +/// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum Code { + /// Not an error; returned on success + /// + /// HTTP Mapping: 200 OK + Ok = 0, + /// The operation was cancelled, typically by the caller. + /// + /// HTTP Mapping: 499 Client Closed Request + Cancelled = 1, + /// Unknown error. For example, this error may be returned when + /// a `Status` value received from another address space belongs to + /// an error space that is not known in this address space. Also + /// errors raised by APIs that do not return enough error information + /// may be converted to this error. + /// + /// HTTP Mapping: 500 Internal Server Error + Unknown = 2, + /// The client specified an invalid argument. Note that this differs + /// from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments + /// that are problematic regardless of the state of the system + /// (e.g., a malformed file name). + /// + /// HTTP Mapping: 400 Bad Request + InvalidArgument = 3, + /// The deadline expired before the operation could complete. For operations + /// that change the state of the system, this error may be returned + /// even if the operation has completed successfully. For example, a + /// successful response from a server could have been delayed long + /// enough for the deadline to expire. + /// + /// HTTP Mapping: 504 Gateway Timeout + DeadlineExceeded = 4, + /// Some requested entity (e.g., file or directory) was not found. + /// + /// Note to server developers: if a request is denied for an entire class + /// of users, such as gradual feature rollout or undocumented whitelist, + /// `NOT_FOUND` may be used. If a request is denied for some users within + /// a class of users, such as user-based access control, `PERMISSION_DENIED` + /// must be used. + /// + /// HTTP Mapping: 404 Not Found + NotFound = 5, + /// The entity that a client attempted to create (e.g., file or directory) + /// already exists. + /// + /// HTTP Mapping: 409 Conflict + AlreadyExists = 6, + /// The caller does not have permission to execute the specified + /// operation. `PERMISSION_DENIED` must not be used for rejections + /// caused by exhausting some resource (use `RESOURCE_EXHAUSTED` + /// instead for those errors). `PERMISSION_DENIED` must not be + /// used if the caller can not be identified (use `UNAUTHENTICATED` + /// instead for those errors). This error code does not imply the + /// request is valid or the requested entity exists or satisfies + /// other pre-conditions. + /// + /// HTTP Mapping: 403 Forbidden + PermissionDenied = 7, + /// The request does not have valid authentication credentials for the + /// operation. + /// + /// HTTP Mapping: 401 Unauthorized + Unauthenticated = 16, + /// Some resource has been exhausted, perhaps a per-user quota, or + /// perhaps the entire file system is out of space. + /// + /// HTTP Mapping: 429 Too Many Requests + ResourceExhausted = 8, + /// The operation was rejected because the system is not in a state + /// required for the operation's execution. For example, the directory + /// to be deleted is non-empty, an rmdir operation is applied to + /// a non-directory, etc. + /// + /// Service implementors can use the following guidelines to decide + /// between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: + /// (a) Use `UNAVAILABLE` if the client can retry just the failing call. + /// (b) Use `ABORTED` if the client should retry at a higher level + /// (e.g., when a client-specified test-and-set fails, indicating the + /// client should restart a read-modify-write sequence). + /// (c) Use `FAILED_PRECONDITION` if the client should not retry until + /// the system state has been explicitly fixed. E.g., if an "rmdir" + /// fails because the directory is non-empty, `FAILED_PRECONDITION` + /// should be returned since the client should not retry unless + /// the files are deleted from the directory. + /// + /// HTTP Mapping: 400 Bad Request + FailedPrecondition = 9, + /// The operation was aborted, typically due to a concurrency issue such as + /// a sequencer check failure or transaction abort. + /// + /// See the guidelines above for deciding between `FAILED_PRECONDITION`, + /// `ABORTED`, and `UNAVAILABLE`. + /// + /// HTTP Mapping: 409 Conflict + Aborted = 10, + /// The operation was attempted past the valid range. E.g., seeking or + /// reading past end-of-file. + /// + /// Unlike `INVALID_ARGUMENT`, this error indicates a problem that may + /// be fixed if the system state changes. For example, a 32-bit file + /// system will generate `INVALID_ARGUMENT` if asked to read at an + /// offset that is not in the range \[0,2^32-1\], but it will generate + /// `OUT_OF_RANGE` if asked to read from an offset past the current + /// file size. + /// + /// There is a fair bit of overlap between `FAILED_PRECONDITION` and + /// `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific + /// error) when it applies so that callers who are iterating through + /// a space can easily look for an `OUT_OF_RANGE` error to detect when + /// they are done. + /// + /// HTTP Mapping: 400 Bad Request + OutOfRange = 11, + /// The operation is not implemented or is not supported/enabled in this + /// service. + /// + /// HTTP Mapping: 501 Not Implemented + Unimplemented = 12, + /// Internal errors. This means that some invariants expected by the + /// underlying system have been broken. This error code is reserved + /// for serious errors. + /// + /// HTTP Mapping: 500 Internal Server Error + Internal = 13, + /// The service is currently unavailable. This is most likely a + /// transient condition, which can be corrected by retrying with + /// a backoff. Note that it is not always safe to retry + /// non-idempotent operations. + /// + /// See the guidelines above for deciding between `FAILED_PRECONDITION`, + /// `ABORTED`, and `UNAVAILABLE`. + /// + /// HTTP Mapping: 503 Service Unavailable + Unavailable = 14, + /// Unrecoverable data loss or corruption. + /// + /// HTTP Mapping: 500 Internal Server Error + DataLoss = 15, +} +impl Code { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Code::Ok => "OK", + Code::Cancelled => "CANCELLED", + Code::Unknown => "UNKNOWN", + Code::InvalidArgument => "INVALID_ARGUMENT", + Code::DeadlineExceeded => "DEADLINE_EXCEEDED", + Code::NotFound => "NOT_FOUND", + Code::AlreadyExists => "ALREADY_EXISTS", + Code::PermissionDenied => "PERMISSION_DENIED", + Code::Unauthenticated => "UNAUTHENTICATED", + Code::ResourceExhausted => "RESOURCE_EXHAUSTED", + Code::FailedPrecondition => "FAILED_PRECONDITION", + Code::Aborted => "ABORTED", + Code::OutOfRange => "OUT_OF_RANGE", + Code::Unimplemented => "UNIMPLEMENTED", + Code::Internal => "INTERNAL", + Code::Unavailable => "UNAVAILABLE", + Code::DataLoss => "DATA_LOSS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "OK" => Some(Self::Ok), + "CANCELLED" => Some(Self::Cancelled), + "UNKNOWN" => Some(Self::Unknown), + "INVALID_ARGUMENT" => Some(Self::InvalidArgument), + "DEADLINE_EXCEEDED" => Some(Self::DeadlineExceeded), + "NOT_FOUND" => Some(Self::NotFound), + "ALREADY_EXISTS" => Some(Self::AlreadyExists), + "PERMISSION_DENIED" => Some(Self::PermissionDenied), + "UNAUTHENTICATED" => Some(Self::Unauthenticated), + "RESOURCE_EXHAUSTED" => Some(Self::ResourceExhausted), + "FAILED_PRECONDITION" => Some(Self::FailedPrecondition), + "ABORTED" => Some(Self::Aborted), + "OUT_OF_RANGE" => Some(Self::OutOfRange), + "UNIMPLEMENTED" => Some(Self::Unimplemented), + "INTERNAL" => Some(Self::Internal), + "UNAVAILABLE" => Some(Self::Unavailable), + "DATA_LOSS" => Some(Self::DataLoss), + _ => None, + } + } +} +/// The `Status` type defines a logical error model that is suitable for +/// different programming environments, including REST APIs and RPC APIs. It is +/// used by [gRPC](). Each `Status` message contains +/// three pieces of data: error code, error message, and error details. +/// +/// You can find out more about this error model and how to work with it in the +/// [API Design Guide](). +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Status { + /// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + #[prost(int32, tag = "1")] + pub code: i32, + /// A developer-facing error message, which should be in English. Any + /// user-facing error message should be localized and sent in the + /// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + #[prost(string, tag = "2")] + pub message: ::prost::alloc::string::String, + /// A list of messages that carry the error details. There is a common set of + /// message types for APIs to use. + #[prost(message, repeated, tag = "3")] + pub details: ::prost::alloc::vec::Vec, +} diff --git a/bomboni/src/proto/google/any.rs b/bomboni/src/proto/google/any.rs deleted file mode 100644 index f9b7e89..0000000 --- a/bomboni/src/proto/google/any.rs +++ /dev/null @@ -1,157 +0,0 @@ -use super::protobuf::Any; -use super::rpc::ErrorInfo; -use prost::{DecodeError, EncodeError, Message, Name}; -use serde::ser::SerializeStruct; -use serde::{Deserialize, Serialize, Serializer}; - -impl Any { - pub fn new(type_url: String, value: Vec) -> Self { - Any { type_url, value } - } - - pub fn pack_from(message: &T) -> Result - where - T: Name, - { - let type_url = T::type_url(); - let mut value = Vec::new(); - Message::encode(message, &mut value)?; - Ok(Any { type_url, value }) - } - - pub fn unpack_into(self) -> Result - where - T: Default + Name, - { - let expected_type_url = T::type_url(); - if expected_type_url != self.type_url { - let mut err = DecodeError::new(format!( - "expected type URL `{}`, but got `{}`", - expected_type_url, &self.type_url - )); - err.push("unexpected type URL", "type_url"); - return Err(err); - } - T::decode(&*self.value) - } -} - -#[macro_export(local_inner_macros)] -macro_rules! impl_proto_any_serde { - ([$($message:ty),* $(,)?]) => { - // impl ::serde::Serialize for $crate::proto::google::protobuf::Any { - // fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - // where - // S: ::serde::Serializer, - // { - // serialize(self, serializer) - // } - // } - - // impl<'de> ::serde::Deserialize<'de> for $crate::proto::google::protobuf::Any { - // fn deserialize(deserializer: D) -> std::result::Result>::Error> - // where - // D: ::serde::Deserializer<'de>, - // { - // deserialize(deserializer) - // } - // } - - pub fn serialize( - value: &$crate::proto::google::protobuf::Any, - serializer: S, - ) -> Result<::Ok, ::Error> - where - S: ::serde::Serializer, - { - use ::prost::Name; - use ::serde::{Serialize, Serializer}; - - #[derive(::serde::Serialize)] - struct AnySerdeProxy { - #[serde(rename = "@type")] - type_url: String, - #[serde(flatten)] - message: T, - } - - match value.type_url.as_str() { - $( - <$message>::TYPE_URL => { - return AnySerdeProxy { - type_url: <$message>::TYPE_URL.into(), - message: value.clone().unpack_into::<$message>().unwrap(), - }.serialize(serializer); - } - )* - _ => { - ::core::unimplemented!("any serialize for type url {}", value.type_url) - } - } - } - - pub fn deserialize<'de, D>( - deserializer: D, - ) -> Result<$crate::proto::google::protobuf::Any, >::Error> - where - D: ::serde::Deserializer<'de>, - { - use ::prost::Name; - use ::serde::Deserialize; - - #[derive(::serde::Deserialize)] - struct AnySerdeProxy { - #[serde(rename = "@type")] - type_url: String, - #[serde(flatten)] - obj: ::std::collections::BTreeMap, - } - - let proxy = AnySerdeProxy::deserialize(deserializer)?; - match proxy.type_url.as_str() { - $( - <$message>::TYPE_URL => { - let message = ::serde_json::from_value::<$message>( - ::serde_json::Value::Object(proxy.obj.into_iter() - .collect()) - ).map_err(|err| { - ::serde::de::Error::custom(::std::format!("failed to deserialize {}: {}", proxy.type_url, err)) - })?; - $crate::proto::google::protobuf::Any::pack_from(&message) - .map_err(|err| { - ::serde::de::Error::custom(::std::format!("failed to pack {}: {}", proxy.type_url, err)) - }) - } - )* - _ => { - ::core::unimplemented!("any deserialize for type url {}", proxy.type_url) - } - } - } - }; -} - -#[cfg(test)] -mod tests { - use crate::proto::google::rpc::{ErrorInfo, RetryInfo}; - - use super::*; - - #[test] - fn it_works() { - let msg = ErrorInfo { - reason: "reason".to_string(), - domain: "domain".to_string(), - metadata: Default::default(), - }; - let any = Any::pack_from(&msg).unwrap(); - let decoded: ErrorInfo = any.unpack_into().unwrap(); - assert_eq!(decoded, msg); - } - - #[test] - fn errors() { - let any = Any::pack_from(&ErrorInfo::default()).unwrap(); - assert!(any.unpack_into::().is_err()); - } -} diff --git a/bomboni/src/proto/google/mod.rs b/bomboni/src/proto/google/mod.rs deleted file mode 100644 index bac9d7f..0000000 --- a/bomboni/src/proto/google/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod any; -mod duration; -mod empty; -mod field_mask; -mod status; -mod timestamp; -mod wrappers; - -pub mod protobuf { - include!("../google.protobuf.rs"); - include!("../google.protobuf.plus.rs"); -} - -pub mod rpc { - include!("../google.rpc.rs"); - include!("../google.rpc.plus.rs"); -} diff --git a/bomboni/src/proto/google/status.rs b/bomboni/src/proto/google/status.rs deleted file mode 100644 index 10e7220..0000000 --- a/bomboni/src/proto/google/status.rs +++ /dev/null @@ -1,160 +0,0 @@ -use super::{ - protobuf::Any, - rpc::{Code, Status}, -}; -use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer}; - -impl Status { - pub fn new(code: Code, message: String, details: Vec) -> Self { - Status { - code: code as i32, - message, - details, - } - } -} - -impl Serialize for Status { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer, - { - struct AnyProxy<'a>(&'a Any); - impl<'a> ::serde::Serialize for AnyProxy<'a> { - fn serialize( - &self, - serializer: S, - ) -> Result<::Ok, ::Error> - where - S: ::serde::Serializer, - { - detail_serde::serialize(self.0, serializer) - } - } - - #[derive(Serialize)] - struct StatusProxy<'a> { - code: Code, - message: &'a str, - details: Vec>, - } - let proxy = StatusProxy { - code: self.code.try_into().map_err(|_| { - serde::ser::Error::custom(format!("invalid status code {}", self.code)) - })?, - message: &self.message, - details: self.details.iter().map(AnyProxy).collect::>(), - }; - proxy.serialize(serializer) - } -} - -// impl<'de> Deserialize<'de> for Status { -// fn deserialize(deserializer: D) -> Result>::Error> -// where -// D: Deserializer<'de>, -// { -// luet mut status = deserializer.deserialize_struct(name, fields, visitor) -// } -// } - -pub mod detail_serde { - use crate::{ - impl_proto_any_serde, - proto::google::{ - protobuf::Any, - rpc::{ - BadRequest, DebugInfo, ErrorInfo, Help, LocalizedMessage, PreconditionFailure, - QuotaFailure, RequestInfo, ResourceInfo, RetryInfo, - }, - }, - }; - use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; - - // impl Serialize for &[Any] { - // fn serialize( - // &self, - // serializer: S, - // ) -> Result<::Ok, ::Error> - // where - // S: Serializer, - // { - // let mut seq = serializer.serialize_seq(Some(self.len()))?; - // for detail in *self { - // seq.serialize_element(detail)?; - // } - // seq.end() - // } - // } - - impl_proto_any_serde!([ - BadRequest, - DebugInfo, - ErrorInfo, - Help, - LocalizedMessage, - PreconditionFailure, - QuotaFailure, - RequestInfo, - ResourceInfo, - RetryInfo, - ]); -} - -// pub mod details_serde { -// pub fn serialize( -// details: &[T], -// serializer: S, -// ) -> Result<::Ok, ::Error> -// where -// S: ::serde::Serializer, -// T: TryInto, -// { -// use ::serde::ser::SerializeSeq; - -// let mut seq = serializer.serialize_seq(Some(details.len()))?; - -// // let mut seq = serializer.serialize_seq(Some(details.len()))?; -// // for detail in details { -// // // seq.serialize_element(detail)?; -// // // crate::proto::google::status::detail_serde::serialize(detail, seq); -// // let awd = crate::proto::google::status::detail_serde::serialize(detail, seq); -// // } -// // seq.end() -// todo!() -// } - -// // pub fn deserialize<'de, T, D>(deserializer: D) -> Result, D::Error> -// // where -// // T: TryFrom, -// // D: ::serde::Deserializer<'de>, -// // { -// // // use ::serde::ser::SerializeSeq; -// // // use serde::de::Error; -// // // let details: Vec = Vec::deserialize(deserializer)?; -// // // Ok(details) -// // todo!() -// // } -// } - -#[cfg(test)] -mod tests { - use crate::proto::google::rpc::ErrorInfo; - - use super::*; - - #[test] - fn serde() { - let s = Status::new( - Code::InvalidArgument, - "error".to_string(), - vec![Any::pack_from(&ErrorInfo { - reason: "reason".to_string(), - domain: "domain".to_string(), - metadata: Default::default(), - }) - .unwrap()], - ); - println!("{}", serde_json::to_string_pretty(&s).unwrap()); - } -} diff --git a/bomboni/src/proto/mod.rs b/bomboni/src/proto/mod.rs deleted file mode 100644 index 283d427..0000000 --- a/bomboni/src/proto/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod error; -pub mod google; -pub mod serde_helpers; diff --git a/bomboni/tests/proto/fd.pb b/bomboni/tests/proto/fd.pb new file mode 100644 index 0000000000000000000000000000000000000000..69f9a45413a539b83c953842710dcb1d2071cbc6 GIT binary patch literal 1716 zcmZuy!EVz)5VhC#+8#TOvrW=A6;Q%~wxECts8S^kfDllm0BM0^RZv2rX+(UVY)u-XuUa4qGyRv!TH$HwQN0TH;a zC5TAZAqJ0tN2qHM1um}{B;2S{OFlgQzxx zdBG#UJTN9^M|-@+y~};me+-FU>{0f4o|Q9o7kup^UcG3$d$|!tCak{+&ALW8%_n7s ziz|Qg5>GfY&@T3`gGONoz~s(L_IS={km$hZ|(iiK2ewXBw6_68u>)B zPXhLdq}7lCizWF&^Ti{QhX7K(Y#W67`<)vGp;-Rlp}8Kx+NoU!!G+z0)dyN^3#EtE z4TG>YY~D2ptHHhdTn&lX8gMn*#yD8!MY73-aql)~Ai({Ld(~PYqQL7n4Tsg@ty?sz zhodGIeighDJc>#@MddsmwJ8!xA%IjbcS_dL%RaV6; QN^1!=Cn4g}mbw4`0`M;LM*si- literal 0 HcmV?d00001 diff --git a/bomboni/tests/proto/tools.command.plus.rs b/bomboni/tests/proto/tools.command.plus.rs new file mode 100644 index 0000000..eaa7c75 --- /dev/null +++ b/bomboni/tests/proto/tools.command.plus.rs @@ -0,0 +1,113 @@ +///Implement [`prost::Name`] for `Command`. +impl ::prost::Name for Command { + const NAME: &'static str = "Command"; + const PACKAGE: &'static str = "tools.command"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Command { + pub const TYPE_URL: &'static str = "/Command"; +} +impl Command { + pub const USER_FIELD_NAME: &'static str = "user"; + pub const STATUS_FIELD_NAME: &'static str = "status"; + pub const PRINT_FIELD_NAME: &'static str = "print"; + pub const APPLY_PERMS_FIELD_NAME: &'static str = "apply_perms"; +} +impl Command { + pub const KIND_ONEOF_NAME: &'static str = "kind"; +} +impl command::Kind { + pub const STATUS_VARIANT_NAME: &'static str = "status"; + pub const PRINT_VARIANT_NAME: &'static str = "print"; + pub const APPLY_PERMS_VARIANT_NAME: &'static str = "apply_perms"; +} +impl From for command::Kind { + fn from(value: String) -> Self { + Self::Print(value) + } +} +impl From for command::Kind { + fn from(value: super::super::tools::command::command::Status) -> Self { + Self::Status(value) + } +} +impl From for command::Kind { + fn from(value: super::super::tools::perms::Perms) -> Self { + Self::ApplyPerms(value) + } +} +impl command::Kind { + pub fn get_variant_name(&self) -> &'static str { + match self { + Self::Status(_) => Self::STATUS_VARIANT_NAME, + Self::Print(_) => Self::PRINT_VARIANT_NAME, + Self::ApplyPerms(_) => Self::APPLY_PERMS_VARIANT_NAME, + } + } +} +///Implement [`prost::Name`] for `Command.Status`. +impl ::prost::Name for command::Status { + const NAME: &'static str = "Command.Status"; + const PACKAGE: &'static str = "tools.command"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl command::Status { + pub const TYPE_URL: &'static str = "/Command.Status"; +} +impl command::Status { + pub const OK_FIELD_NAME: &'static str = "ok"; + pub const ERROR_FIELD_NAME: &'static str = "error"; +} +impl command::Status { + pub const KIND_ONEOF_NAME: &'static str = "kind"; +} +impl command::status::Kind { + pub const OK_VARIANT_NAME: &'static str = "ok"; + pub const ERROR_VARIANT_NAME: &'static str = "error"; +} +impl From for command::status::Kind { + fn from(value: String) -> Self { + Self::Error(value) + } +} +/// From source variant type to owner message type. +impl From for command::Status { + fn from(value: String) -> Self { + Self { kind: Some(value.into()) } + } +} +impl From for command::status::Kind { + fn from(value: bool) -> Self { + Self::Ok(value) + } +} +/// From source variant type to owner message type. +impl From for command::Status { + fn from(value: bool) -> Self { + Self { kind: Some(value.into()) } + } +} +impl command::status::Kind { + pub fn get_variant_name(&self) -> &'static str { + match self { + Self::Ok(_) => Self::OK_VARIANT_NAME, + Self::Error(_) => Self::ERROR_VARIANT_NAME, + } + } +} +/// From oneof type to owner message type. +impl From for command::Status { + fn from(value: command::status::Kind) -> Self { + Self { kind: Some(value) } + } +} diff --git a/bomboni/tests/proto/tools.command.rs b/bomboni/tests/proto/tools.command.rs new file mode 100644 index 0000000..f153444 --- /dev/null +++ b/bomboni/tests/proto/tools.command.rs @@ -0,0 +1,38 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Command { + #[prost(string, tag = "1")] + pub user: ::prost::alloc::string::String, + #[prost(oneof = "command::Kind", tags = "2, 4, 5")] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `Command`. +pub mod command { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Status { + #[prost(oneof = "status::Kind", tags = "1, 2")] + pub kind: ::core::option::Option, + } + /// Nested message and enum types in `Status`. + pub mod status { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(bool, tag = "1")] + Ok(bool), + #[prost(string, tag = "2")] + Error(::prost::alloc::string::String), + } + } + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(message, tag = "2")] + Status(Status), + #[prost(string, tag = "4")] + Print(::prost::alloc::string::String), + #[prost(message, tag = "5")] + ApplyPerms(super::super::perms::Perms), + } +} diff --git a/bomboni/tests/proto/tools.perms.plus.rs b/bomboni/tests/proto/tools.perms.plus.rs new file mode 100644 index 0000000..a167461 --- /dev/null +++ b/bomboni/tests/proto/tools.perms.plus.rs @@ -0,0 +1,17 @@ +///Implement [`prost::Name`] for `Perms`. +impl ::prost::Name for Perms { + const NAME: &'static str = "Perms"; + const PACKAGE: &'static str = "tools.perms"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl Perms { + pub const TYPE_URL: &'static str = "/Perms"; +} +impl Perms { + pub const CODE_FIELD_NAME: &'static str = "code"; +} diff --git a/bomboni/tests/proto/tools.perms.rs b/bomboni/tests/proto/tools.perms.rs new file mode 100644 index 0000000..7c861e4 --- /dev/null +++ b/bomboni/tests/proto/tools.perms.rs @@ -0,0 +1,6 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Perms { + #[prost(uint32, tag = "1")] + pub code: u32, +} diff --git a/bomboni/tests/proto/tools.plus.rs b/bomboni/tests/proto/tools.plus.rs new file mode 100644 index 0000000..1092f02 --- /dev/null +++ b/bomboni/tests/proto/tools.plus.rs @@ -0,0 +1,133 @@ +///Implement [`prost::Name`] for `CommandRequest`. +impl ::prost::Name for CommandRequest { + const NAME: &'static str = "CommandRequest"; + const PACKAGE: &'static str = "tools"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl CommandRequest { + pub const TYPE_URL: &'static str = "/CommandRequest"; +} +impl CommandRequest { + pub const COMMAND_FIELD_NAME: &'static str = "command"; +} +///Implement [`prost::Name`] for `CommandResponse`. +impl ::prost::Name for CommandResponse { + const NAME: &'static str = "CommandResponse"; + const PACKAGE: &'static str = "tools"; + fn full_name() -> String { + format!("{}.{}", Self::PACKAGE, Self::NAME) + } + fn type_url() -> String { + Self::TYPE_URL.into() + } +} +impl CommandResponse { + pub const TYPE_URL: &'static str = "/CommandResponse"; +} +impl CommandResponse { + pub const RESULT_FIELD_NAME: &'static str = "result"; +} +impl ServingStatus { + pub const NAME: &'static str = "ServingStatus"; + pub const PACKAGE: &'static str = "tools"; +} +impl ServingStatus { + pub const UNKNOWN_VALUE_NAME: &'static str = "UNKNOWN"; + pub const SERVING_VALUE_NAME: &'static str = "SERVING"; + pub const NOT_SERVING_VALUE_NAME: &'static str = "NOT_SERVING"; + pub const VALUE_NAMES: &'static [&'static str] = &[ + Self::UNKNOWN_VALUE_NAME, + Self::SERVING_VALUE_NAME, + Self::NOT_SERVING_VALUE_NAME, + ]; +} +impl ::serde::Serialize for ServingStatus { + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + serializer.serialize_str(self.as_str_name()) + } +} +impl<'de> ::serde::Deserialize<'de> for ServingStatus { + fn deserialize(deserializer: D) -> Result + where + D: ::serde::Deserializer<'de>, + { + struct Visitor; + impl<'de> ::serde::de::Visitor<'de> for Visitor { + type Value = ServingStatus; + fn expecting( + &self, + formatter: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", ServingStatus::VALUE_NAMES) + } + fn visit_i64(self, v: i64) -> Result + where + E: ::serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|v| ServingStatus::try_from(v).ok()) + .ok_or_else(|| { + ::serde::de::Error::invalid_value( + ::serde::de::Unexpected::Signed(v), + &self, + ) + }) + } + fn visit_u64(self, v: u64) -> Result + where + E: ::serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|v| ServingStatus::try_from(v).ok()) + .ok_or_else(|| { + ::serde::de::Error::invalid_value( + ::serde::de::Unexpected::Unsigned(v), + &self, + ) + }) + } + fn visit_str(self, value: &str) -> Result + where + E: ::serde::de::Error, + { + ServingStatus::from_str_name(value) + .ok_or_else(|| ::serde::de::Error::unknown_variant( + value, + ServingStatus::VALUE_NAMES, + )) + } + } + deserializer.deserialize_any(Visitor) + } +} +pub mod serving_status_serde { + use super::*; + use ::serde::{Serialize, Deserialize}; + pub fn serialize( + value: &i32, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: ::serde::Serializer, + { + let value = ServingStatus::try_from(*value).unwrap(); + value.serialize(serializer) + } + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: ::serde::Deserializer<'de>, + { + let value = ServingStatus::deserialize(deserializer)?; + Ok(value as i32) + } +} diff --git a/bomboni/tests/proto/tools.rs b/bomboni/tests/proto/tools.rs new file mode 100644 index 0000000..5802605 --- /dev/null +++ b/bomboni/tests/proto/tools.rs @@ -0,0 +1,41 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommandRequest { + #[prost(message, optional, tag = "1")] + pub command: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommandResponse { + #[prost(string, tag = "1")] + pub result: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ServingStatus { + Unknown = 0, + Serving = 1, + NotServing = 2, +} +impl ServingStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ServingStatus::Unknown => "UNKNOWN", + ServingStatus::Serving => "SERVING", + ServingStatus::NotServing => "NOT_SERVING", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN" => Some(Self::Unknown), + "SERVING" => Some(Self::Serving), + "NOT_SERVING" => Some(Self::NotServing), + _ => None, + } + } +} diff --git a/bomboni_common/Cargo.toml b/bomboni_common/Cargo.toml new file mode 100644 index 0000000..45fe6af --- /dev/null +++ b/bomboni_common/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "bomboni_common" +version = "0.1.3" +authors = ["Tin Rabzelj "] +description = "Common things for Bomboni library." +repository = "https://github.com/tinrab/bomboni" +homepage = "https://github.com/tinrab/bomboni" +license-file = "../LICENSE" +readme = "../README.md" +edition = "2021" + +[lib] +name = "bomboni_common" +path = "src/lib.rs" + +[dependencies] +regex = "1.10.2" diff --git a/bomboni_common/src/lib.rs b/bomboni_common/src/lib.rs new file mode 100644 index 0000000..eda363d --- /dev/null +++ b/bomboni_common/src/lib.rs @@ -0,0 +1 @@ +pub mod macros; diff --git a/bomboni/src/macros/collections.rs b/bomboni_common/src/macros/collections.rs similarity index 93% rename from bomboni/src/macros/collections.rs rename to bomboni_common/src/macros/collections.rs index 88e9613..78f997b 100644 --- a/bomboni/src/macros/collections.rs +++ b/bomboni_common/src/macros/collections.rs @@ -5,7 +5,7 @@ /// # Examples /// /// ``` -/// use bomboni::count_repeating; +/// use bomboni_common::count_repeating; /// /// let count = count_repeating!(1, 1, 2, 3, 5); /// assert_eq!(count, 5); @@ -23,7 +23,7 @@ macro_rules! count_repeating { /// Create a map of key-value pairs. /// /// ``` -/// use bomboni::btree_map; +/// use bomboni_common::btree_map; /// /// let map = btree_map! { /// 1 => "first", @@ -55,7 +55,7 @@ macro_rules! btree_map { /// /// ``` /// # use std::collections::BTreeMap; -/// use bomboni::btree_map_into; +/// use bomboni_common::btree_map_into; /// /// let map: BTreeMap = btree_map_into! { /// 1 => "first", @@ -78,7 +78,7 @@ macro_rules! btree_map_into { /// Create a map of key-value pairs. /// /// ``` -/// use bomboni::hash_map; +/// use bomboni_common::hash_map; /// /// let map = hash_map! { /// 1 => "first", @@ -91,7 +91,7 @@ macro_rules! btree_map_into { /// Create a map with a given capacity. /// /// ``` -/// use bomboni::hash_map; +/// use bomboni_common::hash_map; /// # use std::collections::HashMap; /// /// let _map: HashMap = hash_map!(100); @@ -121,7 +121,7 @@ macro_rules! hash_map { /// /// ``` /// # use std::collections::HashMap; -/// use bomboni::hash_map_into; +/// use bomboni_common::hash_map_into; /// /// let map: HashMap = hash_map_into! { /// 1 => "first", @@ -142,7 +142,7 @@ macro_rules! hash_map_into { /// # Examples /// /// ``` -/// use bomboni::btree_set; +/// use bomboni_common::btree_set; /// /// let set = btree_set![1, 2, 3]; /// assert!(set.contains(&1)); @@ -170,7 +170,7 @@ macro_rules! btree_set { /// /// ``` /// # use std::collections::BTreeSet; -/// use bomboni::btree_set_into; +/// use bomboni_common::btree_set_into; /// /// let set: BTreeSet = btree_set_into![1, 2, 3]; /// assert!(set.contains(&1)); @@ -189,7 +189,7 @@ macro_rules! btree_set_into { /// # Examples /// /// ``` -/// use bomboni::hash_set; +/// use bomboni_common::hash_set; /// /// let set = hash_set![1, 2, 3]; /// assert!(set.contains(&1)); @@ -217,7 +217,7 @@ macro_rules! hash_set { /// /// ``` /// # use std::collections::HashSet; -/// use bomboni::hash_set_into; +/// use bomboni_common::hash_set_into; /// /// let set: HashSet = hash_set_into![1, 2, 3]; /// assert!(set.contains(&1)); @@ -237,7 +237,7 @@ macro_rules! hash_set_into { /// /// ``` /// # use std::collections::VecDeque; -/// use bomboni::vec_deque; +/// use bomboni_common::vec_deque; /// /// let deque = vec_deque![1, 2, 3]; /// assert_eq!(deque, VecDeque::from(vec![1, 2, 3])); @@ -262,7 +262,7 @@ macro_rules! vec_deque { /// /// ``` /// # use std::collections::VecDeque; -/// use bomboni::vec_deque_into; +/// use bomboni_common::vec_deque_into; /// /// let deque: VecDeque = vec_deque_into![1, 2, 3]; /// assert_eq!(deque, VecDeque::from(vec![1, 2, 3])); diff --git a/bomboni/src/macros/mod.rs b/bomboni_common/src/macros/mod.rs similarity index 91% rename from bomboni/src/macros/mod.rs rename to bomboni_common/src/macros/mod.rs index ac48612..062da3b 100644 --- a/bomboni/src/macros/mod.rs +++ b/bomboni_common/src/macros/mod.rs @@ -11,13 +11,12 @@ pub mod collections; /// # Examples /// /// ``` -/// use common_macros::regex; +/// use bomboni_common::regex; /// /// let re = regex!("\\d{4}-\\d{2}-\\d{2}"); /// assert!(re.is_match("2021-08-012")); /// ``` #[macro_export(local_inner_macros)] -#[cfg(feature = "regex")] macro_rules! regex { ($re:literal $(,)?) => {{ static REGEX: ::std::sync::OnceLock = ::std::sync::OnceLock::new(); diff --git a/bomboni_derive/Cargo.toml b/bomboni_derive/Cargo.toml index 41fe437..62f6601 100644 --- a/bomboni_derive/Cargo.toml +++ b/bomboni_derive/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bomboni_derive" -version = "0.1.2" +version = "0.1.3" authors = ["Tin Rabzelj "] -description = "Macros for Bomboni library" +description = "Provides derive implementations for Bomboni library." repository = "https://github.com/tinrab/bomboni" homepage = "https://github.com/tinrab/bomboni" license-file = "../LICENSE" diff --git a/bomboni_prost/Cargo.toml b/bomboni_prost/Cargo.toml index 371a9fa..827a83e 100644 --- a/bomboni_prost/Cargo.toml +++ b/bomboni_prost/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "bomboni_prost" -version = "0.1.0" +version = "0.1.3" authors = ["Tin Rabzelj "] -description = "Utilities for working with prost. Part of Bomboni library" +description = "Utilities for working with prost. Part of Bomboni library." repository = "https://github.com/tinrab/bomboni" homepage = "https://github.com/tinrab/bomboni" license-file = "../LICENSE" diff --git a/bomboni_prost/src/enums.rs b/bomboni_prost/src/enums.rs index dabee97..d133ad1 100644 --- a/bomboni_prost/src/enums.rs +++ b/bomboni_prost/src/enums.rs @@ -121,10 +121,10 @@ fn write_enum_serde(context: &Context, s: &mut TokenStream, enum_type: &EnumDesc } }); - // Utility for working with i32s in message fields. - // Usable with #[serde(with = "...")] let mod_ident = format_ident!("{}_serde", enum_type.name().to_case(Case::Snake)); s.extend(quote! { + /// Utility for working with i32s in message fields. + /// Usable with #[serde(with = "...")] pub mod #mod_ident { use super::*; use ::serde::{Serialize, Deserialize}; diff --git a/bomboni_prost/src/messages.rs b/bomboni_prost/src/messages.rs index 31f6ab1..70e209d 100644 --- a/bomboni_prost/src/messages.rs +++ b/bomboni_prost/src/messages.rs @@ -42,9 +42,15 @@ fn write_message_name(context: &Context, s: &mut TokenStream, message: &Descript let package_proto_name = Literal::string(&context.package_name); let type_url = if let Some(domain) = context.config.domain.as_ref() { - Literal::string(&format!("{}/{}", domain, message_proto_name)) + Literal::string(&format!( + "{}/{}.{}", + domain, &context.package_name, message_proto_name + )) } else { - Literal::string(&format!("/{}", message_proto_name)) + Literal::string(&format!( + "/{}.{}", + &context.package_name, message_proto_name + )) }; let comment = format_comment!("Implement [`prost::Name`] for `{}`.", message_proto_name); diff --git a/bomboni_proto/Cargo.toml b/bomboni_proto/Cargo.toml new file mode 100644 index 0000000..c635ecf --- /dev/null +++ b/bomboni_proto/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "bomboni_proto" +version = "0.1.3" +authors = ["Tin Rabzelj "] +description = "Utilities for working with Protobuf/gRPC. Part of Bomboni library." +repository = "https://github.com/tinrab/bomboni" +homepage = "https://github.com/tinrab/bomboni" +license-file = "../LICENSE" +readme = "../README.md" +edition = "2021" + +[lib] +name = "bomboni_proto" +path = "src/lib.rs" + +[features] +testing = [] + +[dependencies] +thiserror = "1.0.50" +itertools = "0.11.0" +chrono = { version = "0.4.31", features = ["serde"] } +prost = "0.12.1" +serde = { version = "1.0.192", features = ["derive"] } +pot = "3.0.0" + +[dev-dependencies] +serde_json = "1.0.108" + +[build-dependencies] +bomboni_prost = { path = "../bomboni_prost", version = "0.1.3" } +prost-build = "0.12.1" diff --git a/bomboni/build.rs b/bomboni_proto/build.rs similarity index 74% rename from bomboni/build.rs rename to bomboni_proto/build.rs index 1ad1e7f..355a044 100644 --- a/bomboni/build.rs +++ b/bomboni_proto/build.rs @@ -44,8 +44,8 @@ fn main() -> Result<(), Box> { let mut config = prost_build::Config::new(); config - .out_dir("./src/proto") - .file_descriptor_set_path("./src/proto/fd.pb") + .out_dir("./src") + .file_descriptor_set_path("./src/fd.pb") .compile_well_known_types() .protoc_arg("--experimental_allow_proto3_optional") .btree_map(["."]); @@ -59,14 +59,32 @@ fn main() -> Result<(), Box> { "#, ); } + for type_path in get_default_type_paths() { + config.field_attribute( + type_path, + r#"#[serde(default, skip_serializing_if = "crate::serde::helpers::is_default")]"#, + ); + } for type_path in get_copy_type_paths() { config.type_attribute(type_path, r#"#[derive(Copy)]"#); } + config.type_attribute( + ".google.rpc.Status", + r#"#[derive(::serde::Serialize, ::serde::Deserialize)]"#, + ); + config.field_attribute( + ".google.rpc.Status.details", + r#"#[serde(with = "crate::google::rpc::status::details_serde")]"#, + ); + config.field_attribute( + ".google.rpc.Status.code", + r#"#[serde(with = "crate::google::rpc::code_serde")]"#, + ); config.compile_protos(&proto_paths, &["./proto"])?; compile(CompileConfig { - file_descriptor_set_path: "./src/proto/fd.pb".into(), - output_path: "./src/proto".into(), + file_descriptor_set_path: "./src/fd.pb".into(), + output_path: "./src".into(), api: ApiConfig { domain: Some("type.googleapis.com".into()), ..Default::default() @@ -94,6 +112,12 @@ fn get_camel_cased_type_paths() -> impl Iterator { .map(|type_name| format!(".google.rpc.{}", type_name)) } +fn get_default_type_paths() -> impl Iterator { + ["ErrorInfo.metadata"] + .into_iter() + .map(|type_name| format!(".google.rpc.{}", type_name)) +} + fn get_copy_type_paths() -> impl Iterator { ["Timestamp", "Empty", "Duration"] .into_iter() diff --git a/bomboni/proto/google/api/annotations.proto b/bomboni_proto/proto/google/api/annotations.proto similarity index 100% rename from bomboni/proto/google/api/annotations.proto rename to bomboni_proto/proto/google/api/annotations.proto diff --git a/bomboni/proto/google/api/client.proto b/bomboni_proto/proto/google/api/client.proto similarity index 100% rename from bomboni/proto/google/api/client.proto rename to bomboni_proto/proto/google/api/client.proto diff --git a/bomboni/proto/google/api/field_behavior.proto b/bomboni_proto/proto/google/api/field_behavior.proto similarity index 100% rename from bomboni/proto/google/api/field_behavior.proto rename to bomboni_proto/proto/google/api/field_behavior.proto diff --git a/bomboni/proto/google/api/http.proto b/bomboni_proto/proto/google/api/http.proto similarity index 100% rename from bomboni/proto/google/api/http.proto rename to bomboni_proto/proto/google/api/http.proto diff --git a/bomboni/proto/google/api/httpbody.proto b/bomboni_proto/proto/google/api/httpbody.proto similarity index 100% rename from bomboni/proto/google/api/httpbody.proto rename to bomboni_proto/proto/google/api/httpbody.proto diff --git a/bomboni/proto/google/api/resource.proto b/bomboni_proto/proto/google/api/resource.proto similarity index 100% rename from bomboni/proto/google/api/resource.proto rename to bomboni_proto/proto/google/api/resource.proto diff --git a/bomboni/proto/google/protobuf/any.proto b/bomboni_proto/proto/google/protobuf/any.proto similarity index 100% rename from bomboni/proto/google/protobuf/any.proto rename to bomboni_proto/proto/google/protobuf/any.proto diff --git a/bomboni/proto/google/protobuf/api.proto b/bomboni_proto/proto/google/protobuf/api.proto similarity index 100% rename from bomboni/proto/google/protobuf/api.proto rename to bomboni_proto/proto/google/protobuf/api.proto diff --git a/bomboni/proto/google/protobuf/descriptor.proto b/bomboni_proto/proto/google/protobuf/descriptor.proto similarity index 100% rename from bomboni/proto/google/protobuf/descriptor.proto rename to bomboni_proto/proto/google/protobuf/descriptor.proto diff --git a/bomboni/proto/google/protobuf/duration.proto b/bomboni_proto/proto/google/protobuf/duration.proto similarity index 100% rename from bomboni/proto/google/protobuf/duration.proto rename to bomboni_proto/proto/google/protobuf/duration.proto diff --git a/bomboni/proto/google/protobuf/empty.proto b/bomboni_proto/proto/google/protobuf/empty.proto similarity index 100% rename from bomboni/proto/google/protobuf/empty.proto rename to bomboni_proto/proto/google/protobuf/empty.proto diff --git a/bomboni/proto/google/protobuf/field_mask.proto b/bomboni_proto/proto/google/protobuf/field_mask.proto similarity index 100% rename from bomboni/proto/google/protobuf/field_mask.proto rename to bomboni_proto/proto/google/protobuf/field_mask.proto diff --git a/bomboni/proto/google/protobuf/source_context.proto b/bomboni_proto/proto/google/protobuf/source_context.proto similarity index 100% rename from bomboni/proto/google/protobuf/source_context.proto rename to bomboni_proto/proto/google/protobuf/source_context.proto diff --git a/bomboni/proto/google/protobuf/struct.proto b/bomboni_proto/proto/google/protobuf/struct.proto similarity index 100% rename from bomboni/proto/google/protobuf/struct.proto rename to bomboni_proto/proto/google/protobuf/struct.proto diff --git a/bomboni/proto/google/protobuf/timestamp.proto b/bomboni_proto/proto/google/protobuf/timestamp.proto similarity index 100% rename from bomboni/proto/google/protobuf/timestamp.proto rename to bomboni_proto/proto/google/protobuf/timestamp.proto diff --git a/bomboni/proto/google/protobuf/type.proto b/bomboni_proto/proto/google/protobuf/type.proto similarity index 100% rename from bomboni/proto/google/protobuf/type.proto rename to bomboni_proto/proto/google/protobuf/type.proto diff --git a/bomboni/proto/google/protobuf/wrappers.proto b/bomboni_proto/proto/google/protobuf/wrappers.proto similarity index 100% rename from bomboni/proto/google/protobuf/wrappers.proto rename to bomboni_proto/proto/google/protobuf/wrappers.proto diff --git a/bomboni/proto/google/rpc/code.proto b/bomboni_proto/proto/google/rpc/code.proto similarity index 100% rename from bomboni/proto/google/rpc/code.proto rename to bomboni_proto/proto/google/rpc/code.proto diff --git a/bomboni/proto/google/rpc/error_details.proto b/bomboni_proto/proto/google/rpc/error_details.proto similarity index 100% rename from bomboni/proto/google/rpc/error_details.proto rename to bomboni_proto/proto/google/rpc/error_details.proto diff --git a/bomboni/proto/google/rpc/status.proto b/bomboni_proto/proto/google/rpc/status.proto similarity index 100% rename from bomboni/proto/google/rpc/status.proto rename to bomboni_proto/proto/google/rpc/status.proto diff --git a/bomboni/proto/google/type/calendar_period.proto b/bomboni_proto/proto/google/type/calendar_period.proto similarity index 100% rename from bomboni/proto/google/type/calendar_period.proto rename to bomboni_proto/proto/google/type/calendar_period.proto diff --git a/bomboni/proto/google/type/color.proto b/bomboni_proto/proto/google/type/color.proto similarity index 100% rename from bomboni/proto/google/type/color.proto rename to bomboni_proto/proto/google/type/color.proto diff --git a/bomboni/proto/google/type/date.proto b/bomboni_proto/proto/google/type/date.proto similarity index 100% rename from bomboni/proto/google/type/date.proto rename to bomboni_proto/proto/google/type/date.proto diff --git a/bomboni/proto/google/type/datetime.proto b/bomboni_proto/proto/google/type/datetime.proto similarity index 100% rename from bomboni/proto/google/type/datetime.proto rename to bomboni_proto/proto/google/type/datetime.proto diff --git a/bomboni/proto/google/type/dayofweek.proto b/bomboni_proto/proto/google/type/dayofweek.proto similarity index 100% rename from bomboni/proto/google/type/dayofweek.proto rename to bomboni_proto/proto/google/type/dayofweek.proto diff --git a/bomboni/proto/google/type/decimal.proto b/bomboni_proto/proto/google/type/decimal.proto similarity index 100% rename from bomboni/proto/google/type/decimal.proto rename to bomboni_proto/proto/google/type/decimal.proto diff --git a/bomboni/proto/google/type/expr.proto b/bomboni_proto/proto/google/type/expr.proto similarity index 100% rename from bomboni/proto/google/type/expr.proto rename to bomboni_proto/proto/google/type/expr.proto diff --git a/bomboni/proto/google/type/fraction.proto b/bomboni_proto/proto/google/type/fraction.proto similarity index 100% rename from bomboni/proto/google/type/fraction.proto rename to bomboni_proto/proto/google/type/fraction.proto diff --git a/bomboni/proto/google/type/interval.proto b/bomboni_proto/proto/google/type/interval.proto similarity index 100% rename from bomboni/proto/google/type/interval.proto rename to bomboni_proto/proto/google/type/interval.proto diff --git a/bomboni/proto/google/type/latlng.proto b/bomboni_proto/proto/google/type/latlng.proto similarity index 100% rename from bomboni/proto/google/type/latlng.proto rename to bomboni_proto/proto/google/type/latlng.proto diff --git a/bomboni/proto/google/type/localized_text.proto b/bomboni_proto/proto/google/type/localized_text.proto similarity index 100% rename from bomboni/proto/google/type/localized_text.proto rename to bomboni_proto/proto/google/type/localized_text.proto diff --git a/bomboni/proto/google/type/money.proto b/bomboni_proto/proto/google/type/money.proto similarity index 100% rename from bomboni/proto/google/type/money.proto rename to bomboni_proto/proto/google/type/money.proto diff --git a/bomboni/proto/google/type/month.proto b/bomboni_proto/proto/google/type/month.proto similarity index 100% rename from bomboni/proto/google/type/month.proto rename to bomboni_proto/proto/google/type/month.proto diff --git a/bomboni/proto/google/type/phone_number.proto b/bomboni_proto/proto/google/type/phone_number.proto similarity index 100% rename from bomboni/proto/google/type/phone_number.proto rename to bomboni_proto/proto/google/type/phone_number.proto diff --git a/bomboni/proto/google/type/postal_address.proto b/bomboni_proto/proto/google/type/postal_address.proto similarity index 100% rename from bomboni/proto/google/type/postal_address.proto rename to bomboni_proto/proto/google/type/postal_address.proto diff --git a/bomboni/proto/google/type/quaternion.proto b/bomboni_proto/proto/google/type/quaternion.proto similarity index 100% rename from bomboni/proto/google/type/quaternion.proto rename to bomboni_proto/proto/google/type/quaternion.proto diff --git a/bomboni/proto/google/type/timeofday.proto b/bomboni_proto/proto/google/type/timeofday.proto similarity index 100% rename from bomboni/proto/google/type/timeofday.proto rename to bomboni_proto/proto/google/type/timeofday.proto diff --git a/bomboni/src/proto/.gitignore b/bomboni_proto/src/.gitignore similarity index 100% rename from bomboni/src/proto/.gitignore rename to bomboni_proto/src/.gitignore diff --git a/bomboni/src/proto/fd.pb b/bomboni_proto/src/fd.pb similarity index 100% rename from bomboni/src/proto/fd.pb rename to bomboni_proto/src/fd.pb diff --git a/bomboni_proto/src/google/mod.rs b/bomboni_proto/src/google/mod.rs new file mode 100644 index 0000000..69c2ef9 --- /dev/null +++ b/bomboni_proto/src/google/mod.rs @@ -0,0 +1,2 @@ +pub mod protobuf; +pub mod rpc; diff --git a/bomboni_proto/src/google/protobuf/any.rs b/bomboni_proto/src/google/protobuf/any.rs new file mode 100644 index 0000000..d81bd7c --- /dev/null +++ b/bomboni_proto/src/google/protobuf/any.rs @@ -0,0 +1,177 @@ +use prost::{DecodeError, EncodeError, Message, Name}; + +use super::Any; + +impl Any { + pub fn new(type_url: String, value: Vec) -> Self { + Any { type_url, value } + } + + pub fn pack_from(message: &T) -> Result + where + T: Name, + { + let type_url = T::type_url(); + let mut value = Vec::new(); + Message::encode(message, &mut value)?; + Ok(Any { type_url, value }) + } + + pub fn unpack_into(self) -> Result + where + T: Default + Name, + { + let expected_type_url = T::type_url(); + if expected_type_url != self.type_url { + return Err(DecodeError::new(format!( + "expected type URL `{}`, but got `{}`", + expected_type_url, &self.type_url + ))); + } + T::decode(&*self.value) + } +} + +#[macro_export(local_inner_macros)] +macro_rules! impl_proto_any_serde { + ([$($message:ty),* $(,)?]) => { + /// Serialize different messages determined by TypeURL. + pub fn serialize( + value: &$crate::google::protobuf::Any, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: ::serde::Serializer, + { + use ::serde::Serialize; + + #[derive(::serde::Serialize)] + struct Proxy { + #[serde(rename = "@type")] + type_url: String, + #[serde(flatten)] + message: T, + } + + match value.type_url.as_str() { + $( + <$message>::TYPE_URL => { + Proxy { + type_url: <$message>::TYPE_URL.into(), + message: value.clone().unpack_into::<$message>().unwrap(), + }.serialize(serializer) + } + )* + _ => { + ::core::unimplemented!("any serialize for type url {}", value.type_url) + } + } + } + + /// Deserialize different messages based on TypeURL. + /// We deserialize to a proxy Value form `pot` library then convert to the target message type. + /// Pot is used because it's self-describing and supports all of serde's types. + pub fn deserialize<'de, D>( + deserializer: D, + ) -> Result<$crate::google::protobuf::Any, >::Error> + where + D: ::serde::Deserializer<'de>, + { + use ::serde::Deserialize; + use ::serde::de::Error; + use ::pot::Value; + + const TYPE_FIELD_NAME: &'static str= "@type"; + + let proxy = Value::deserialize(deserializer)?; + let (type_url, mappings) = if let Value::Mappings(mut mappings) = proxy { + let type_url = mappings + .remove( + mappings + .iter() + .position(|(k, _)| ::std::matches!(k, Value::String(k) if k == TYPE_FIELD_NAME)) + .ok_or_else(|| Error::missing_field(TYPE_FIELD_NAME))?, + ) + .1; + if let Value::String(type_url) = type_url { + (type_url.to_string(), mappings) + } else { + return Err(Error::custom("expected a string @type field")); + } + } else { + return Err(Error::custom("expected a map")); + }; + + match type_url.as_str() { + $( + <$message>::TYPE_URL => { + let message = Value::Mappings(mappings) + .deserialize_as::<$message>() + .map_err(|err| { + Error::custom(::std::format!("failed to deserialize {}: {}", type_url, err)) + })?; + $crate::google::protobuf::Any::pack_from(&message) + .map_err(|err| { + Error::custom(::std::format!("failed to pack {}: {}", type_url, err)) + }) + } + )* + _ => { + ::core::unimplemented!("any deserialize for type url {}", type_url) + } + } + } + }; +} + +#[cfg(test)] +mod tests { + use crate::google::rpc::{ErrorInfo, RetryInfo}; + use serde::{Deserialize, Serialize}; + + use super::*; + + #[test] + fn it_works() { + let msg = ErrorInfo { + reason: "reason".to_string(), + domain: "domain".to_string(), + metadata: Default::default(), + }; + let any = Any::pack_from(&msg).unwrap(); + let decoded: ErrorInfo = any.unpack_into().unwrap(); + assert_eq!(decoded, msg); + } + + #[test] + fn errors() { + let any = Any::pack_from(&ErrorInfo::default()).unwrap(); + assert!(any.unpack_into::().is_err()); + } + + #[test] + fn any_serde() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Item { + #[serde(with = "item_serde")] + any: Any, + } + mod item_serde { + use crate::google::rpc::ErrorInfo; + + impl_proto_any_serde!([ErrorInfo]); + } + + let item = Item { + any: Any::pack_from(&ErrorInfo { + reason: "reason".to_string(), + domain: "domain".to_string(), + metadata: Default::default(), + }) + .unwrap(), + }; + let js = serde_json::to_string_pretty(&item).unwrap(); + let decoded = serde_json::from_str::(&js).unwrap(); + assert_eq!(decoded, item); + } +} diff --git a/bomboni/src/proto/google/duration.rs b/bomboni_proto/src/google/protobuf/duration.rs similarity index 75% rename from bomboni/src/proto/google/duration.rs rename to bomboni_proto/src/google/protobuf/duration.rs index fd9652a..dc610f6 100644 --- a/bomboni/src/proto/google/duration.rs +++ b/bomboni_proto/src/google/protobuf/duration.rs @@ -1,8 +1,6 @@ +use crate::serde::helpers as serde_helpers; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::proto::serde_helpers; - -use super::protobuf::Duration; use chrono::Duration as ChronoDuration; use std::{ fmt::{self, Display, Formatter}, @@ -11,6 +9,8 @@ use std::{ }; use thiserror::Error; +use super::Duration; + #[derive(Error, Debug)] pub enum DurationError { #[error("duration is out of range")] @@ -231,36 +231,36 @@ mod tests { (line!(), i64::MIN , 1, i64::MIN + 1, -999_999_999), (line!(), i64::MIN , 1_000_000_000, i64::MIN + 1, 0), (line!(), i64::MIN , -1_000_000_000, i64::MIN , -999_999_999), - // (line!(), i64::MIN + 1, -1_000_000_000, i64::MIN , 0), - // (line!(), i64::MIN + 2, -1_000_000_000, i64::MIN + 1, 0), - // (line!(), i64::MIN , -1_999_999_998, i64::MIN , -999_999_999), - // (line!(), i64::MIN + 1, -1_999_999_998, i64::MIN , -999_999_998), - // (line!(), i64::MIN + 2, -1_999_999_998, i64::MIN + 1, -999_999_998), - // (line!(), i64::MIN , -1_999_999_999, i64::MIN , -999_999_999), - // (line!(), i64::MIN + 1, -1_999_999_999, i64::MIN , -999_999_999), - // (line!(), i64::MIN + 2, -1_999_999_999, i64::MIN + 1, -999_999_999), - // (line!(), i64::MIN , -2_000_000_000, i64::MIN , -999_999_999), - // (line!(), i64::MIN + 1, -2_000_000_000, i64::MIN , -999_999_999), - // (line!(), i64::MIN + 2, -2_000_000_000, i64::MIN , 0), - // (line!(), i64::MIN , -999_999_998, i64::MIN , -999_999_998), - // (line!(), i64::MIN + 1, -999_999_998, i64::MIN + 1, -999_999_998), - // (line!(), i64::MAX , 0, i64::MAX , 0), - // (line!(), i64::MAX - 1, 0, i64::MAX - 1, 0), - // (line!(), i64::MAX , -1, i64::MAX - 1, 999_999_999), - // (line!(), i64::MAX , 1_000_000_000, i64::MAX , 999_999_999), - // (line!(), i64::MAX - 1, 1_000_000_000, i64::MAX , 0), - // (line!(), i64::MAX - 2, 1_000_000_000, i64::MAX - 1, 0), - // (line!(), i64::MAX , 1_999_999_998, i64::MAX , 999_999_999), - // (line!(), i64::MAX - 1, 1_999_999_998, i64::MAX , 999_999_998), - // (line!(), i64::MAX - 2, 1_999_999_998, i64::MAX - 1, 999_999_998), - // (line!(), i64::MAX , 1_999_999_999, i64::MAX , 999_999_999), - // (line!(), i64::MAX - 1, 1_999_999_999, i64::MAX , 999_999_999), - // (line!(), i64::MAX - 2, 1_999_999_999, i64::MAX - 1, 999_999_999), - // (line!(), i64::MAX , 2_000_000_000, i64::MAX , 999_999_999), - // (line!(), i64::MAX - 1, 2_000_000_000, i64::MAX , 999_999_999), - // (line!(), i64::MAX - 2, 2_000_000_000, i64::MAX , 0), - // (line!(), i64::MAX , 999_999_998, i64::MAX , 999_999_998), - // (line!(), i64::MAX - 1, 999_999_998, i64::MAX - 1, 999_999_998), + (line!(), i64::MIN + 1, -1_000_000_000, i64::MIN , 0), + (line!(), i64::MIN + 2, -1_000_000_000, i64::MIN + 1, 0), + (line!(), i64::MIN , -1_999_999_998, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -1_999_999_998, i64::MIN , -999_999_998), + (line!(), i64::MIN + 2, -1_999_999_998, i64::MIN + 1, -999_999_998), + (line!(), i64::MIN , -1_999_999_999, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -1_999_999_999, i64::MIN , -999_999_999), + (line!(), i64::MIN + 2, -1_999_999_999, i64::MIN + 1, -999_999_999), + (line!(), i64::MIN , -2_000_000_000, i64::MIN , -999_999_999), + (line!(), i64::MIN + 1, -2_000_000_000, i64::MIN , -999_999_999), + (line!(), i64::MIN + 2, -2_000_000_000, i64::MIN , 0), + (line!(), i64::MIN , -999_999_998, i64::MIN , -999_999_998), + (line!(), i64::MIN + 1, -999_999_998, i64::MIN + 1, -999_999_998), + (line!(), i64::MAX , 0, i64::MAX , 0), + (line!(), i64::MAX - 1, 0, i64::MAX - 1, 0), + (line!(), i64::MAX , -1, i64::MAX - 1, 999_999_999), + (line!(), i64::MAX , 1_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_000_000_000, i64::MAX , 0), + (line!(), i64::MAX - 2, 1_000_000_000, i64::MAX - 1, 0), + (line!(), i64::MAX , 1_999_999_998, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_999_999_998, i64::MAX , 999_999_998), + (line!(), i64::MAX - 2, 1_999_999_998, i64::MAX - 1, 999_999_998), + (line!(), i64::MAX , 1_999_999_999, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 1_999_999_999, i64::MAX , 999_999_999), + (line!(), i64::MAX - 2, 1_999_999_999, i64::MAX - 1, 999_999_999), + (line!(), i64::MAX , 2_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 1, 2_000_000_000, i64::MAX , 999_999_999), + (line!(), i64::MAX - 2, 2_000_000_000, i64::MAX , 0), + (line!(), i64::MAX , 999_999_998, i64::MAX , 999_999_998), + (line!(), i64::MAX - 1, 999_999_998, i64::MAX - 1, 999_999_998), ]; for case in cases.iter() { diff --git a/bomboni/src/proto/google/empty.rs b/bomboni_proto/src/google/protobuf/empty.rs similarity index 95% rename from bomboni/src/proto/google/empty.rs rename to bomboni_proto/src/google/protobuf/empty.rs index ea48796..f452b7b 100644 --- a/bomboni/src/proto/google/empty.rs +++ b/bomboni_proto/src/google/protobuf/empty.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use super::protobuf::Empty; +use super::Empty; impl Empty { pub fn new() -> Self { diff --git a/bomboni/src/proto/google/field_mask.rs b/bomboni_proto/src/google/protobuf/field_mask.rs similarity index 96% rename from bomboni/src/proto/google/field_mask.rs rename to bomboni_proto/src/google/protobuf/field_mask.rs index 0838486..99009d1 100644 --- a/bomboni/src/proto/google/field_mask.rs +++ b/bomboni_proto/src/google/protobuf/field_mask.rs @@ -1,8 +1,7 @@ +use crate::serde::helpers as serde_helpers; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::proto::serde_helpers; - -use super::protobuf::FieldMask; +use super::FieldMask; impl FieldMask { pub fn new(paths: Vec) -> Self { diff --git a/bomboni_proto/src/google/protobuf/mod.rs b/bomboni_proto/src/google/protobuf/mod.rs new file mode 100644 index 0000000..6a3171f --- /dev/null +++ b/bomboni_proto/src/google/protobuf/mod.rs @@ -0,0 +1,9 @@ +include!("../../google.protobuf.rs"); +include!("../../google.protobuf.plus.rs"); + +mod any; +mod duration; +mod empty; +mod field_mask; +mod timestamp; +mod wrappers; diff --git a/bomboni/src/proto/google/timestamp.rs b/bomboni_proto/src/google/protobuf/timestamp.rs similarity index 99% rename from bomboni/src/proto/google/timestamp.rs rename to bomboni_proto/src/google/protobuf/timestamp.rs index ae7c59d..e2d066a 100644 --- a/bomboni/src/proto/google/timestamp.rs +++ b/bomboni_proto/src/google/protobuf/timestamp.rs @@ -7,9 +7,10 @@ use std::{ use chrono::{DateTime, NaiveDateTime, Utc}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use super::protobuf::Timestamp; use thiserror::Error; +use super::Timestamp; + #[derive(Error, Debug)] pub enum TimestampError { #[error("invalid nanoseconds")] diff --git a/bomboni/src/proto/google/wrappers.rs b/bomboni_proto/src/google/protobuf/wrappers.rs similarity index 95% rename from bomboni/src/proto/google/wrappers.rs rename to bomboni_proto/src/google/protobuf/wrappers.rs index 5a08452..6bc3e92 100644 --- a/bomboni/src/proto/google/wrappers.rs +++ b/bomboni_proto/src/google/protobuf/wrappers.rs @@ -1,10 +1,10 @@ -use crate::proto::google::protobuf::{ - Any, BoolValue, BytesValue, DoubleValue, Duration, Empty, FieldMask, FloatValue, Int32Value, - Int64Value, StringValue, Timestamp, UInt32Value, UInt64Value, +use crate::google::protobuf::{ + BoolValue, BytesValue, DoubleValue, FloatValue, Int32Value, Int64Value, StringValue, + UInt32Value, UInt64Value, }; -use crate::proto::serde_helpers; +use crate::serde::helpers as serde_helpers; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::fmt; + use std::fmt::{Display, Formatter}; use std::num::{ParseFloatError, ParseIntError}; use std::str::FromStr; @@ -251,7 +251,7 @@ mod tests { #[test] fn serde() { - let x: DoubleValue = f64::consts::PI.into(); + let x: DoubleValue = 42f32.into(); let encoded = serde_json::to_string(&x).unwrap(); let decoded: DoubleValue = serde_json::from_str(&encoded).unwrap(); assert_eq!(decoded, x); diff --git a/bomboni_proto/src/google/rpc/mod.rs b/bomboni_proto/src/google/rpc/mod.rs new file mode 100644 index 0000000..55a6c89 --- /dev/null +++ b/bomboni_proto/src/google/rpc/mod.rs @@ -0,0 +1,4 @@ +include!("../../google.rpc.rs"); +include!("../../google.rpc.plus.rs"); + +pub mod status; diff --git a/bomboni_proto/src/google/rpc/status.rs b/bomboni_proto/src/google/rpc/status.rs new file mode 100644 index 0000000..f7360f4 --- /dev/null +++ b/bomboni_proto/src/google/rpc/status.rs @@ -0,0 +1,106 @@ +use crate::google::protobuf::Any; + +use super::{Code, Status}; + +impl Status { + pub fn new(code: Code, message: String, details: Vec) -> Self { + Status { + code: code as i32, + message, + details, + } + } +} + +pub mod details_serde { + use super::*; + use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(details: &[Any], serializer: S) -> Result + where + S: Serializer, + { + struct Proxy<'a>(&'a Any); + impl<'a> Serialize for Proxy<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + detail_serde::serialize(self.0, serializer) + } + } + let mut seq = serializer.serialize_seq(Some(details.len()))?; + for detail in details { + seq.serialize_element(&Proxy(detail))?; + } + seq.end() + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + struct Proxy(Any); + impl<'de> Deserialize<'de> for Proxy { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + detail_serde::deserialize(deserializer).map(Proxy) + } + } + let details: Vec = Vec::deserialize(deserializer)?; + Ok(details.into_iter().map(|p| p.0).collect()) + } +} + +pub mod detail_serde { + use crate::{ + google::rpc::{ + BadRequest, DebugInfo, ErrorInfo, Help, LocalizedMessage, PreconditionFailure, + QuotaFailure, RequestInfo, ResourceInfo, RetryInfo, + }, + impl_proto_any_serde, + }; + + impl_proto_any_serde!([ + BadRequest, + DebugInfo, + ErrorInfo, + Help, + LocalizedMessage, + PreconditionFailure, + QuotaFailure, + RequestInfo, + ResourceInfo, + RetryInfo, + ]); +} + +#[cfg(test)] +mod tests { + use crate::google::rpc::ErrorInfo; + + use super::*; + + #[test] + fn serde() { + let s = Status::new( + Code::InvalidArgument, + "error".to_string(), + vec![Any::pack_from(&ErrorInfo { + reason: "a".to_string(), + domain: "b".to_string(), + metadata: Default::default(), + }) + .unwrap()], + ); + let js = serde_json::to_string(&s).unwrap(); + assert_eq!( + js, + r#"{"code":"INVALID_ARGUMENT","message":"error","details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"a","domain":"b"}]}"# + ); + let decoded: Status = serde_json::from_str(&js).unwrap(); + assert_eq!(decoded, s); + } +} diff --git a/bomboni_proto/src/lib.rs b/bomboni_proto/src/lib.rs new file mode 100644 index 0000000..6eb961e --- /dev/null +++ b/bomboni_proto/src/lib.rs @@ -0,0 +1,2 @@ +pub mod google; +pub mod serde; diff --git a/bomboni/src/proto/serde_helpers.rs b/bomboni_proto/src/serde/helpers.rs similarity index 86% rename from bomboni/src/proto/serde_helpers.rs rename to bomboni_proto/src/serde/helpers.rs index 3e4f7d0..d90469a 100644 --- a/bomboni/src/proto/serde_helpers.rs +++ b/bomboni_proto/src/serde/helpers.rs @@ -1,17 +1,12 @@ -use crate::proto::google::protobuf::Duration; -use chrono::Duration as ChronoDuration; -use serde::Serialize; -use serde::{de, ser}; -use serde::{Deserialize, Deserializer, Serializer}; -use serde_json::Value; +use crate::google::protobuf::Duration; +use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::fmt::{Display, Formatter}; use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; + use std::str::FromStr; -use std::time::Duration as StdDuration; -pub fn skip_if_default(value: &T) -> bool +pub fn is_default(value: &T) -> bool where T: Default + PartialEq, { @@ -103,23 +98,23 @@ pub mod string_list { } // Credit: `handlebars = "4.3.1"` -pub fn is_truthy(value: &Value, include_zero: bool) -> bool { - match value { - Value::Bool(ref i) => *i, - Value::Number(ref n) => { - if include_zero { - n.as_f64().map(|f| !f.is_nan()).unwrap_or(false) - } else { - // there is no inifity in json/serde_json - n.as_f64().map(|f| f.is_normal()).unwrap_or(false) - } - } - Value::Null => false, - Value::String(ref i) => !i.is_empty(), - Value::Array(ref i) => !i.is_empty(), - Value::Object(ref i) => !i.is_empty(), - } -} +// pub fn is_truthy(value: &Value, include_zero: bool) -> bool { +// match value { +// Value::Bool(ref i) => *i, +// Value::Number(ref n) => { +// if include_zero { +// n.as_f64().map(|f| !f.is_nan()).unwrap_or(false) +// } else { +// // there is no inifity in json/serde_json +// n.as_f64().map(|f| f.is_normal()).unwrap_or(false) +// } +// } +// Value::Null => false, +// Value::String(ref i) => !i.is_empty(), +// Value::Array(ref i) => !i.is_empty(), +// Value::Object(ref i) => !i.is_empty(), +// } +// } pub mod duration { use super::*; @@ -166,6 +161,7 @@ pub mod duration { #[cfg(test)] mod tests { use super::*; + use chrono::Duration as ChronoDuration; #[test] fn duration() { diff --git a/bomboni_proto/src/serde/mod.rs b/bomboni_proto/src/serde/mod.rs new file mode 100644 index 0000000..1630fab --- /dev/null +++ b/bomboni_proto/src/serde/mod.rs @@ -0,0 +1 @@ +pub mod helpers; diff --git a/bomboni/tests/prost.rs b/bomboni_proto/tests/prost.rs similarity index 100% rename from bomboni/tests/prost.rs rename to bomboni_proto/tests/prost.rs diff --git a/bomboni/tests/proto/.gitignore b/bomboni_proto/tests/proto/.gitignore similarity index 100% rename from bomboni/tests/proto/.gitignore rename to bomboni_proto/tests/proto/.gitignore diff --git a/bomboni/tests/proto/command/command.proto b/bomboni_proto/tests/proto/command/command.proto similarity index 100% rename from bomboni/tests/proto/command/command.proto rename to bomboni_proto/tests/proto/command/command.proto diff --git a/bomboni/tests/proto/perms/perms.proto b/bomboni_proto/tests/proto/perms/perms.proto similarity index 100% rename from bomboni/tests/proto/perms/perms.proto rename to bomboni_proto/tests/proto/perms/perms.proto diff --git a/bomboni/tests/proto/tools.proto b/bomboni_proto/tests/proto/tools.proto similarity index 100% rename from bomboni/tests/proto/tools.proto rename to bomboni_proto/tests/proto/tools.proto diff --git a/bomboni_request/Cargo.toml b/bomboni_request/Cargo.toml new file mode 100644 index 0000000..9e7575e --- /dev/null +++ b/bomboni_request/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "bomboni_request" +version = "0.1.3" +authors = ["Tin Rabzelj "] +description = "Utilities for working with API requests. Part of Bomboni library." +repository = "https://github.com/tinrab/bomboni" +homepage = "https://github.com/tinrab/bomboni" +license-file = "../LICENSE" +readme = "../README.md" +edition = "2021" + +[lib] +name = "bomboni_request" +path = "src/lib.rs" + +[features] +testing = [] + +[dependencies] +bomboni_common = { path = "../bomboni_common", version = "0.1.3" } +bomboni_derive = { path = "../bomboni_derive", version = "0.1.3" } +thiserror = "1.0.50" +itertools = "0.11.0" +chrono = "0.4.31" +pest = "2.7.5" +pest_derive = "2.7.5" diff --git a/bomboni/src/request/filter/error.rs b/bomboni_request/src/filter/error.rs similarity index 96% rename from bomboni/src/request/filter/error.rs rename to bomboni_request/src/filter/error.rs index 8c4af81..3ab0cb6 100644 --- a/bomboni/src/request/filter/error.rs +++ b/bomboni_request/src/filter/error.rs @@ -1,7 +1,7 @@ use pest::error::InputLocation; use thiserror::Error; -use crate::request::schema::ValueType; +use crate::schema::ValueType; use super::parser::Rule; diff --git a/bomboni/src/request/filter/grammar.pest b/bomboni_request/src/filter/grammar.pest similarity index 100% rename from bomboni/src/request/filter/grammar.pest rename to bomboni_request/src/filter/grammar.pest diff --git a/bomboni/src/request/filter/mod.rs b/bomboni_request/src/filter/mod.rs similarity index 99% rename from bomboni/src/request/filter/mod.rs rename to bomboni_request/src/filter/mod.rs index a9e7107..11c5595 100644 --- a/bomboni/src/request/filter/mod.rs +++ b/bomboni_request/src/filter/mod.rs @@ -19,7 +19,7 @@ pub(crate) mod parser { use pest_derive::Parser; #[derive(Parser)] - #[grammar = "./request/filter/grammar.pest"] + #[grammar = "./filter/grammar.pest"] pub(crate) struct FilterParser; } diff --git a/bomboni_request/src/lib.rs b/bomboni_request/src/lib.rs new file mode 100644 index 0000000..f28f713 --- /dev/null +++ b/bomboni_request/src/lib.rs @@ -0,0 +1,10 @@ +pub mod filter; +pub mod ordering; +pub mod query; +pub mod resource; +pub mod schema; +pub mod value; + +#[cfg(feature = "testing")] +#[allow(clippy::all, missing_docs)] +pub mod testing; diff --git a/bomboni/src/request/mod.rs b/bomboni_request/src/mod.rs similarity index 100% rename from bomboni/src/request/mod.rs rename to bomboni_request/src/mod.rs diff --git a/bomboni/src/request/ordering/error.rs b/bomboni_request/src/ordering/error.rs similarity index 100% rename from bomboni/src/request/ordering/error.rs rename to bomboni_request/src/ordering/error.rs diff --git a/bomboni/src/request/ordering/mod.rs b/bomboni_request/src/ordering/mod.rs similarity index 98% rename from bomboni/src/request/ordering/mod.rs rename to bomboni_request/src/ordering/mod.rs index c207aee..69d0e61 100644 --- a/bomboni/src/request/ordering/mod.rs +++ b/bomboni_request/src/ordering/mod.rs @@ -116,7 +116,7 @@ impl Display for OrderingDirection { #[cfg(test)] mod tests { - use crate::request::ordering::OrderingDirection::{Ascending, Descending}; + use crate::ordering::OrderingDirection::{Ascending, Descending}; use crate::testing::schema::UserItem; use super::*; diff --git a/bomboni/src/request/query.rs b/bomboni_request/src/query.rs similarity index 100% rename from bomboni/src/request/query.rs rename to bomboni_request/src/query.rs diff --git a/bomboni/src/request/resource.rs b/bomboni_request/src/resource.rs similarity index 97% rename from bomboni/src/request/resource.rs rename to bomboni_request/src/resource.rs index d5e3d5d..ba85f5b 100644 --- a/bomboni/src/request/resource.rs +++ b/bomboni_request/src/resource.rs @@ -1,6 +1,5 @@ //! # Tools for working with API resources. -#[cfg(feature = "macros")] pub use bomboni_derive::parse_resource_name; #[cfg(test)] diff --git a/bomboni/src/request/schema.rs b/bomboni_request/src/schema.rs similarity index 99% rename from bomboni/src/request/schema.rs rename to bomboni_request/src/schema.rs index 178f7cc..1bd5c89 100644 --- a/bomboni/src/request/schema.rs +++ b/bomboni_request/src/schema.rs @@ -3,7 +3,7 @@ use std::{ fmt::{self, Display, Formatter}, }; -use crate::request::value::Value; +use crate::value::Value; #[derive(Debug, Clone)] pub struct Schema { diff --git a/bomboni/src/testing/mod.rs b/bomboni_request/src/testing/mod.rs similarity index 100% rename from bomboni/src/testing/mod.rs rename to bomboni_request/src/testing/mod.rs diff --git a/bomboni/src/testing/schema.rs b/bomboni_request/src/testing/schema.rs similarity index 97% rename from bomboni/src/testing/schema.rs rename to bomboni_request/src/testing/schema.rs index cae241b..45bb22f 100644 --- a/bomboni/src/testing/schema.rs +++ b/bomboni_request/src/testing/schema.rs @@ -1,9 +1,9 @@ -use crate::btree_map_into; -use crate::request::schema::{ +use crate::schema::{ FieldMemberSchema, FunctionSchema, MemberSchema, ResourceMemberSchema, Schema, SchemaMapped, ValueType, }; -use crate::request::value::Value; +use crate::value::Value; +use bomboni_common::btree_map_into; pub struct RequestItem { pub user: UserItem, diff --git a/bomboni/src/request/value.rs b/bomboni_request/src/value.rs similarity index 98% rename from bomboni/src/request/value.rs rename to bomboni_request/src/value.rs index ded17da..625cb4c 100644 --- a/bomboni/src/request/value.rs +++ b/bomboni_request/src/value.rs @@ -7,11 +7,10 @@ use chrono::NaiveDateTime; use itertools::Itertools; use pest::iterators::Pair; +use crate::filter::parser::Rule; + use super::{ - filter::{ - error::{FilterError, FilterResult}, - parser::Rule, - }, + filter::error::{FilterError, FilterResult}, schema::ValueType, }; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..596c295 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,22 @@ +pub mod common { + pub use bomboni_common::*; +} + +pub mod derive { + pub use bomboni_derive::*; +} + +#[cfg(feature = "prost")] +pub mod prost { + pub use bomboni_prost::*; +} + +#[cfg(feature = "proto")] +pub mod proto { + pub use bomboni_proto::*; +} + +#[cfg(feature = "request")] +pub mod request { + pub use bomboni_request::*; +}