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}