1#[derive(Clone, Debug, Default, PartialEq)]
54#[non_exhaustive]
55pub struct Any(serde_json::Map<String, serde_json::Value>);
56
57#[derive(thiserror::Error, Debug)]
59pub enum AnyError {
60 #[error("cannot serialize object into an Any, source={0:?}")]
62 SerializationError(#[source] BoxedError),
63
64 #[error("cannot deserialize from an Any, source={0:?}")]
66 DeserializationError(#[source] BoxedError),
67
68 #[error("expected type mismatch in Any deserialization type={0}")]
70 TypeMismatchError(String),
71}
72
73impl AnyError {
74 pub(crate) fn ser<T: Into<BoxedError>>(v: T) -> Self {
75 Self::SerializationError(v.into())
76 }
77
78 pub(crate) fn deser<T: Into<BoxedError>>(v: T) -> Self {
79 Self::DeserializationError(v.into())
80 }
81}
82
83type BoxedError = Box<dyn std::error::Error + Send + Sync>;
84type Error = AnyError;
85
86impl Any {
87 pub fn type_url(&self) -> Option<&str> {
97 self.0.get("@type").and_then(serde_json::Value::as_str)
98 }
99
100 pub fn try_from<T>(message: &T) -> Result<Self, Error>
103 where
104 T: serde::ser::Serialize + crate::message::Message,
105 {
106 let value = message.to_map()?;
107 Ok(Any(value))
108 }
109
110 pub fn try_into_message<T>(&self) -> Result<T, Error>
112 where
113 T: serde::de::DeserializeOwned + crate::message::Message,
114 {
115 let map = &self.0;
116 let r#type = map
117 .get("@type")
118 .and_then(|v| v.as_str())
119 .ok_or_else(|| "@type field is missing or is not a string".to_string())
120 .map_err(Error::deser)?;
121 Self::check_typename(r#type, T::typename())?;
122 T::from_map(map)
123 }
124
125 fn check_typename(got: &str, want: &str) -> Result<(), Error> {
126 if got == want {
127 return Ok(());
128 }
129 Err(Error::deser(format!(
130 "mismatched typenames extracting from Any, the any has {got}, the target type is {want}"
131 )))
132 }
133}
134
135impl crate::message::Message for Any {
136 fn typename() -> &'static str {
137 "type.googleapis.com/google.protobuf.Any"
138 }
139 fn to_map(&self) -> Result<crate::message::Map, AnyError> {
140 use serde_json::Value;
141 let map = [
142 ("@type", Value::String(Self::typename().into())),
143 ("value", Value::Object(self.0.clone())),
144 ]
145 .into_iter()
146 .map(|(k, v)| (k.to_string(), v))
147 .collect::<crate::message::Map>();
148 Ok(map)
149 }
150 fn from_map(map: &crate::message::Map) -> Result<Self, AnyError> {
151 crate::message::from_value(map)
152 }
153}
154
155impl serde::ser::Serialize for Any {
157 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158 where
159 S: serde::ser::Serializer,
160 {
161 self.0.serialize(serializer)
162 }
163}
164
165impl<'de> serde::de::Deserialize<'de> for Any {
167 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168 where
169 D: serde::Deserializer<'de>,
170 {
171 let value = serde_json::Map::<String, serde_json::Value>::deserialize(deserializer)?;
172 Ok(Any(value))
173 }
174}
175
176#[cfg(test)]
177mod test {
178 use super::*;
179 use crate::duration::*;
180 use crate::empty::Empty;
181 use crate::field_mask::*;
182 use crate::timestamp::*;
183 use serde_json::json;
184 type Result = std::result::Result<(), Box<dyn std::error::Error>>;
185
186 #[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
187 #[serde(rename_all = "camelCase")]
188 #[non_exhaustive]
189 pub struct Stored {
190 #[serde(skip_serializing_if = "String::is_empty")]
191 pub parent: String,
192 #[serde(skip_serializing_if = "String::is_empty")]
193 pub id: String,
194 }
195
196 impl crate::message::Message for Stored {
197 fn typename() -> &'static str {
198 "type.googleapis.com/wkt.test.Stored"
199 }
200 }
201
202 #[test]
203 fn serialize_any() -> Result {
204 let d = Duration::clamp(60, 0);
205 let any = Any::try_from(&d)?;
206 let any = Any::try_from(&any)?;
207 assert_eq!(
208 any.type_url(),
209 Some("type.googleapis.com/google.protobuf.Any")
210 );
211 let got = serde_json::to_value(any)?;
212 let want = json!({
213 "@type": "type.googleapis.com/google.protobuf.Any",
214 "value": {
215 "@type": "type.googleapis.com/google.protobuf.Duration",
216 "value": "60s"
217 }
218 });
219 assert_eq!(got, want);
220 Ok(())
221 }
222
223 #[test]
224 fn deserialize_any() -> Result {
225 let input = json!({
226 "@type": "type.googleapis.com/google.protobuf.Any",
227 "value": {
228 "@type": "type.googleapis.com/google.protobuf.Duration",
229 "value": "60s"
230 }
231 });
232 let any = Any(input.as_object().unwrap().clone());
233 assert_eq!(
234 any.type_url(),
235 Some("type.googleapis.com/google.protobuf.Any")
236 );
237 let any = any.try_into_message::<Any>()?;
238 assert_eq!(
239 any.type_url(),
240 Some("type.googleapis.com/google.protobuf.Duration")
241 );
242 let d = any.try_into_message::<Duration>()?;
243 assert_eq!(d, Duration::clamp(60, 0));
244 Ok(())
245 }
246
247 #[test]
248 fn serialize_duration() -> Result {
249 let d = Duration::clamp(60, 0);
250 let any = Any::try_from(&d)?;
251 assert_eq!(
252 any.type_url(),
253 Some("type.googleapis.com/google.protobuf.Duration")
254 );
255 let got = serde_json::to_value(any)?;
256 let want = json!({"@type": "type.googleapis.com/google.protobuf.Duration", "value": "60s"});
257 assert_eq!(got, want);
258 Ok(())
259 }
260
261 #[test]
262 fn deserialize_duration() -> Result {
263 let input =
264 json!({"@type": "type.googleapis.com/google.protobuf.Duration", "value": "60s"});
265 let any = Any(input.as_object().unwrap().clone());
266 assert_eq!(
267 any.type_url(),
268 Some("type.googleapis.com/google.protobuf.Duration")
269 );
270 let d = any.try_into_message::<Duration>()?;
271 assert_eq!(d, Duration::clamp(60, 0));
272 Ok(())
273 }
274
275 #[test]
276 fn serialize_empty() -> Result {
277 let empty = Empty::default();
278 let any = Any::try_from(&empty)?;
279 assert_eq!(
280 any.type_url(),
281 Some("type.googleapis.com/google.protobuf.Empty")
282 );
283 let got = serde_json::to_value(any)?;
284 let want = json!({"@type": "type.googleapis.com/google.protobuf.Empty"});
285 assert_eq!(got, want);
286 Ok(())
287 }
288
289 #[test]
290 fn deserialize_empty() -> Result {
291 let input = json!({"@type": "type.googleapis.com/google.protobuf.Empty"});
292 let any = Any(input.as_object().unwrap().clone());
293 assert_eq!(
294 any.type_url(),
295 Some("type.googleapis.com/google.protobuf.Empty")
296 );
297 let empty = any.try_into_message::<Empty>()?;
298 assert_eq!(empty, Empty::default());
299 Ok(())
300 }
301
302 #[test]
303 fn serialize_field_mask() -> Result {
304 let d = FieldMask::default().set_paths(["a", "b"].map(str::to_string).to_vec());
305 let any = Any::try_from(&d)?;
306 assert_eq!(
307 any.type_url(),
308 Some("type.googleapis.com/google.protobuf.FieldMask")
309 );
310 let got = serde_json::to_value(any)?;
311 let want =
312 json!({"@type": "type.googleapis.com/google.protobuf.FieldMask", "paths": "a,b"});
313 assert_eq!(got, want);
314 Ok(())
315 }
316
317 #[test]
318 fn deserialize_field_mask() -> Result {
319 let input =
320 json!({"@type": "type.googleapis.com/google.protobuf.FieldMask", "paths": "a,b"});
321 let any = Any(input.as_object().unwrap().clone());
322 assert_eq!(
323 any.type_url(),
324 Some("type.googleapis.com/google.protobuf.FieldMask")
325 );
326 let d = any.try_into_message::<FieldMask>()?;
327 assert_eq!(
328 d,
329 FieldMask::default().set_paths(["a", "b"].map(str::to_string).to_vec())
330 );
331 Ok(())
332 }
333
334 #[test]
335 fn serialize_timestamp() -> Result {
336 let d = Timestamp::clamp(123, 0);
337 let any = Any::try_from(&d)?;
338 assert_eq!(
339 any.type_url(),
340 Some("type.googleapis.com/google.protobuf.Timestamp")
341 );
342 let got = serde_json::to_value(any)?;
343 let want = json!({"@type": "type.googleapis.com/google.protobuf.Timestamp", "value": "1970-01-01T00:02:03Z"});
344 assert_eq!(got, want);
345 Ok(())
346 }
347
348 #[test]
349 fn deserialize_timestamp() -> Result {
350 let input = json!({"@type": "type.googleapis.com/google.protobuf.Timestamp", "value": "1970-01-01T00:02:03Z"});
351 let any = Any(input.as_object().unwrap().clone());
352 assert_eq!(
353 any.type_url(),
354 Some("type.googleapis.com/google.protobuf.Timestamp")
355 );
356 let d = any.try_into_message::<Timestamp>()?;
357 assert_eq!(d, Timestamp::clamp(123, 0));
358 Ok(())
359 }
360
361 #[test]
362 fn serialize_generic() -> Result {
363 let d = Stored {
364 parent: "parent".to_string(),
365 id: "id".to_string(),
366 };
367 let any = Any::try_from(&d)?;
368 assert_eq!(any.type_url(), Some("type.googleapis.com/wkt.test.Stored"));
369 let got = serde_json::to_value(any)?;
370 let want =
371 json!({"@type": "type.googleapis.com/wkt.test.Stored", "parent": "parent", "id": "id"});
372 assert_eq!(got, want);
373 Ok(())
374 }
375
376 #[test]
377 fn deserialize_generic() -> Result {
378 let input =
379 json!({"@type": "type.googleapis.com/wkt.test.Stored", "parent": "parent", "id": "id"});
380 let any = Any(input.as_object().unwrap().clone());
381 assert_eq!(any.type_url(), Some("type.googleapis.com/wkt.test.Stored"));
382 let d = any.try_into_message::<Stored>()?;
383 assert_eq!(
384 d,
385 Stored {
386 parent: "parent".to_string(),
387 id: "id".to_string()
388 }
389 );
390 Ok(())
391 }
392
393 #[derive(Default, serde::Serialize, serde::Deserialize)]
394 struct DetectBadMessages(serde_json::Value);
395 impl crate::message::Message for DetectBadMessages {
396 fn typename() -> &'static str {
397 "not used"
398 }
399 }
400
401 #[test]
402 fn try_from_error() -> Result {
403 let input = DetectBadMessages(json!([2, 3]));
404 let got = Any::try_from(&input);
405 assert!(got.is_err(), "{got:?}");
406
407 Ok(())
408 }
409
410 #[test]
411 fn deserialize_missing_type_field() -> Result {
412 let input = json!({"@type-is-missing": ""});
413 let any = serde_json::from_value::<Any>(input)?;
414 let got = any.try_into_message::<Stored>();
415 assert!(got.is_err());
416 Ok(())
417 }
418
419 #[test]
420 fn deserialize_invalid_type_field() -> Result {
421 let input = json!({"@type": [1, 2, 3]});
422 let any = serde_json::from_value::<Any>(input)?;
423 let got = any.try_into_message::<Stored>();
424 assert!(got.is_err());
425 Ok(())
426 }
427
428 #[test]
429 fn deserialize_missing_value_field() -> Result {
430 let input = json!({"@type": "type.googleapis.com/google.protobuf.Duration", "value-is-missing": "1.2s"});
431 let any = serde_json::from_value::<Any>(input)?;
432 let got = any.try_into_message::<Duration>();
433 assert!(got.is_err());
434 Ok(())
435 }
436
437 #[test]
438 fn deserialize_invalid_value_field() -> Result {
439 let input =
440 json!({"@type": "type.googleapis.com/google.protobuf.Duration", "value": ["1.2s"]});
441 let any = serde_json::from_value::<Any>(input)?;
442 let got = any.try_into_message::<Duration>();
443 assert!(got.is_err());
444 Ok(())
445 }
446
447 #[test]
448 fn deserialize_type_mismatch() -> Result {
449 let input =
450 json!({"@type": "type.googleapis.com/google.protobuf.Duration", "value": "1.2s"});
451 let any = serde_json::from_value::<Any>(input)?;
452 let got = any.try_into_message::<Timestamp>();
453 assert!(got.is_err());
454 let error = got.err().unwrap();
455 assert!(
456 format!("{error}").contains("type.googleapis.com/google.protobuf.Duration"),
457 "{error}"
458 );
459 assert!(
460 format!("{error}").contains("type.googleapis.com/google.protobuf.Timestamp"),
461 "{error}"
462 );
463 Ok(())
464 }
465}