1use std::{fmt, str};
5
6#[cfg(not(target_arch = "wasm32"))]
7use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode;
8#[cfg(not(target_arch = "wasm32"))]
9use tokio_tungstenite::tungstenite::protocol::CloseFrame as TungsteniteCloseFrame;
10#[cfg(not(target_arch = "wasm32"))]
11use tokio_tungstenite::tungstenite::protocol::Message as TungsteniteMessage;
12
13#[cfg(not(target_arch = "wasm32"))]
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct CloseFrame {
16 pub code: u16,
18 pub reason: String,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub enum Message {
25 Text(String),
27 Binary(Vec<u8>),
29 #[cfg(not(target_arch = "wasm32"))]
33 Ping(Vec<u8>),
34 #[cfg(not(target_arch = "wasm32"))]
38 Pong(Vec<u8>),
39 #[cfg(not(target_arch = "wasm32"))]
41 Close(Option<CloseFrame>),
42}
43
44impl Message {
45 #[cfg(not(target_arch = "wasm32"))]
46 pub(crate) fn from_native(msg: TungsteniteMessage) -> Self {
47 match msg {
48 TungsteniteMessage::Text(text) => Self::Text(text.to_string()),
49 TungsteniteMessage::Binary(data) => Self::Binary(data.to_vec()),
50 TungsteniteMessage::Ping(data) => Self::Ping(data.to_vec()),
51 TungsteniteMessage::Pong(data) => Self::Pong(data.to_vec()),
52 TungsteniteMessage::Close(frame) => Self::Close(frame.map(|f| f.into())),
53 TungsteniteMessage::Frame(..) => unreachable!(),
56 }
57 }
58
59 #[inline]
61 pub fn len(&self) -> usize {
62 match self {
63 Self::Text(string) => string.len(),
64 Self::Binary(data) => data.len(),
65 #[cfg(not(target_arch = "wasm32"))]
66 Self::Ping(data) => data.len(),
67 #[cfg(not(target_arch = "wasm32"))]
68 Self::Pong(data) => data.len(),
69 #[cfg(not(target_arch = "wasm32"))]
70 Self::Close(data) => data.as_ref().map(|d| d.reason.len()).unwrap_or(0),
71 }
72 }
73
74 #[inline]
75 pub fn is_empty(&self) -> bool {
76 self.len() == 0
77 }
78
79 pub fn as_text(&self) -> Option<&str> {
82 match self {
83 Self::Text(string) => Some(string.as_str()),
84 Self::Binary(data) => str::from_utf8(data).ok(),
85 #[cfg(not(target_arch = "wasm32"))]
86 Self::Ping(data) | Self::Pong(data) => str::from_utf8(data).ok(),
87 #[cfg(not(target_arch = "wasm32"))]
88 Self::Close(None) => Some(""),
89 #[cfg(not(target_arch = "wasm32"))]
90 Self::Close(Some(frame)) => Some(&frame.reason),
91 }
92 }
93}
94
95impl fmt::Display for Message {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 if let Some(string) = self.as_text() {
98 write!(f, "{string}")
99 } else {
100 write!(f, "Binary Data<length={}>", self.len())
101 }
102 }
103}
104
105#[cfg(not(target_arch = "wasm32"))]
106impl From<CloseFrame> for TungsteniteCloseFrame {
107 fn from(frame: CloseFrame) -> Self {
108 Self {
109 code: CloseCode::from(frame.code),
110 reason: frame.reason.into(),
111 }
112 }
113}
114
115#[cfg(not(target_arch = "wasm32"))]
116impl From<Message> for TungsteniteMessage {
117 fn from(msg: Message) -> Self {
118 match msg {
119 Message::Text(text) => Self::Text(text.into()),
120 Message::Binary(data) => Self::Binary(data.into()),
121 Message::Ping(data) => Self::Ping(data.into()),
122 Message::Pong(data) => Self::Pong(data.into()),
123 Message::Close(frame) => Self::Close(frame.map(|f| f.into())),
124 }
125 }
126}
127
128#[cfg(not(target_arch = "wasm32"))]
129impl From<TungsteniteCloseFrame> for CloseFrame {
130 fn from(frame: TungsteniteCloseFrame) -> Self {
131 Self {
132 code: frame.code.into(),
133 reason: frame.reason.to_string(),
134 }
135 }
136}