wamp_core/messages/
yield.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/// # Yield - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-yield-2)
11///  Represents an Yield message in the WAMP protocol.
12/// ## Examples
13/// ```
14/// use wamp_core::messages::Yield;
15/// use wamp_core::r#yield;
16/// use serde_json::{json, Value};
17///
18/// let r#yield = Yield {
19///     request_id: 2,
20///     options: json!({}),
21///     args: serde_json::Value::Null,
22///     kwargs: serde_json::Value::Null
23/// };
24///
25/// let mut r#yield2 = r#yield!{1, json!({})};
26///
27/// assert_ne!(r#yield, r#yield2);
28///
29/// r#yield2.request_id = 2;
30///
31/// assert_eq!(r#yield, r#yield2);
32/// ```
33/// ### Serializer
34/// Serde Serialize trait implementation for Yield.
35/// ```
36/// use wamp_core::messages::Yield;
37/// use serde_json::{json, to_string};
38///
39/// let r#yield = Yield {
40///     request_id: 2,
41///     options: json!({}),
42///     args: json!([1, 2, 3]),
43///     kwargs: json!({"key": "value"})
44/// };
45///
46/// let r#yield2_string = r#"[70,2,{},[1,2,3],{"key":"value"}]"#;
47///
48/// let r#yield_string = to_string(&r#yield).unwrap();
49/// assert_eq!(r#yield_string, r#yield2_string);
50/// ```
51/// ### Deserializer
52/// Serde Deserialize trait implementation for Yield.
53/// ```
54/// use wamp_core::messages::Yield;
55/// use serde_json::{json, from_str};
56///
57/// let r#yield = Yield {
58///     request_id: 2,
59///     options: json!({}),
60///     args: json!([1, 2, 3]),
61///     kwargs: json!({"key": "value"})
62/// };
63///
64/// let r#yield2_string = r#"[70,2,{},[1,2,3],{"key":"value"}]"#;
65///
66/// let r#yield2 = from_str::<Yield>(r#yield2_string).unwrap();
67/// assert_eq!(r#yield, r#yield2);
68/// ```
69pub struct Yield {
70    pub request_id: u64,
71    pub options: Value,
72    pub args: Value,
73    pub kwargs: Value,
74}
75
76#[macro_export]
77/// ## Yield Macro - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-yield-2)
78/// Yield macro for easy creation with default values
79/// ### Examples
80/// ```
81/// use wamp_core::r#yield;
82/// use wamp_core::messages::Yield;
83/// use serde_json::{json, Value};
84///
85/// // Create a r#yield message with default values
86/// let mut r#yield = r#yield!(1, json!({}));
87///
88/// // Which is the same as creating this:
89/// let r#yield2 = Yield {
90///     request_id: 2,
91///     options: json!({}),
92///     args: Value::Null,
93///     kwargs: Value::Null
94/// };
95///
96/// assert_ne!(r#yield, r#yield2);
97///
98/// r#yield.request_id = 2;
99///
100/// assert_eq!(r#yield, r#yield2);
101///
102/// // Some other ways you can construct it using the macro
103///
104/// // Create a r#yield with custom options but empty args and kwargs
105/// let _ = r#yield!(2, json!( { "key": "value" } ));
106///
107/// // Create a r#yield with custom args or kwargs, but empty options
108/// let _ = r#yield!(2, args: json!( [ 1, 2, 3 ] ));
109/// let _ = r#yield!(2, kwargs: json!( { "key": "value" } ));
110///
111/// // Create a r#yield with custom args and kwargs, but empty options
112/// let _ = r#yield!(2, args: json!([ 1, 2, 3 ]), kwargs: json!({ "key": "value" }));
113///
114/// // Create a r#yield with custom options, and either custom args OR custom kwargs
115/// let _ = r#yield!(2, json!( { "key": "value" } ), args: json!( [ 1, 2, 3 ] ));
116/// let _ = r#yield!(2, json!( { "key": "value" } ), kwargs: json!( { "key": "value" } ));
117///
118/// // Create a r#yield with custom options, and both custom args and kwargs
119/// // Note that when you use all "required" arguments for the struuct, keyword arguments should not be used for args and kwargs
120/// let _ = r#yield!(2, json!({}), json!([]), json!({}));
121/// ```
122macro_rules! r#yield {
123    ($request_id:expr) => {
124        r#yield! {$request_id, serde_json::json!({}), serde_json::Value::Null, serde_json::Value::Null}
125    };
126    ($request_id:expr, $options:expr) => {
127        r#yield! {$request_id, $options, serde_json::Value::Null, serde_json::Value::Null}
128    };
129    ($request_id:expr, args: $args:expr) => {
130        r#yield! {$request_id, serde_json::json!({}), $args, serde_json::Value::Null}
131    };
132    ($request_id:expr, kwargs: $kwargs:expr) => {
133        r#yield! {$request_id, serde_json::json!({}), serde_json::Value::Null, $kwargs}
134    };
135    ($request_id:expr, args: $args:expr, kwargs: $kwargs:expr) => {
136        r#yield! {$request_id, serde_json::json!({}), $args, $kwargs}
137    };
138    ($request_id:expr, $options:expr, args: $args:expr) => {
139        r#yield! {$request_id, $options, $args, serde_json::Value::Null}
140    };
141    ($request_id:expr, $options:expr, kwargs: $kwargs:expr) => {
142        r#yield! {$request_id, $options, serde_json::Value::Null, $kwargs}
143    };
144    ($request_id:expr, $options:expr, $args:expr, $kwargs:expr) => {
145        Yield {
146            args: $args,
147            request_id: $request_id,
148            options: $options,
149            kwargs: $kwargs,
150        }
151    };
152}
153
154impl WampMessage for Yield {
155    const ID: u64 = 70;
156
157    fn direction(role: Roles) -> &'static MessageDirection {
158        match role {
159            Roles::Callee => &MessageDirection {
160                receives: &false,
161                sends: &true,
162            },
163            Roles::Caller => &MessageDirection {
164                receives: &false,
165                sends: &false,
166            },
167            Roles::Publisher => &MessageDirection {
168                receives: &false,
169                sends: &false,
170            },
171            Roles::Subscriber => &MessageDirection {
172                receives: &false,
173                sends: &false,
174            },
175            Roles::Dealer => &MessageDirection {
176                receives: &true,
177                sends: &false,
178            },
179            Roles::Broker => &MessageDirection {
180                receives: &false,
181                sends: &false,
182            },
183        }
184    }
185}
186
187impl Serialize for Yield {
188    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
189    where
190        S: serde::Serializer,
191    {
192        let options =
193            helpers::ser_value_is_object::<S, _>(&self.options, "options must be object like.")?;
194        let args =
195            helpers::ser_value_is_args::<S, _>(&self.args, "Args must be Array like or Null.")?;
196        let kwargs = helpers::ser_value_is_kwargs::<S, _>(
197            &self.kwargs,
198            "Kwargs must be Object like or Null.",
199        )?;
200        if args.is_null() {
201            if kwargs.is_null() {
202                (Self::ID, &self.request_id, options).serialize(serializer)
203            } else {
204                (Self::ID, &self.request_id, options, json!([]), kwargs).serialize(serializer)
205            }
206        } else {
207            if kwargs.is_null() {
208                (Self::ID, &self.request_id, options, args).serialize(serializer)
209            } else {
210                (Self::ID, &self.request_id, options, args, kwargs).serialize(serializer)
211            }
212        }
213    }
214}
215
216impl<'de> Deserialize<'de> for Yield {
217    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
218    where
219        D: Deserializer<'de>,
220    {
221        struct YieldVisitor(
222            PhantomData<u64>,
223            PhantomData<u64>,
224            PhantomData<Value>,
225            PhantomData<Value>,
226            PhantomData<Value>,
227        );
228
229        impl<'vi> Visitor<'vi> for YieldVisitor {
230            type Value = Yield;
231            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
232                formatter.write_str("A sequence of Yield components.")
233            }
234
235            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
236            where
237                A: SeqAccess<'vi>,
238            {
239                let message_id: u64 = helpers::deser_seq_element(
240                    &mut seq,
241                    "Message ID must be present and type u8.",
242                )?;
243                helpers::validate_id::<Yield, A, _>(&message_id, "Yield")?;
244                let request_id: u64 = helpers::deser_seq_element(
245                    &mut seq,
246                    "Request ID must be present and type u64.",
247                )?;
248                let options: Value = helpers::deser_seq_element(
249                    &mut seq,
250                    "options must be present and object like.",
251                )?;
252                helpers::deser_value_is_object::<A, _>(&options, "options must be object like.")?;
253                let args: Value = helpers::deser_args_kwargs_element(
254                    &mut seq,
255                    "Args must be array like or null.",
256                )?;
257                let kwargs: Value = helpers::deser_args_kwargs_element(
258                    &mut seq,
259                    "Kwargs must be object like or null.",
260                )?;
261                Ok(Yield {
262                    request_id,
263                    options,
264                    args,
265                    kwargs,
266                })
267            }
268        }
269
270        deserializer.deserialize_struct(
271            "Yield",
272            &["request_id", "options", "args", "kwargs"],
273            YieldVisitor(
274                PhantomData,
275                PhantomData,
276                PhantomData,
277                PhantomData,
278                PhantomData,
279            ),
280        )
281    }
282}