Skip to main content

actioncable/
message.rs

1use std::fmt;
2
3use serde::de::DeserializeOwned;
4use serde_json::Value;
5
6use crate::error::Error;
7
8/// The undecoded payload a channel broadcast or transmitted, exactly as it came off the
9/// wire. Its shape is entirely up to the channel, so [`decode`](Message::decode) it into
10/// the type you expect.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct Message {
13    json: String,
14}
15
16impl Message {
17    /// Wraps JSON text without checking it. For protocol implementations, which have
18    /// already parsed the frame around it.
19    pub fn from_json(json: impl Into<String>) -> Message {
20        Message { json: json.into() }
21    }
22
23    /// Decodes the payload into the type the channel sends.
24    pub fn decode<T: DeserializeOwned>(&self) -> Result<T, Error> {
25        Ok(serde_json::from_str(&self.json)?)
26    }
27
28    /// Decodes the payload into a [`serde_json::Value`], for a shape known at runtime.
29    pub fn to_value(&self) -> Result<Value, Error> {
30        self.decode()
31    }
32
33    /// The payload's JSON text, as it came off the wire.
34    pub fn as_str(&self) -> &str {
35        &self.json
36    }
37}
38
39impl fmt::Display for Message {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        f.write_str(&self.json)
42    }
43}
44
45#[cfg(test)]
46#[allow(
47    clippy::unwrap_used,
48    clippy::expect_used,
49    reason = "a test that can't have what it asked for has nothing left to assert"
50)]
51mod tests {
52    use serde::Deserialize;
53
54    use super::*;
55
56    #[derive(Debug, PartialEq, Deserialize)]
57    struct Said {
58        body: String,
59    }
60
61    #[test]
62    fn a_message_decodes_into_the_callers_type() {
63        let message = Message::from_json(r#"{"body":"Hello!"}"#);
64
65        let said: Said = message.decode().unwrap();
66
67        assert_eq!("Hello!", said.body);
68        assert_eq!(r#"{"body":"Hello!"}"#, message.to_string());
69        assert!(matches!(
70            Message::from_json("not json").decode::<Said>(),
71            Err(Error::Json(_))
72        ));
73    }
74}