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}