wamp_core/messages/
invocation.rs

1use super::{helpers, MessageDirection, WampMessage};
2use crate::roles::Roles;
3use serde::de::{SeqAccess, Visitor};
4use serde::{Deserialize, Deserializer, Serialize};
5use serde_json::{json, Value};
6use std::fmt::Formatter;
7use std::marker::PhantomData;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10/// # Invocation - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-invocation-2)
11///  Represents an invocation message in the WAMP protocol.
12/// ## Examples
13/// ```
14/// use wamp_core::messages::Invocation;
15/// use wamp_core::invocation;
16/// use serde_json::{json, Value};
17///
18/// let invocation = Invocation {
19///     request_id: 1,
20///     registration: 2,
21///     details: json!({}),
22///     args: Value::Null,
23///     kwargs: Value::Null
24/// };
25///
26/// let invocation2 = invocation!(2);
27///
28/// assert_eq!(invocation, invocation2);
29/// ```
30/// ### Serializer
31/// Serde Serialize trait implementation for invocation.
32/// ```
33/// use wamp_core::messages::Invocation;
34/// use serde_json::{json, to_string};
35///
36/// let invocation = Invocation {
37///     request_id: 1,
38///     registration: 2,
39///     details: json!({}),
40///     args: json!([1, 2, 3]),
41///     kwargs: json!({"key": "value"})
42/// };
43///
44/// let invocation2_string = r#"[68,1,2,{},[1,2,3],{"key":"value"}]"#;
45///
46/// let invocation_string = to_string(&invocation).unwrap();
47/// assert_eq!(invocation_string, invocation2_string);
48/// ```
49/// ### Deserializer
50/// Serde Deserialize trait implementation for invocation.
51/// ```
52/// use wamp_core::messages::Invocation;
53/// use serde_json::{json, from_str};
54///
55/// let invocation = Invocation {
56///     request_id: 1,
57///     registration: 2,
58///     details: json!({}),
59///     args: json!([1, 2, 3]),
60///     kwargs: json!({"key": "value"})
61/// };
62///
63/// let invocation2_string = r#"[68,1,2,{},[1,2,3],{"key":"value"}]"#;
64///
65/// let invocation2 = from_str::<Invocation>(invocation2_string).unwrap();
66/// assert_eq!(invocation, invocation2);
67/// ```
68pub struct Invocation {
69    pub request_id: u64,
70    pub registration: u64,
71    pub details: Value,
72    pub args: Value,
73    pub kwargs: Value,
74}
75
76#[macro_export]
77/// ## invocation Macro - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-invocation-2)
78/// Macro for creating invocation messages easily with auto incrementing request id.
79/// ### Examples
80/// ```
81/// use wamp_core::invocation;
82/// use wamp_core::messages::Invocation;
83/// use serde_json::{json, Value};
84///
85/// // Create a invocation message with default values
86/// let invocation = invocation!(2);
87///
88/// // Which is the same as creating this:
89/// let invocation2 = Invocation {
90///     request_id: 1,
91///     registration: 2,
92///     details: json!({}),
93///     args: Value::Null,
94///     kwargs: Value::Null
95/// };
96///
97/// assert_eq!(invocation, invocation2);
98///
99/// // Some other ways you can construct it using the macro
100///
101/// // Create a invocation with custom details but empty args and kwargs
102/// let _ = invocation!(2, json!( { "key": "value" } ));
103///
104/// // Create a invocation with custom args or kwargs, but empty details
105/// let _ = invocation!(2, args: json!( [ 1, 2, 3 ] ));
106/// let _ = invocation!(2, kwargs: json!( { "key": "value" } ));
107///
108/// // Create a invocation with custom args and kwargs, but empty details
109/// let _ = invocation!(2, args: json!([ 1, 2, 3 ]), kwargs: json!({ "key": "value" }));
110///
111/// // Create a invocation with custom details, and either custom args OR custom kwargs
112/// let _ = invocation!(2, json!( { "key": "value" } ), args: json!( [ 1, 2, 3 ] ));
113/// let _ = invocation!(2, json!( { "key": "value" } ), kwargs: json!( { "key": "value" } ));
114///
115/// // Create a invocation with custom details, and both custom args and kwargs
116/// // Note that when you use all "required" arguments for the struuct, keyword arguments should not be used for args and kwargs
117/// let _ = invocation!(2, json!({}), json!([]), json!({}));
118/// ```
119macro_rules! invocation {
120    ($registration:expr) => {
121        invocation!{$registration, serde_json::json!({}), serde_json::Value::Null, serde_json::Value::Null}
122    };
123
124    ($registration:expr, $details:expr) => {
125        invocation!{$registration, $details, serde_json::Value::Null, serde_json::Value::Null}
126    };
127
128    ($registration:expr, args: $args:expr) => {
129        invocation!{$registration, serde_json::json!({}), $args, serde_json::Value::Null}
130    };
131
132    ($registration:expr, kwargs: $kwargs:expr) => {
133        invocation!{$registration, serde_json::json!({}), serde_json::Value::Null, $kwargs}
134    };
135
136    ($registration:expr, args: $args:expr, kwargs: $kwargs:expr) => {
137        invocation!{$registration, serde_json::json!({}), $args, $kwargs}
138    };
139
140    ($registration:expr, $details:expr, args: $args:expr) => {
141        invocation!{$registration, $details, $args, serde_json::Value::Null}
142    };
143
144    ($registration:expr, $details:expr, kwargs: $kwargs:expr) => {
145        invocation!{$registration, $details, serde_json::Value::Null, $kwargs}
146    };
147
148    ($registration:expr, $details:expr, $args:expr, $kwargs:expr) => {{
149        Invocation {
150            request_id: $crate::factories::increment(),
151            details: $details,
152            registration: $registration,
153            args: $args,
154            kwargs: $kwargs
155        }
156    }};
157}
158
159impl WampMessage for Invocation {
160    const ID: u64 = 68;
161
162    fn direction(role: Roles) -> &'static MessageDirection {
163        match role {
164            Roles::Callee => &MessageDirection {
165                receives: &true,
166                sends: &false,
167            },
168            Roles::Caller => &MessageDirection {
169                receives: &false,
170                sends: &false,
171            },
172            Roles::Publisher => &MessageDirection {
173                receives: &false,
174                sends: &false,
175            },
176            Roles::Subscriber => &MessageDirection {
177                receives: &false,
178                sends: &false,
179            },
180            Roles::Dealer => &MessageDirection {
181                receives: &false,
182                sends: &true,
183            },
184            Roles::Broker => &MessageDirection {
185                receives: &false,
186                sends: &false,
187            },
188        }
189    }
190}
191
192impl Serialize for Invocation {
193    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194    where
195        S: serde::Serializer,
196    {
197        let args =
198            helpers::ser_value_is_args::<S, _>(&self.args, "Args must be Array like or Null.")?;
199        let kwargs = helpers::ser_value_is_kwargs::<S, _>(
200            &self.kwargs,
201            "Kwargs must be Object like or Null.",
202        )?;
203
204        if args.is_null() {
205            if kwargs.is_null() {
206                (
207                    Self::ID,
208                    &self.request_id,
209                    &self.registration,
210                    &self.details,
211                )
212                    .serialize(serializer)
213            } else {
214                (
215                    Self::ID,
216                    &self.request_id,
217                    &self.registration,
218                    &self.details,
219                    json!([]),
220                    kwargs,
221                )
222                    .serialize(serializer)
223            }
224        } else {
225            if kwargs.is_null() {
226                (
227                    Self::ID,
228                    &self.request_id,
229                    &self.registration,
230                    &self.details,
231                    args,
232                )
233                    .serialize(serializer)
234            } else {
235                (
236                    Self::ID,
237                    &self.request_id,
238                    &self.registration,
239                    &self.details,
240                    args,
241                    kwargs,
242                )
243                    .serialize(serializer)
244            }
245        }
246    }
247}
248
249impl<'de> Deserialize<'de> for Invocation {
250    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
251    where
252        D: Deserializer<'de>,
253    {
254        struct InvocationVisitor(
255            PhantomData<u8>,
256            PhantomData<u64>,
257            PhantomData<u64>,
258            PhantomData<Value>,
259            PhantomData<Value>,
260            PhantomData<Value>,
261        );
262
263        impl<'vi> Visitor<'vi> for InvocationVisitor {
264            type Value = Invocation;
265            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
266                formatter.write_str("A sequence of Invocation components.")
267            }
268
269            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
270            where
271                A: SeqAccess<'vi>,
272            {
273                let message_id: u64 = helpers::deser_seq_element(
274                    &mut seq,
275                    "Message ID must be present and type u8.",
276                )?;
277                helpers::validate_id::<Invocation, A, _>(&message_id, "Invocation")?;
278                let request_id: u64 = helpers::deser_seq_element(
279                    &mut seq,
280                    "request_id must be present and type u64.",
281                )?;
282                let registration: u64 = helpers::deser_seq_element(
283                    &mut seq,
284                    "registration must be present and object like.",
285                )?;
286                let details: Value = helpers::deser_seq_element(
287                    &mut seq,
288                    "Details must be present and object like.",
289                )?;
290                helpers::deser_value_is_object::<A, _>(&details, "Details must be object like.")?;
291                let args: Value = helpers::deser_args_kwargs_element(
292                    &mut seq,
293                    "Args must be array like or null.",
294                )?;
295                let kwargs: Value = helpers::deser_args_kwargs_element(
296                    &mut seq,
297                    "Kwargs must be object like or null.",
298                )?;
299                Ok(Invocation {
300                    request_id,
301                    registration,
302                    details,
303                    args,
304                    kwargs,
305                })
306            }
307        }
308
309        deserializer.deserialize_struct(
310            "Invocation",
311            &["request_id", "registration", "details", "args", "kwargs"],
312            InvocationVisitor(
313                PhantomData,
314                PhantomData,
315                PhantomData,
316                PhantomData,
317                PhantomData,
318                PhantomData,
319            ),
320        )
321    }
322}
323
324#[cfg(test)]
325mod tests {
326    use serde_json::{from_str, to_string};
327
328    use super::Invocation;
329
330    #[test]
331    fn test() {
332        let d = r#"[68,6131533,9823529,{},["johnny"],{"firstname":"John","surname":"Doe"}]"#;
333        let mut ed = Invocation {
334            request_id: 6131533,
335            registration: 9823529,
336            details: serde_json::json!({}),
337            args: serde_json::Value::Null,
338            kwargs: serde_json::json!({"firstname":"John","surname":"Doe"}),
339        };
340        let ed2: Invocation = from_str(d).unwrap();
341        assert_ne!(ed, ed2);
342        ed.args = serde_json::json!(["johnny"]);
343        assert_eq!(ed, ed2);
344        let d2 = to_string(&ed).unwrap();
345        assert_eq!(d, d2);
346    }
347}