Skip to main content

phoenix_channel_runtime/
payload.rs

1use serde_json::Value;
2use thiserror::Error;
3
4/// Associates an application event name with its deserialized payload type.
5pub trait EventRoute {
6    /// Event name to match.
7    const EVENT: &'static str;
8    /// Payload type produced for a matching event.
9    type Output: serde::de::DeserializeOwned;
10}
11
12/// Payload carried by a Phoenix protocol frame.
13#[derive(Clone, Debug, PartialEq)]
14pub enum Payload {
15    /// An ordinary JSON payload.
16    Json(Value),
17    /// An opaque binary payload.
18    Binary(Vec<u8>),
19    /// The status and response object inside a `phx_reply` frame.
20    Reply {
21        /// Phoenix reply status string, normally `ok` or `error`.
22        status: String,
23        /// JSON or binary response returned by the server.
24        response: Box<Payload>,
25    },
26}
27
28impl Payload {
29    /// Borrows the JSON value when this is [`Payload::Json`].
30    pub fn as_json(&self) -> Option<&Value> {
31        match self {
32            Self::Json(value) => Some(value),
33            Self::Binary(_) | Self::Reply { .. } => None,
34        }
35    }
36
37    /// Borrows the bytes when this is [`Payload::Binary`].
38    pub fn as_binary(&self) -> Option<&[u8]> {
39        match self {
40            Self::Binary(value) => Some(value),
41            Self::Json(_) | Self::Reply { .. } => None,
42        }
43    }
44
45    /// Consumes this payload and returns its JSON value.
46    ///
47    /// Returns the original payload when it is not JSON.
48    pub fn into_json(self) -> Result<Value, Self> {
49        match self {
50            Self::Json(value) => Ok(value),
51            other => Err(other),
52        }
53    }
54
55    /// Consumes this payload and returns its binary bytes.
56    ///
57    /// Returns the original payload when it is not binary.
58    pub fn into_binary(self) -> Result<Vec<u8>, Self> {
59        match self {
60            Self::Binary(value) => Ok(value),
61            other => Err(other),
62        }
63    }
64
65    /// Deserializes a JSON payload into `T`.
66    pub fn deserialize<T: serde::de::DeserializeOwned>(&self) -> Result<T, PayloadError> {
67        let value = self.as_json().ok_or(PayloadError::ExpectedJson)?;
68        serde_json::from_value(value.clone()).map_err(PayloadError::Deserialize)
69    }
70}
71
72impl From<Value> for Payload {
73    fn from(value: Value) -> Self {
74        Self::Json(value)
75    }
76}
77
78impl From<Vec<u8>> for Payload {
79    fn from(value: Vec<u8>) -> Self {
80        Self::Binary(value)
81    }
82}
83
84impl PartialEq<Value> for Payload {
85    fn eq(&self, other: &Value) -> bool {
86        self.as_json() == Some(other)
87    }
88}
89
90/// Failure while reading a typed value from a [`Payload`].
91#[derive(Debug, Error)]
92pub enum PayloadError {
93    /// The payload was not JSON.
94    #[error("expected a JSON payload, received binary data")]
95    ExpectedJson,
96    /// The JSON payload could not be deserialized into the requested type.
97    #[error("failed to deserialize a JSON payload: {0}")]
98    Deserialize(#[source] serde_json::Error),
99}