use prost::{DecodeError, Message};
use prost_types::Any;
use crate::richer_error::FromAnyRef;
use super::super::{pb, FromAny, IntoAny};
#[derive(Clone, Debug)]
pub struct FieldViolation {
pub field: String,
pub description: String,
}
impl FieldViolation {
pub fn new(field: impl Into<String>, description: impl Into<String>) -> Self {
FieldViolation {
field: field.into(),
description: description.into(),
}
}
}
impl From<pb::bad_request::FieldViolation> for FieldViolation {
fn from(value: pb::bad_request::FieldViolation) -> Self {
FieldViolation {
field: value.field,
description: value.description,
}
}
}
impl From<FieldViolation> for pb::bad_request::FieldViolation {
fn from(value: FieldViolation) -> Self {
pb::bad_request::FieldViolation {
field: value.field,
description: value.description,
}
}
}
#[derive(Clone, Debug)]
pub struct BadRequest {
pub field_violations: Vec<FieldViolation>,
}
impl BadRequest {
pub const TYPE_URL: &'static str = "type.googleapis.com/google.rpc.BadRequest";
pub fn new(field_violations: impl Into<Vec<FieldViolation>>) -> Self {
BadRequest {
field_violations: field_violations.into(),
}
}
pub fn with_violation(field: impl Into<String>, description: impl Into<String>) -> Self {
BadRequest {
field_violations: vec![FieldViolation {
field: field.into(),
description: description.into(),
}],
}
}
pub fn add_violation(
&mut self,
field: impl Into<String>,
description: impl Into<String>,
) -> &mut Self {
self.field_violations.append(&mut vec![FieldViolation {
field: field.into(),
description: description.into(),
}]);
self
}
pub fn is_empty(&self) -> bool {
self.field_violations.is_empty()
}
}
impl IntoAny for BadRequest {
fn into_any(self) -> Any {
let detail_data: pb::BadRequest = self.into();
Any {
type_url: BadRequest::TYPE_URL.to_string(),
value: detail_data.encode_to_vec(),
}
}
}
impl FromAny for BadRequest {
#[inline]
fn from_any(any: Any) -> Result<Self, DecodeError> {
FromAnyRef::from_any_ref(&any)
}
}
impl FromAnyRef for BadRequest {
fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
let buf: &[u8] = &any.value;
let bad_req = pb::BadRequest::decode(buf)?;
Ok(bad_req.into())
}
}
impl From<pb::BadRequest> for BadRequest {
fn from(value: pb::BadRequest) -> Self {
BadRequest {
field_violations: value.field_violations.into_iter().map(Into::into).collect(),
}
}
}
impl From<BadRequest> for pb::BadRequest {
fn from(value: BadRequest) -> Self {
pb::BadRequest {
field_violations: value.field_violations.into_iter().map(Into::into).collect(),
}
}
}
#[cfg(test)]
mod tests {
use super::super::super::{FromAny, IntoAny};
use super::BadRequest;
#[test]
fn gen_bad_request() {
let mut br_details = BadRequest::new(Vec::new());
let formatted = format!("{:?}", br_details);
let expected = "BadRequest { field_violations: [] }";
assert!(
formatted.eq(expected),
"empty BadRequest differs from expected result"
);
assert!(
br_details.is_empty(),
"empty BadRequest returns 'false' from .is_empty()"
);
br_details
.add_violation("field_a", "description_a")
.add_violation("field_b", "description_b");
let formatted = format!("{:?}", br_details);
let expected_filled = "BadRequest { field_violations: [FieldViolation { field: \"field_a\", description: \"description_a\" }, FieldViolation { field: \"field_b\", description: \"description_b\" }] }";
assert!(
formatted.eq(expected_filled),
"filled BadRequest differs from expected result"
);
assert!(
!br_details.is_empty(),
"filled BadRequest returns 'true' from .is_empty()"
);
let gen_any = br_details.into_any();
let formatted = format!("{:?}", gen_any);
let expected = "Any { type_url: \"type.googleapis.com/google.rpc.BadRequest\", value: [10, 24, 10, 7, 102, 105, 101, 108, 100, 95, 97, 18, 13, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 95, 97, 10, 24, 10, 7, 102, 105, 101, 108, 100, 95, 98, 18, 13, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 95, 98] }";
assert!(
formatted.eq(expected),
"Any from filled BadRequest differs from expected result"
);
let br_details = match BadRequest::from_any(gen_any) {
Err(error) => panic!("Error generating BadRequest from Any: {:?}", error),
Ok(from_any) => from_any,
};
let formatted = format!("{:?}", br_details);
assert!(
formatted.eq(expected_filled),
"BadRequest from Any differs from expected result"
);
}
}