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