wamp_core/messages/abort.rs
1use super::{helpers, MessageDirection, WampMessage};
2use crate::roles::Roles;
3use serde::{
4 de::{self, Visitor},
5 Deserialize, Serialize,
6};
7use serde_json::Value;
8use std::marker::PhantomData;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11/// # Abort - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-abort-2)
12/// Represents an Abort message in the WAMP protocol.
13/// ## Examples
14/// ```
15/// use wamp_core::messages::Abort;
16/// use wamp_core::abort;
17/// use serde_json::json;
18/// # let mut abort_message2 = abort!("wamp.error.no_such_realm");
19///
20/// let abort_message = Abort {
21/// reason: "wamp.error.no_such_realm".to_string(),
22/// details: json!({})
23/// };
24///
25/// # assert_eq!(abort_message, abort_message2);
26/// ```
27/// ### Serializer
28/// Implements serde Serialize trait for Abort
29/// ```
30/// use wamp_core::messages::Abort;
31/// use serde_json::{json, to_string};
32///
33/// // Create an Abort message
34/// let abort = Abort {
35/// details: json!({ "message": "The realm does not exist." }),
36/// reason: "wamp.error.no_such_realm".to_string()
37/// };
38///
39/// // Establish raw json data string
40/// let data = r#"[3,{"message":"The realm does not exist."},"wamp.error.no_such_realm"]"#;
41///
42/// // Here we convert it from an `Abort` frame, to a string representation.
43/// let abort = to_string(&abort).unwrap();
44///
45/// // Confirm that our abort frame strings are equal to eachother
46/// assert_eq!(abort, data);
47/// ```
48/// ### Deserializer
49/// Implements serde Deserialize trait for Abort
50/// ```
51/// use wamp_core::messages::Abort;
52/// use serde_json::from_str;
53///
54/// // Here is our raw json data string
55/// let data = r#"[3,{"message":"The realm does not exist."},"wamp.error.no_such_realm"]"#;
56///
57/// // Here we convert it to an `Abort` frame
58/// let abort = from_str::<Abort>(data).unwrap();
59///
60/// // Confirm that our error type deserialized
61/// assert_eq!(abort.reason, "wamp.error.no_such_realm");
62/// ```
63pub struct Abort {
64 pub details: Value,
65 pub reason: String,
66}
67
68#[macro_export]
69/// # Abort Macro - [wamp-proto](https://wamp-proto.org/wamp_latest_ietf.html#name-abort-2)
70/// Abort macro allows for default empty implementation of details object on Abort.
71/// ## Examples
72/// ```
73/// use wamp_core::messages::Abort;
74/// use wamp_core::abort;
75/// use serde_json::json;
76///
77/// // Construct with default empty details object
78/// let mut abort_message = abort!("wamp.error.no_such_realm");
79/// assert_eq!(abort_message.details, json!({}));
80///
81/// // Construct with custom details
82/// let abort_message2 = abort!("wamp.error.no_such_realm", json!({
83/// "message": "The realm does not exist."
84/// }));
85///
86/// assert_ne!(abort_message, abort_message2);
87/// abort_message.details = json!({ "message": "The realm does not exist." });
88/// assert_eq!(abort_message, abort_message2);
89///
90/// // These macro invocations are the same as the following:
91/// let abort_message3 = Abort {
92/// reason: "wamp.error.no_such_realm".to_string(),
93/// details: json!({
94/// "message": "The realm does not exist."
95/// })
96/// };
97///
98/// assert_eq!(abort_message, abort_message3);
99/// assert_eq!(abort_message2, abort_message3);
100/// ```
101macro_rules! abort {
102 ($reason:expr) => {
103 abort! {$reason, serde_json::json!({})}
104 };
105
106 ($reason:expr, $details:expr) => {
107 Abort {
108 details: $details,
109 reason: $reason.to_string(),
110 }
111 };
112}
113
114impl WampMessage for Abort {
115 const ID: u64 = 3;
116
117 fn direction(role: crate::roles::Roles) -> &'static super::MessageDirection {
118 match role {
119 Roles::Callee => &MessageDirection {
120 receives: &true,
121 sends: &false,
122 },
123 Roles::Caller => &MessageDirection {
124 receives: &true,
125 sends: &false,
126 },
127 Roles::Publisher => &MessageDirection {
128 receives: &true,
129 sends: &false,
130 },
131 Roles::Subscriber => &MessageDirection {
132 receives: &true,
133 sends: &false,
134 },
135 Roles::Dealer => &MessageDirection {
136 receives: &false,
137 sends: &true,
138 },
139 Roles::Broker => &MessageDirection {
140 receives: &false,
141 sends: &true,
142 },
143 }
144 }
145}
146
147impl Serialize for Abort {
148 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: serde::Serializer,
151 {
152 let details =
153 helpers::ser_value_is_object::<S, _>(&self.details, "Details must be object like.")?;
154 (Self::ID, &details, &self.reason).serialize(serializer)
155 }
156}
157
158impl<'de> Deserialize<'de> for Abort {
159 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160 where
161 D: serde::Deserializer<'de>,
162 {
163 struct AbortVisitor(PhantomData<u8>, PhantomData<String>, PhantomData<Value>);
164
165 impl<'vi> Visitor<'vi> for AbortVisitor {
166 type Value = Abort;
167
168 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
169 formatter.write_str("WAMP Abort frame, expressed as a sequence.")
170 }
171
172 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
173 where
174 A: de::SeqAccess<'vi>,
175 {
176 let message_id: u64 =
177 helpers::deser_seq_element(&mut seq, "Message ID must be type u8.")?;
178 helpers::validate_id::<Abort, A, _>(&message_id, "Abort")?;
179 let details: Value =
180 helpers::deser_seq_element(&mut seq, "Details must be a JSON value.")?;
181 let reason: String =
182 helpers::deser_seq_element(&mut seq, "Reason must be a String.")?;
183 helpers::deser_value_is_object::<A, _>(&details, "Details must be object like.")?;
184 Ok(Abort { reason, details })
185 }
186 }
187
188 deserializer.deserialize_struct(
189 "Abort",
190 &["reason", "details"],
191 AbortVisitor(PhantomData, PhantomData, PhantomData),
192 )
193 }
194}