protobuf/well_known_types_util/any.rs
1use crate::reflect::MessageDescriptor;
2use crate::well_known_types::Any;
3use crate::Message;
4use crate::ProtobufResult;
5
6impl Any {
7 fn type_url(type_url_prefix: &str, descriptor: &MessageDescriptor) -> String {
8 format!("{}/{}", type_url_prefix, descriptor.full_name())
9 }
10
11 fn get_type_name_from_type_url(type_url: &str) -> Option<&str> {
12 match type_url.rfind('/') {
13 Some(i) => Some(&type_url[i + 1..]),
14 None => None,
15 }
16 }
17
18 /// Pack any message into `well_known_types::Any` value.
19 ///
20 /// # Examples
21 ///
22 /// ```
23 /// # use protobuf::Message;
24 /// # use protobuf::ProtobufResult;
25 /// use protobuf::well_known_types::Any;
26 ///
27 /// # fn the_test<MyMessage: Message>(message: &MyMessage) -> ProtobufResult<()> {
28 /// let message: &MyMessage = message;
29 /// let any = Any::pack(message)?;
30 /// assert!(any.is::<MyMessage>());
31 /// # Ok(())
32 /// # }
33 /// ```
34 pub fn pack<M: Message>(message: &M) -> ProtobufResult<Any> {
35 Any::pack_dyn(message)
36 }
37
38 /// Pack any message into `well_known_types::Any` value.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// use protobuf::Message;
44 /// # use protobuf::ProtobufResult;
45 /// use protobuf::well_known_types::Any;
46 ///
47 /// # fn the_test(message: &dyn Message) -> ProtobufResult<()> {
48 /// let message: &dyn Message = message;
49 /// let any = Any::pack_dyn(message)?;
50 /// assert!(any.is_dyn(message.descriptor()));
51 /// # Ok(())
52 /// # }
53 /// ```
54 pub fn pack_dyn(message: &dyn Message) -> ProtobufResult<Any> {
55 Any::pack_with_type_url_prefix(message, "type.googleapis.com")
56 }
57
58 fn pack_with_type_url_prefix(
59 message: &dyn Message,
60 type_url_prefix: &str,
61 ) -> ProtobufResult<Any> {
62 Ok(Any {
63 type_url: Any::type_url(type_url_prefix, message.descriptor()),
64 value: message.write_to_bytes()?,
65 ..Default::default()
66 })
67 }
68
69 /// Check if `Any` contains a message of given type.
70 pub fn is<M: Message>(&self) -> bool {
71 self.is_dyn(M::descriptor_static())
72 }
73
74 /// Check if `Any` contains a message of given type.
75 pub fn is_dyn(&self, descriptor: &MessageDescriptor) -> bool {
76 match Any::get_type_name_from_type_url(&self.type_url) {
77 Some(type_name) => type_name == descriptor.full_name(),
78 None => false,
79 }
80 }
81
82 /// Extract a message from this `Any`.
83 ///
84 /// # Returns
85 ///
86 /// * `Ok(None)` when message type mismatch
87 /// * `Err` when parse failed
88 pub fn unpack<M: Message>(&self) -> ProtobufResult<Option<M>> {
89 if !self.is::<M>() {
90 return Ok(None);
91 }
92 Ok(Some(M::parse_from_bytes(&self.value)?))
93 }
94
95 /// Extract a message from this `Any`.
96 ///
97 /// # Returns
98 ///
99 /// * `Ok(None)` when message type mismatch
100 /// * `Err` when parse failed
101 pub fn unpack_dyn(
102 &self,
103 descriptor: &MessageDescriptor,
104 ) -> ProtobufResult<Option<Box<dyn Message>>> {
105 if !self.is_dyn(descriptor) {
106 return Ok(None);
107 }
108 let mut message = descriptor.new_instance();
109 message.merge_from_bytes(&self.value)?;
110 message.check_initialized()?;
111 Ok(Some(message))
112 }
113}