Skip to main content

tonic_types/richer_error/std_messages/
loc_message.rs

1use prost::{DecodeError, Message};
2use prost_types::Any;
3
4use crate::richer_error::FromAnyRef;
5
6use super::super::{pb, FromAny, IntoAny};
7
8/// Used to encode/decode the `LocalizedMessage` standard error message
9/// described in [error_details.proto]. Provides a localized error message
10/// that is safe to return to the user.
11///
12/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto
13#[derive(Clone, Debug, Default)]
14pub struct LocalizedMessage {
15    /// Locale used, following the specification defined in [BCP 47]. For
16    /// example: "en-US", "fr-CH" or "es-MX".
17    ///
18    /// [BCP 47]: http://www.rfc-editor.org/rfc/bcp/bcp47.txt
19    pub locale: String,
20
21    /// Message corresponding to the locale.
22    pub message: String,
23}
24
25impl LocalizedMessage {
26    /// Type URL of the `LocalizedMessage` standard error message type.
27    pub const TYPE_URL: &'static str = "type.googleapis.com/google.rpc.LocalizedMessage";
28
29    /// Creates a new [`LocalizedMessage`] struct.
30    pub fn new(locale: impl Into<String>, message: impl Into<String>) -> Self {
31        LocalizedMessage {
32            locale: locale.into(),
33            message: message.into(),
34        }
35    }
36
37    /// Returns `true` if [`LocalizedMessage`] fields are empty, and `false` if
38    /// they are not.
39    pub fn is_empty(&self) -> bool {
40        self.locale.is_empty() && self.message.is_empty()
41    }
42}
43
44impl IntoAny for LocalizedMessage {
45    fn into_any(self) -> Any {
46        let detail_data: pb::LocalizedMessage = self.into();
47
48        Any {
49            type_url: LocalizedMessage::TYPE_URL.to_string(),
50            value: detail_data.encode_to_vec(),
51        }
52    }
53}
54
55impl FromAny for LocalizedMessage {
56    #[inline]
57    fn from_any(any: Any) -> Result<Self, DecodeError> {
58        FromAnyRef::from_any_ref(&any)
59    }
60}
61
62impl FromAnyRef for LocalizedMessage {
63    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {
64        let buf: &[u8] = &any.value;
65        let loc_message = pb::LocalizedMessage::decode(buf)?;
66
67        Ok(loc_message.into())
68    }
69}
70
71impl From<pb::LocalizedMessage> for LocalizedMessage {
72    fn from(loc_message: pb::LocalizedMessage) -> Self {
73        LocalizedMessage {
74            locale: loc_message.locale,
75            message: loc_message.message,
76        }
77    }
78}
79
80impl From<LocalizedMessage> for pb::LocalizedMessage {
81    fn from(loc_message: LocalizedMessage) -> Self {
82        pb::LocalizedMessage {
83            locale: loc_message.locale,
84            message: loc_message.message,
85        }
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::super::super::{FromAny, IntoAny};
92    use super::LocalizedMessage;
93
94    #[test]
95    fn gen_localized_message() {
96        let loc_message = LocalizedMessage::new("en-US", "message for the user");
97
98        let formatted = format!("{loc_message:?}");
99
100        let expected_filled =
101            "LocalizedMessage { locale: \"en-US\", message: \"message for the user\" }";
102
103        assert!(
104            formatted.eq(expected_filled),
105            "filled LocalizedMessage differs from expected result"
106        );
107
108        let gen_any = loc_message.into_any();
109
110        let formatted = format!("{gen_any:?}");
111
112        let expected =
113            "Any { type_url: \"type.googleapis.com/google.rpc.LocalizedMessage\", value: [10, 5, 101, 110, 45, 85, 83, 18, 20, 109, 101, 115, 115, 97, 103, 101, 32, 102, 111, 114, 32, 116, 104, 101, 32, 117, 115, 101, 114] }";
114
115        assert!(
116            formatted.eq(expected),
117            "Any from filled LocalizedMessage differs from expected result"
118        );
119
120        let br_details = match LocalizedMessage::from_any(gen_any) {
121            Err(error) => panic!("Error generating LocalizedMessage from Any: {error:?}"),
122            Ok(from_any) => from_any,
123        };
124
125        let formatted = format!("{br_details:?}");
126
127        assert!(
128            formatted.eq(expected_filled),
129            "LocalizedMessage from Any differs from expected result"
130        );
131    }
132}