1use serde::de::{DeserializeOwned, Error as _};
5use serde::ser::SerializeMap;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use serde_json::{Map, Value};
8
9#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
11#[serde(default, rename_all = "camelCase")]
12pub struct Status {
13 pub code: i32,
15 pub message: String,
17 #[serde(skip_serializing_if = "Vec::is_empty")]
20 pub details: Vec<Any>,
21}
22
23#[derive(Clone, Debug, Default, PartialEq)]
26pub struct Any {
27 type_url: String,
28 fields: Map<String, Value>,
29}
30
31impl Any {
32 pub fn new(type_url: impl Into<String>, fields: Map<String, Value>) -> Self {
35 Self {
36 type_url: type_url.into(),
37 fields,
38 }
39 }
40
41 pub fn type_url(&self) -> &str {
43 &self.type_url
44 }
45
46 pub fn type_name(&self) -> &str {
49 self.type_url.rsplit('/').next().unwrap_or_default()
50 }
51
52 pub fn fields(&self) -> &Map<String, Value> {
54 &self.fields
55 }
56
57 pub fn decode<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
60 if self.type_name().starts_with("google.protobuf.")
61 && let Some(value) = self.fields.get("value")
62 {
63 return T::deserialize(value);
64 }
65 T::deserialize(Value::Object(self.fields.clone()))
66 }
67
68 pub(crate) fn string(&self, name: &str) -> &str {
70 self.fields
71 .get(name)
72 .and_then(Value::as_str)
73 .unwrap_or_default()
74 }
75}
76
77impl Serialize for Any {
78 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
79 let mut map = serializer.serialize_map(Some(self.fields.len() + 1))?;
80 map.serialize_entry("@type", &self.type_url)?;
81 for (name, value) in &self.fields {
82 map.serialize_entry(name, value)?;
83 }
84 map.end()
85 }
86}
87
88impl<'de> Deserialize<'de> for Any {
89 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
90 let mut fields = Map::deserialize(deserializer)?;
91 let type_url = match fields.remove("@type") {
92 Some(Value::String(url)) => url,
93 Some(_) => return Err(D::Error::custom("@type isn't a string")),
94 None => String::new(),
95 };
96 Ok(Self { type_url, fields })
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn an_any_keeps_its_type_apart_from_its_fields() {
106 let any: Any = serde_json::from_str(
107 r#"{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"NOT_FOUND"}"#,
108 )
109 .unwrap();
110 assert_eq!(any.type_name(), "google.rpc.ErrorInfo");
111 assert_eq!(any.string("reason"), "NOT_FOUND");
112 assert_eq!(
113 serde_json::to_string(&any).unwrap(),
114 r#"{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"NOT_FOUND"}"#
115 );
116 }
117
118 #[test]
119 fn a_well_known_type_is_read_from_its_value() {
120 let any: Any = serde_json::from_str(
121 r#"{"@type":"type.googleapis.com/google.protobuf.Empty","value":{}}"#,
122 )
123 .unwrap();
124 any.decode::<crate::protobuf::Empty>().unwrap();
125 let bare: Any =
126 serde_json::from_str(r#"{"@type":"type.googleapis.com/google.protobuf.Empty"}"#)
127 .unwrap();
128 bare.decode::<crate::protobuf::Empty>().unwrap();
129 }
130}