wireman_core/descriptor/
message.rs

1mod template;
2
3use self::template::apply_template_for_message;
4use crate::{
5    error::{Error, FROM_UTF8},
6    Result,
7};
8use prost_reflect::{
9    DeserializeOptions, DynamicMessage as DynMessage, MessageDescriptor, ReflectMessage,
10    SerializeOptions,
11};
12use serde::{Serialize, Serializer};
13use std::ops::{Deref, DerefMut};
14
15/// Represents a dynamic `gRPC` message that can be used
16/// with various message types.
17#[derive(Debug, Clone)]
18pub struct DynamicMessage {
19    inner: DynMessage,
20}
21
22impl Deref for DynamicMessage {
23    type Target = DynMessage;
24
25    fn deref(&self) -> &DynMessage {
26        &self.inner
27    }
28}
29
30impl DerefMut for DynamicMessage {
31    fn deref_mut(&mut self) -> &mut Self::Target {
32        &mut self.inner
33    }
34}
35
36type JsonSerializer = serde_json::Serializer<Vec<u8>>;
37
38impl DynamicMessage {
39    /// Create a new `DynamicMessage` from a `MessageDescriptor`.
40    #[must_use]
41    pub fn new(message_desc: MessageDescriptor) -> Self {
42        let message = DynMessage::new(message_desc);
43        Self { inner: message }
44    }
45
46    /// Get the name of the message as a String.
47    #[must_use]
48    pub fn message_name(&self) -> String {
49        self.descriptor().name().to_string()
50    }
51
52    /// Get the message descriptor.
53    #[must_use]
54    pub fn descriptor(&self) -> MessageDescriptor {
55        self.inner.descriptor()
56    }
57
58    /// Deserialize a `DynamicMessage` from a JSON string.
59    ///
60    /// # Errors
61    ///
62    /// - Failed to deserialize message.
63    pub fn from_json(&mut self, json: &str) -> Result<()> {
64        let mut de = serde_json::Deserializer::from_str(json);
65        let msg = DynMessage::deserialize_with_options(
66            self.descriptor(),
67            &mut de,
68            &DeserializeOptions::new(),
69        )
70        .map_err(Error::DeserializeMessage)?;
71        de.end().map_err(Error::DeserializeMessage)?;
72        self.inner = msg;
73        Ok(())
74    }
75
76    /// Serialize a `DynamicMessage` to a JSON string.
77    ///
78    /// # Errors
79    ///
80    /// - Failed to convert utf8 to String
81    /// - Failed to serialize message
82    pub fn to_json(&self) -> Result<String> {
83        let mut s = serde_json::Serializer::new(Vec::new());
84        self.serialize(&mut s).map_err(Error::SerializeJsonError)?;
85        String::from_utf8(s.into_inner()).map_err(|_| Error::Internal(FROM_UTF8.to_string()))
86    }
87
88    /// Apply default values to a `DynamicMessage`.
89    pub fn apply_template(&mut self) {
90        apply_template_for_message(self, 0);
91    }
92}
93
94impl Serialize for DynamicMessage {
95    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
96    where
97        S: Serializer,
98    {
99        self.inner.serialize_with_options(
100            serializer,
101            &SerializeOptions::new()
102                .stringify_64_bit_integers(false)
103                .skip_default_fields(false),
104        )
105    }
106}
107
108#[cfg(test)]
109mod test {
110    use crate::ProtoDescriptor;
111
112    use super::*;
113
114    #[test]
115    fn test_template_nested() {
116        // given
117        let mut given_message = load_test_message("Nested");
118        let expected_json = "{\"items\":[{\"number\":0,\"text\":\"\"}]}";
119
120        // when
121        given_message.apply_template();
122        let json = given_message.to_json().unwrap();
123
124        // then
125        assert_eq!(json, expected_json);
126    }
127
128    #[test]
129    fn test_template_repeated() {
130        // given
131        let mut given_message = load_test_message("Repeated");
132        let expected_json = "{\"number\":[0]}";
133
134        // when
135        given_message.apply_template();
136        let json = given_message.to_json().unwrap();
137
138        // then
139        assert_eq!(json, expected_json);
140    }
141
142    #[test]
143    fn test_template_enum() {
144        // given
145        let mut given_message = load_test_message("Enum");
146        let expected_json = "{\"color\":\"NONE\"}";
147
148        // when
149        given_message.apply_template();
150        let json = given_message.to_json().unwrap();
151
152        // then
153        assert_eq!(json, expected_json);
154    }
155
156    fn load_test_message(method: &str) -> DynamicMessage {
157        let files = vec!["test_files/test.proto"];
158        let includes = vec!["."];
159
160        let desc = ProtoDescriptor::new(includes, files).unwrap();
161
162        let method = desc
163            .get_method_by_name("proto.TestService", method)
164            .unwrap();
165        let request = method.input();
166        DynamicMessage::new(request)
167    }
168
169    #[test]
170    fn test_to_json() {
171        // given
172        let given_message = load_test_message("Simple");
173
174        // when
175        let json = given_message.to_json().unwrap();
176
177        // then
178        let expected_json = "{\"number\":0}";
179        assert_eq!(json, expected_json);
180    }
181
182    #[test]
183    fn test_from_json() {
184        // given
185        let mut given_message = load_test_message("Multiple");
186        let given_json = "{\"number\":1}";
187        given_message.from_json(given_json).unwrap();
188
189        // when
190        let json = given_message.to_json().unwrap();
191
192        // then
193        let expected_json = "{\"id\":\"\",\"number\":1}";
194        assert_eq!(json, expected_json);
195    }
196}