diff --git a/tonic-types/src/lib.rs b/tonic-types/src/lib.rs index 20e42e36e..7c9cd7dc8 100644 --- a/tonic-types/src/lib.rs +++ b/tonic-types/src/lib.rs @@ -180,7 +180,7 @@ mod richer_error; pub use richer_error::{ BadRequest, DebugInfo, ErrorDetail, ErrorDetails, ErrorInfo, FieldViolation, Help, HelpLink, LocalizedMessage, PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation, - RequestInfo, ResourceInfo, RetryInfo, StatusExt, + RequestInfo, ResourceInfo, RetryInfo, RpcStatusExt, StatusExt, }; mod sealed { diff --git a/tonic-types/src/richer_error/mod.rs b/tonic-types/src/richer_error/mod.rs index 50fa03e46..411887ce5 100644 --- a/tonic-types/src/richer_error/mod.rs +++ b/tonic-types/src/richer_error/mod.rs @@ -27,6 +27,12 @@ trait FromAny { Self: Sized; } +trait FromAnyRef { + fn from_any_ref(any: &Any) -> Result + where + Self: Sized; +} + fn gen_details_bytes(code: Code, message: &str, details: Vec) -> Bytes { let status = pb::Status { code: code as i32, @@ -599,39 +605,191 @@ impl StatusExt for tonic::Status { fn check_error_details(&self) -> Result { let status = pb::Status::decode(self.details())?; + status.check_error_details() + } + + fn get_error_details(&self) -> ErrorDetails { + self.check_error_details().unwrap_or_default() + } + + fn check_error_details_vec(&self) -> Result, DecodeError> { + let status = pb::Status::decode(self.details())?; + + status.check_error_details_vec() + } + + fn get_error_details_vec(&self) -> Vec { + self.check_error_details_vec().unwrap_or_default() + } + + fn get_details_retry_info(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_retry_info() + } + + fn get_details_debug_info(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_debug_info() + } + + fn get_details_quota_failure(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_quota_failure() + } + + fn get_details_error_info(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_error_info() + } + + fn get_details_precondition_failure(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_precondition_failure() + } + + fn get_details_bad_request(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_bad_request() + } + + fn get_details_request_info(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_request_info() + } + + fn get_details_resource_info(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_resource_info() + } + + fn get_details_help(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_help() + } + + fn get_details_localized_message(&self) -> Option { + let status = pb::Status::decode(self.details()).ok()?; + + status.get_details_localized_message() + } +} + +impl crate::sealed::Sealed for pb::Status {} + +/// Used to implement associated functions and methods on `pb::Status`, that +/// allow the extraction of standard error details. This trait is +/// sealed and not meant to be implemented outside of `tonic-types`. +pub trait RpcStatusExt: crate::sealed::Sealed { + /// Can be used to check if the error details contained in `pb::Status` + /// are malformed or not. Tries to get an [`ErrorDetails`] struct from a + /// `pb::Status`. If some `prost::DecodeError` occurs, it will be + /// returned. If not debugging, consider using + /// [`RpcStatusExt::get_error_details`] or + /// [`RpcStatusExt::get_error_details_vec`]. + fn check_error_details(&self) -> Result; + + /// Get an [`ErrorDetails`] struct from `pb::Status`. If some + /// `prost::DecodeError` occurs, an empty [`ErrorDetails`] struct will be + /// returned. + fn get_error_details(&self) -> ErrorDetails; + + /// Can be used to check if the error details contained in `pb::Status` + /// are malformed or not. Tries to get a vector of [`ErrorDetail`] enums + /// from a `pb::Status`. If some `prost::DecodeError` occurs, it will be + /// returned. If not debugging, consider using + /// [`StatusExt::get_error_details_vec`] or + /// [`StatusExt::get_error_details`]. + fn check_error_details_vec(&self) -> Result, DecodeError>; + + /// Get a vector of [`ErrorDetail`] enums from `pb::Status`. If some + /// `prost::DecodeError` occurs, an empty vector will be returned. + fn get_error_details_vec(&self) -> Vec; + + /// Get first [`RetryInfo`] details found on `pb::Status`, if any. If + /// some `prost::DecodeError` occurs, returns `None`. + fn get_details_retry_info(&self) -> Option; + + /// Get first [`DebugInfo`] details found on `pb::Status`, if any. If + /// some `prost::DecodeError` occurs, returns `None`. + fn get_details_debug_info(&self) -> Option; + + /// Get first [`QuotaFailure`] details found on `pb::Status`, if any. + /// If some `prost::DecodeError` occurs, returns `None`. + fn get_details_quota_failure(&self) -> Option; + + /// Get first [`ErrorInfo`] details found on `pb::Status`, if any. If + /// some `prost::DecodeError` occurs, returns `None`. + fn get_details_error_info(&self) -> Option; + + /// Get first [`PreconditionFailure`] details found on `pb::Status`, + /// if any. If some `prost::DecodeError` occurs, returns `None`. + fn get_details_precondition_failure(&self) -> Option; + + /// Get first [`BadRequest`] details found on `pb::Status`, if any. If + /// some `prost::DecodeError` occurs, returns `None`. + fn get_details_bad_request(&self) -> Option; + + /// Get first [`RequestInfo`] details found on `pb::Status`, if any. + /// If some `prost::DecodeError` occurs, returns `None`. + fn get_details_request_info(&self) -> Option; + + /// Get first [`ResourceInfo`] details found on `pb::Status`, if any. + /// If some `prost::DecodeError` occurs, returns `None`. + fn get_details_resource_info(&self) -> Option; + + /// Get first [`Help`] details found on `pb::Status`, if any. If some + /// `prost::DecodeError` occurs, returns `None`. + fn get_details_help(&self) -> Option; + + /// Get first [`LocalizedMessage`] details found on `pb::Status`, if + /// any. If some `prost::DecodeError` occurs, returns `None`. + fn get_details_localized_message(&self) -> Option; +} + +impl RpcStatusExt for pb::Status { + fn check_error_details(&self) -> Result { let mut details = ErrorDetails::new(); - for any in status.details.into_iter() { + for any in self.details.iter() { match any.type_url.as_str() { RetryInfo::TYPE_URL => { - details.retry_info = Some(RetryInfo::from_any(any)?); + details.retry_info = Some(RetryInfo::from_any_ref(any)?); } DebugInfo::TYPE_URL => { - details.debug_info = Some(DebugInfo::from_any(any)?); + details.debug_info = Some(DebugInfo::from_any_ref(any)?); } QuotaFailure::TYPE_URL => { - details.quota_failure = Some(QuotaFailure::from_any(any)?); + details.quota_failure = Some(QuotaFailure::from_any_ref(any)?); } ErrorInfo::TYPE_URL => { - details.error_info = Some(ErrorInfo::from_any(any)?); + details.error_info = Some(ErrorInfo::from_any_ref(any)?); } PreconditionFailure::TYPE_URL => { - details.precondition_failure = Some(PreconditionFailure::from_any(any)?); + details.precondition_failure = Some(PreconditionFailure::from_any_ref(any)?); } BadRequest::TYPE_URL => { - details.bad_request = Some(BadRequest::from_any(any)?); + details.bad_request = Some(BadRequest::from_any_ref(any)?); } RequestInfo::TYPE_URL => { - details.request_info = Some(RequestInfo::from_any(any)?); + details.request_info = Some(RequestInfo::from_any_ref(any)?); } ResourceInfo::TYPE_URL => { - details.resource_info = Some(ResourceInfo::from_any(any)?); + details.resource_info = Some(ResourceInfo::from_any_ref(any)?); } Help::TYPE_URL => { - details.help = Some(Help::from_any(any)?); + details.help = Some(Help::from_any_ref(any)?); } LocalizedMessage::TYPE_URL => { - details.localized_message = Some(LocalizedMessage::from_any(any)?); + details.localized_message = Some(LocalizedMessage::from_any_ref(any)?); } _ => {} } @@ -645,41 +803,39 @@ impl StatusExt for tonic::Status { } fn check_error_details_vec(&self) -> Result, DecodeError> { - let status = pb::Status::decode(self.details())?; + let mut details: Vec = Vec::with_capacity(self.details.len()); - let mut details: Vec = Vec::with_capacity(status.details.len()); - - for any in status.details.into_iter() { + for any in self.details.iter() { match any.type_url.as_str() { RetryInfo::TYPE_URL => { - details.push(RetryInfo::from_any(any)?.into()); + details.push(RetryInfo::from_any_ref(any)?.into()); } DebugInfo::TYPE_URL => { - details.push(DebugInfo::from_any(any)?.into()); + details.push(DebugInfo::from_any_ref(any)?.into()); } QuotaFailure::TYPE_URL => { - details.push(QuotaFailure::from_any(any)?.into()); + details.push(QuotaFailure::from_any_ref(any)?.into()); } ErrorInfo::TYPE_URL => { - details.push(ErrorInfo::from_any(any)?.into()); + details.push(ErrorInfo::from_any_ref(any)?.into()); } PreconditionFailure::TYPE_URL => { - details.push(PreconditionFailure::from_any(any)?.into()); + details.push(PreconditionFailure::from_any_ref(any)?.into()); } BadRequest::TYPE_URL => { - details.push(BadRequest::from_any(any)?.into()); + details.push(BadRequest::from_any_ref(any)?.into()); } RequestInfo::TYPE_URL => { - details.push(RequestInfo::from_any(any)?.into()); + details.push(RequestInfo::from_any_ref(any)?.into()); } ResourceInfo::TYPE_URL => { - details.push(ResourceInfo::from_any(any)?.into()); + details.push(ResourceInfo::from_any_ref(any)?.into()); } Help::TYPE_URL => { - details.push(Help::from_any(any)?.into()); + details.push(Help::from_any_ref(any)?.into()); } LocalizedMessage::TYPE_URL => { - details.push(LocalizedMessage::from_any(any)?.into()); + details.push(LocalizedMessage::from_any_ref(any)?.into()); } _ => {} } @@ -693,11 +849,9 @@ impl StatusExt for tonic::Status { } fn get_details_retry_info(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == RetryInfo::TYPE_URL { - if let Ok(detail) = RetryInfo::from_any(any) { + if let Ok(detail) = RetryInfo::from_any_ref(any) { return Some(detail); } } @@ -707,11 +861,9 @@ impl StatusExt for tonic::Status { } fn get_details_debug_info(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == DebugInfo::TYPE_URL { - if let Ok(detail) = DebugInfo::from_any(any) { + if let Ok(detail) = DebugInfo::from_any_ref(any) { return Some(detail); } } @@ -721,11 +873,9 @@ impl StatusExt for tonic::Status { } fn get_details_quota_failure(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == QuotaFailure::TYPE_URL { - if let Ok(detail) = QuotaFailure::from_any(any) { + if let Ok(detail) = QuotaFailure::from_any_ref(any) { return Some(detail); } } @@ -735,11 +885,9 @@ impl StatusExt for tonic::Status { } fn get_details_error_info(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == ErrorInfo::TYPE_URL { - if let Ok(detail) = ErrorInfo::from_any(any) { + if let Ok(detail) = ErrorInfo::from_any_ref(any) { return Some(detail); } } @@ -749,11 +897,9 @@ impl StatusExt for tonic::Status { } fn get_details_precondition_failure(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == PreconditionFailure::TYPE_URL { - if let Ok(detail) = PreconditionFailure::from_any(any) { + if let Ok(detail) = PreconditionFailure::from_any_ref(any) { return Some(detail); } } @@ -763,11 +909,9 @@ impl StatusExt for tonic::Status { } fn get_details_bad_request(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == BadRequest::TYPE_URL { - if let Ok(detail) = BadRequest::from_any(any) { + if let Ok(detail) = BadRequest::from_any_ref(any) { return Some(detail); } } @@ -777,11 +921,9 @@ impl StatusExt for tonic::Status { } fn get_details_request_info(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == RequestInfo::TYPE_URL { - if let Ok(detail) = RequestInfo::from_any(any) { + if let Ok(detail) = RequestInfo::from_any_ref(any) { return Some(detail); } } @@ -791,11 +933,9 @@ impl StatusExt for tonic::Status { } fn get_details_resource_info(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == ResourceInfo::TYPE_URL { - if let Ok(detail) = ResourceInfo::from_any(any) { + if let Ok(detail) = ResourceInfo::from_any_ref(any) { return Some(detail); } } @@ -805,11 +945,9 @@ impl StatusExt for tonic::Status { } fn get_details_help(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == Help::TYPE_URL { - if let Ok(detail) = Help::from_any(any) { + if let Ok(detail) = Help::from_any_ref(any) { return Some(detail); } } @@ -819,11 +957,9 @@ impl StatusExt for tonic::Status { } fn get_details_localized_message(&self) -> Option { - let status = pb::Status::decode(self.details()).ok()?; - - for any in status.details.into_iter() { + for any in self.details.iter() { if any.type_url.as_str() == LocalizedMessage::TYPE_URL { - if let Ok(detail) = LocalizedMessage::from_any(any) { + if let Ok(detail) = LocalizedMessage::from_any_ref(any) { return Some(detail); } } diff --git a/tonic-types/src/richer_error/std_messages/bad_request.rs b/tonic-types/src/richer_error/std_messages/bad_request.rs index bda03ba79..c9fcb984a 100644 --- a/tonic-types/src/richer_error/std_messages/bad_request.rs +++ b/tonic-types/src/richer_error/std_messages/bad_request.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used at the `field_violations` field of the [`BadRequest`] struct. @@ -26,6 +28,24 @@ impl FieldViolation { } } +impl From for FieldViolation { + fn from(value: pb::bad_request::FieldViolation) -> Self { + FieldViolation { + field: value.field, + description: value.description, + } + } +} + +impl From for pb::bad_request::FieldViolation { + fn from(value: FieldViolation) -> Self { + pb::bad_request::FieldViolation { + field: value.field, + description: value.description, + } + } +} + /// Used to encode/decode the `BadRequest` standard error message described in /// [error_details.proto]. Describes violations in a client request. Focuses /// on the syntactic aspects of the request. @@ -81,16 +101,7 @@ impl BadRequest { impl IntoAny for BadRequest { fn into_any(self) -> Any { - let detail_data = pb::BadRequest { - field_violations: self - .field_violations - .into_iter() - .map(|v| pb::bad_request::FieldViolation { - field: v.field, - description: v.description, - }) - .collect(), - }; + let detail_data: pb::BadRequest = self.into(); Any { type_url: BadRequest::TYPE_URL.to_string(), @@ -100,22 +111,34 @@ impl IntoAny for BadRequest { } impl FromAny for BadRequest { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for BadRequest { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let bad_req = pb::BadRequest::decode(buf)?; - let bad_req = BadRequest { - field_violations: bad_req - .field_violations - .into_iter() - .map(|v| FieldViolation { - field: v.field, - description: v.description, - }) - .collect(), - }; + Ok(bad_req.into()) + } +} - Ok(bad_req) +impl From for BadRequest { + fn from(value: pb::BadRequest) -> Self { + BadRequest { + field_violations: value.field_violations.into_iter().map(Into::into).collect(), + } + } +} + +impl From for pb::BadRequest { + fn from(value: BadRequest) -> Self { + pb::BadRequest { + field_violations: value.field_violations.into_iter().map(Into::into).collect(), + } } } diff --git a/tonic-types/src/richer_error/std_messages/debug_info.rs b/tonic-types/src/richer_error/std_messages/debug_info.rs index a27d2ef23..9c450c774 100644 --- a/tonic-types/src/richer_error/std_messages/debug_info.rs +++ b/tonic-types/src/richer_error/std_messages/debug_info.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used to encode/decode the `DebugInfo` standard error message described in @@ -37,10 +39,7 @@ impl DebugInfo { impl IntoAny for DebugInfo { fn into_any(self) -> Any { - let detail_data = pb::DebugInfo { - stack_entries: self.stack_entries, - detail: self.detail, - }; + let detail_data: pb::DebugInfo = self.into(); Any { type_url: DebugInfo::TYPE_URL.to_string(), @@ -50,16 +49,36 @@ impl IntoAny for DebugInfo { } impl FromAny for DebugInfo { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for DebugInfo { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let debug_info = pb::DebugInfo::decode(buf)?; - let debug_info = DebugInfo { + Ok(debug_info.into()) + } +} + +impl From for DebugInfo { + fn from(debug_info: pb::DebugInfo) -> Self { + DebugInfo { stack_entries: debug_info.stack_entries, detail: debug_info.detail, - }; + } + } +} - Ok(debug_info) +impl From for pb::DebugInfo { + fn from(debug_info: DebugInfo) -> Self { + pb::DebugInfo { + stack_entries: debug_info.stack_entries, + detail: debug_info.detail, + } } } diff --git a/tonic-types/src/richer_error/std_messages/error_info.rs b/tonic-types/src/richer_error/std_messages/error_info.rs index b1ba7967c..8d535a157 100644 --- a/tonic-types/src/richer_error/std_messages/error_info.rs +++ b/tonic-types/src/richer_error/std_messages/error_info.rs @@ -3,6 +3,8 @@ use std::collections::HashMap; use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used to encode/decode the `ErrorInfo` standard error message described in @@ -53,11 +55,7 @@ impl ErrorInfo { impl IntoAny for ErrorInfo { fn into_any(self) -> Any { - let detail_data = pb::ErrorInfo { - reason: self.reason, - domain: self.domain, - metadata: self.metadata, - }; + let detail_data: pb::ErrorInfo = self.into(); Any { type_url: ErrorInfo::TYPE_URL.to_string(), @@ -67,17 +65,38 @@ impl IntoAny for ErrorInfo { } impl FromAny for ErrorInfo { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for ErrorInfo { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let error_info = pb::ErrorInfo::decode(buf)?; - let error_info = ErrorInfo { + Ok(error_info.into()) + } +} + +impl From for ErrorInfo { + fn from(error_info: pb::ErrorInfo) -> Self { + ErrorInfo { reason: error_info.reason, domain: error_info.domain, metadata: error_info.metadata, - }; + } + } +} - Ok(error_info) +impl From for pb::ErrorInfo { + fn from(error_info: ErrorInfo) -> Self { + pb::ErrorInfo { + reason: error_info.reason, + domain: error_info.domain, + metadata: error_info.metadata, + } } } diff --git a/tonic-types/src/richer_error/std_messages/help.rs b/tonic-types/src/richer_error/std_messages/help.rs index 1febf841a..08549b2e9 100644 --- a/tonic-types/src/richer_error/std_messages/help.rs +++ b/tonic-types/src/richer_error/std_messages/help.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used at the `links` field of the [`Help`] struct. Describes a URL link. @@ -23,6 +25,24 @@ impl HelpLink { } } +impl From for HelpLink { + fn from(value: pb::help::Link) -> Self { + HelpLink { + description: value.description, + url: value.url, + } + } +} + +impl From for pb::help::Link { + fn from(value: HelpLink) -> Self { + pb::help::Link { + description: value.description, + url: value.url, + } + } +} + /// Used to encode/decode the `Help` standard error message described in /// [error_details.proto]. Provides links to documentation or for performing /// an out-of-band action. @@ -77,16 +97,7 @@ impl Help { impl IntoAny for Help { fn into_any(self) -> Any { - let detail_data = pb::Help { - links: self - .links - .into_iter() - .map(|v| pb::help::Link { - description: v.description, - url: v.url, - }) - .collect(), - }; + let detail_data: pb::Help = self.into(); Any { type_url: Help::TYPE_URL.to_string(), @@ -96,22 +107,34 @@ impl IntoAny for Help { } impl FromAny for Help { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for Help { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let help = pb::Help::decode(buf)?; - let help = Help { - links: help - .links - .into_iter() - .map(|v| HelpLink { - description: v.description, - url: v.url, - }) - .collect(), - }; + Ok(help.into()) + } +} - Ok(help) +impl From for Help { + fn from(value: pb::Help) -> Self { + Help { + links: value.links.into_iter().map(Into::into).collect(), + } + } +} + +impl From for pb::Help { + fn from(value: Help) -> Self { + pb::Help { + links: value.links.into_iter().map(Into::into).collect(), + } } } diff --git a/tonic-types/src/richer_error/std_messages/loc_message.rs b/tonic-types/src/richer_error/std_messages/loc_message.rs index 75469ff96..98ab72bce 100644 --- a/tonic-types/src/richer_error/std_messages/loc_message.rs +++ b/tonic-types/src/richer_error/std_messages/loc_message.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used to encode/decode the `LocalizedMessage` standard error message @@ -41,10 +43,7 @@ impl LocalizedMessage { impl IntoAny for LocalizedMessage { fn into_any(self) -> Any { - let detail_data = pb::LocalizedMessage { - locale: self.locale, - message: self.message, - }; + let detail_data: pb::LocalizedMessage = self.into(); Any { type_url: LocalizedMessage::TYPE_URL.to_string(), @@ -54,16 +53,36 @@ impl IntoAny for LocalizedMessage { } impl FromAny for LocalizedMessage { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for LocalizedMessage { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let loc_message = pb::LocalizedMessage::decode(buf)?; - let loc_message = LocalizedMessage { + Ok(loc_message.into()) + } +} + +impl From for LocalizedMessage { + fn from(loc_message: pb::LocalizedMessage) -> Self { + LocalizedMessage { locale: loc_message.locale, message: loc_message.message, - }; + } + } +} - Ok(loc_message) +impl From for pb::LocalizedMessage { + fn from(loc_message: LocalizedMessage) -> Self { + pb::LocalizedMessage { + locale: loc_message.locale, + message: loc_message.message, + } } } diff --git a/tonic-types/src/richer_error/std_messages/prec_failure.rs b/tonic-types/src/richer_error/std_messages/prec_failure.rs index 95b05815e..a8a5c50f1 100644 --- a/tonic-types/src/richer_error/std_messages/prec_failure.rs +++ b/tonic-types/src/richer_error/std_messages/prec_failure.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used at the `violations` field of the [`PreconditionFailure`] struct. @@ -36,6 +38,26 @@ impl PreconditionViolation { } } +impl From for PreconditionViolation { + fn from(value: pb::precondition_failure::Violation) -> Self { + PreconditionViolation { + r#type: value.r#type, + subject: value.subject, + description: value.description, + } + } +} + +impl From for pb::precondition_failure::Violation { + fn from(value: PreconditionViolation) -> Self { + pb::precondition_failure::Violation { + r#type: value.r#type, + subject: value.subject, + description: value.description, + } + } +} + /// Used to encode/decode the `PreconditionFailure` standard error message /// described in [error_details.proto]. Describes what preconditions have /// failed. @@ -99,17 +121,7 @@ impl PreconditionFailure { impl IntoAny for PreconditionFailure { fn into_any(self) -> Any { - let detail_data = pb::PreconditionFailure { - violations: self - .violations - .into_iter() - .map(|v| pb::precondition_failure::Violation { - r#type: v.r#type, - subject: v.subject, - description: v.description, - }) - .collect(), - }; + let detail_data: pb::PreconditionFailure = self.into(); Any { type_url: PreconditionFailure::TYPE_URL.to_string(), @@ -119,23 +131,34 @@ impl IntoAny for PreconditionFailure { } impl FromAny for PreconditionFailure { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for PreconditionFailure { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let precondition_failure = pb::PreconditionFailure::decode(buf)?; - let precondition_failure = PreconditionFailure { - violations: precondition_failure - .violations - .into_iter() - .map(|v| PreconditionViolation { - r#type: v.r#type, - subject: v.subject, - description: v.description, - }) - .collect(), - }; + Ok(precondition_failure.into()) + } +} - Ok(precondition_failure) +impl From for PreconditionFailure { + fn from(value: pb::PreconditionFailure) -> Self { + PreconditionFailure { + violations: value.violations.into_iter().map(Into::into).collect(), + } + } +} + +impl From for pb::PreconditionFailure { + fn from(value: PreconditionFailure) -> Self { + pb::PreconditionFailure { + violations: value.violations.into_iter().map(Into::into).collect(), + } } } diff --git a/tonic-types/src/richer_error/std_messages/quota_failure.rs b/tonic-types/src/richer_error/std_messages/quota_failure.rs index 261980ae8..23d160521 100644 --- a/tonic-types/src/richer_error/std_messages/quota_failure.rs +++ b/tonic-types/src/richer_error/std_messages/quota_failure.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used at the `violations` field of the [`QuotaFailure`] struct. Describes a @@ -24,6 +26,24 @@ impl QuotaViolation { } } +impl From for QuotaViolation { + fn from(value: pb::quota_failure::Violation) -> Self { + QuotaViolation { + subject: value.subject, + description: value.description, + } + } +} + +impl From for pb::quota_failure::Violation { + fn from(value: QuotaViolation) -> Self { + pb::quota_failure::Violation { + subject: value.subject, + description: value.description, + } + } +} + /// Used to encode/decode the `QuotaFailure` standard error message described /// in [error_details.proto]. Describes how a quota check failed. /// @@ -78,16 +98,7 @@ impl QuotaFailure { impl IntoAny for QuotaFailure { fn into_any(self) -> Any { - let detail_data = pb::QuotaFailure { - violations: self - .violations - .into_iter() - .map(|v| pb::quota_failure::Violation { - subject: v.subject, - description: v.description, - }) - .collect(), - }; + let detail_data: pb::QuotaFailure = self.into(); Any { type_url: QuotaFailure::TYPE_URL.to_string(), @@ -97,22 +108,34 @@ impl IntoAny for QuotaFailure { } impl FromAny for QuotaFailure { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for QuotaFailure { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let quota_failure = pb::QuotaFailure::decode(buf)?; - let quota_failure = QuotaFailure { - violations: quota_failure - .violations - .into_iter() - .map(|v| QuotaViolation { - subject: v.subject, - description: v.description, - }) - .collect(), - }; + Ok(quota_failure.into()) + } +} - Ok(quota_failure) +impl From for QuotaFailure { + fn from(value: pb::QuotaFailure) -> Self { + QuotaFailure { + violations: value.violations.into_iter().map(Into::into).collect(), + } + } +} + +impl From for pb::QuotaFailure { + fn from(value: QuotaFailure) -> Self { + pb::QuotaFailure { + violations: value.violations.into_iter().map(Into::into).collect(), + } } } diff --git a/tonic-types/src/richer_error/std_messages/request_info.rs b/tonic-types/src/richer_error/std_messages/request_info.rs index e28468c89..bb09f0c5b 100644 --- a/tonic-types/src/richer_error/std_messages/request_info.rs +++ b/tonic-types/src/richer_error/std_messages/request_info.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used to encode/decode the `RequestInfo` standard error message described @@ -40,10 +42,7 @@ impl RequestInfo { impl IntoAny for RequestInfo { fn into_any(self) -> Any { - let detail_data = pb::RequestInfo { - request_id: self.request_id, - serving_data: self.serving_data, - }; + let detail_data: pb::RequestInfo = self.into(); Any { type_url: RequestInfo::TYPE_URL.to_string(), @@ -53,16 +52,36 @@ impl IntoAny for RequestInfo { } impl FromAny for RequestInfo { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for RequestInfo { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let req_info = pb::RequestInfo::decode(buf)?; - let req_info = RequestInfo { + Ok(req_info.into()) + } +} + +impl From for RequestInfo { + fn from(req_info: pb::RequestInfo) -> Self { + RequestInfo { request_id: req_info.request_id, serving_data: req_info.serving_data, - }; + } + } +} - Ok(req_info) +impl From for pb::RequestInfo { + fn from(req_info: RequestInfo) -> Self { + pb::RequestInfo { + request_id: req_info.request_id, + serving_data: req_info.serving_data, + } } } diff --git a/tonic-types/src/richer_error/std_messages/resource_info.rs b/tonic-types/src/richer_error/std_messages/resource_info.rs index 7e9090a58..ccb23e1a7 100644 --- a/tonic-types/src/richer_error/std_messages/resource_info.rs +++ b/tonic-types/src/richer_error/std_messages/resource_info.rs @@ -1,6 +1,8 @@ use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used to encode/decode the `ResourceInfo` standard error message described @@ -53,12 +55,7 @@ impl ResourceInfo { impl IntoAny for ResourceInfo { fn into_any(self) -> Any { - let detail_data = pb::ResourceInfo { - resource_type: self.resource_type, - resource_name: self.resource_name, - owner: self.owner, - description: self.description, - }; + let detail_data: pb::ResourceInfo = self.into(); Any { type_url: ResourceInfo::TYPE_URL.to_string(), @@ -68,18 +65,40 @@ impl IntoAny for ResourceInfo { } impl FromAny for ResourceInfo { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for ResourceInfo { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let res_info = pb::ResourceInfo::decode(buf)?; - let res_info = ResourceInfo { + Ok(res_info.into()) + } +} + +impl From for ResourceInfo { + fn from(res_info: pb::ResourceInfo) -> Self { + ResourceInfo { resource_type: res_info.resource_type, resource_name: res_info.resource_name, owner: res_info.owner, description: res_info.description, - }; + } + } +} - Ok(res_info) +impl From for pb::ResourceInfo { + fn from(res_info: ResourceInfo) -> Self { + pb::ResourceInfo { + resource_type: res_info.resource_type, + resource_name: res_info.resource_name, + owner: res_info.owner, + description: res_info.description, + } } } diff --git a/tonic-types/src/richer_error/std_messages/retry_info.rs b/tonic-types/src/richer_error/std_messages/retry_info.rs index 5c35b2417..a26e62076 100644 --- a/tonic-types/src/richer_error/std_messages/retry_info.rs +++ b/tonic-types/src/richer_error/std_messages/retry_info.rs @@ -3,6 +3,8 @@ use std::time; use prost::{DecodeError, Message}; use prost_types::Any; +use crate::richer_error::FromAnyRef; + use super::super::{pb, FromAny, IntoAny}; /// Used to encode/decode the `RetryInfo` standard error message described in @@ -52,22 +54,7 @@ impl RetryInfo { impl IntoAny for RetryInfo { fn into_any(self) -> Any { - let retry_delay = match self.retry_delay { - Some(duration) => { - // If duration is too large, uses max `prost_types::Duration` - let duration = match prost_types::Duration::try_from(duration) { - Ok(duration) => duration, - Err(_) => prost_types::Duration { - seconds: 315_576_000_000, - nanos: 999_999_999, - }, - }; - Some(duration) - } - None => None, - }; - - let detail_data = pb::RetryInfo { retry_delay }; + let detail_data: pb::RetryInfo = self.into(); Any { type_url: RetryInfo::TYPE_URL.to_string(), @@ -77,10 +64,23 @@ impl IntoAny for RetryInfo { } impl FromAny for RetryInfo { + #[inline] fn from_any(any: Any) -> Result { + FromAnyRef::from_any_ref(&any) + } +} + +impl FromAnyRef for RetryInfo { + fn from_any_ref(any: &Any) -> Result { let buf: &[u8] = &any.value; let retry_info = pb::RetryInfo::decode(buf)?; + Ok(retry_info.into()) + } +} + +impl From for RetryInfo { + fn from(retry_info: pb::RetryInfo) -> Self { let retry_delay = match retry_info.retry_delay { Some(duration) => { // Negative retry_delays become 0 @@ -90,9 +90,28 @@ impl FromAny for RetryInfo { None => None, }; - let retry_info = RetryInfo { retry_delay }; + RetryInfo { retry_delay } + } +} + +impl From for pb::RetryInfo { + fn from(value: RetryInfo) -> Self { + let retry_delay = match value.retry_delay { + Some(duration) => { + // If duration is too large, uses max `prost_types::Duration` + let duration = match prost_types::Duration::try_from(duration) { + Ok(duration) => duration, + Err(_) => prost_types::Duration { + seconds: 315_576_000_000, + nanos: 999_999_999, + }, + }; + Some(duration) + } + None => None, + }; - Ok(retry_info) + pb::RetryInfo { retry_delay } } }