1use core::{fmt, str};
6
7use js_sys::{ArrayBuffer, Uint8Array};
8use wasm_bindgen::JsCast;
9use web_sys::{Blob, MessageEvent};
10
11use crate::WsErr;
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum WsMessage {
16 Text(String),
18
19 Binary(Vec<u8>),
21}
22
23impl WsMessage {
24 #[inline]
26 pub fn len(&self) -> usize {
27 match self {
28 Self::Text(string) => string.len(),
29 Self::Binary(data) => data.len(),
30 }
31 }
32
33 #[inline]
36 pub fn is_empty(&self) -> bool {
37 self.len() == 0
38 }
39
40 pub fn into_data(self) -> Vec<u8> {
42 match self {
43 Self::Text(string) => string.into_bytes(),
44 Self::Binary(data) => data,
45 }
46 }
47
48 pub fn to_text(&self) -> Result<&str, WsErr> {
51 match self {
52 Self::Text(string) => Ok(string),
53 Self::Binary(data) => Ok(str::from_utf8(data)?),
54 }
55 }
56}
57
58impl TryFrom<MessageEvent> for WsMessage {
62 type Error = WsErr;
63
64 fn try_from(evt: MessageEvent) -> Result<Self, Self::Error> {
65 match evt.data() {
66 d if d.is_instance_of::<ArrayBuffer>() => {
67 let buffy = Uint8Array::new(d.unchecked_ref());
68 let mut v = vec![0; buffy.length() as usize];
69
70 buffy.copy_to(&mut v); Ok(WsMessage::Binary(v))
73 }
74
75 d if d.is_string() => match d.as_string() {
83 Some(text) => Ok(WsMessage::Text(text)),
84 None => Err(WsErr::InvalidEncoding),
85 },
86
87 d if d.is_instance_of::<Blob>() => Err(WsErr::CantDecodeBlob),
90
91 _ => Err(WsErr::UnknownDataType),
93 }
94 }
95}
96
97impl From<WsMessage> for Vec<u8> {
98 fn from(msg: WsMessage) -> Self {
99 match msg {
100 WsMessage::Text(string) => string.into(),
101 WsMessage::Binary(vec) => vec,
102 }
103 }
104}
105
106impl From<Vec<u8>> for WsMessage {
107 fn from(vec: Vec<u8>) -> Self {
108 WsMessage::Binary(vec)
109 }
110}
111
112impl From<String> for WsMessage {
113 fn from(s: String) -> Self {
114 WsMessage::Text(s)
115 }
116}
117
118impl AsRef<[u8]> for WsMessage {
119 fn as_ref(&self) -> &[u8] {
120 match self {
121 WsMessage::Text(string) => string.as_ref(),
122 WsMessage::Binary(vec) => vec.as_ref(),
123 }
124 }
125}
126
127impl fmt::Display for WsMessage {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 if let Ok(string) = self.to_text() {
130 write!(f, "{string}")
131 } else {
132 write!(f, "Binary Data<length={}>", self.len())
133 }
134 }
135}