1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use bytes::Bytes;
use serde_json::Value;

/// A type which represents a `payload` in the `socket.io` context.
/// The enum is used for both representing data that's send and
/// data that's received.
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum Payload {
    Binary(Bytes),
    Json(Value),
    Multi(Vec<RawPayload>),
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RawPayload {
    Binary(Bytes),
    Json(Value),
}

impl From<serde_json::Value> for Payload {
    fn from(value: serde_json::Value) -> Self {
        Self::Json(value)
    }
}

impl From<Option<serde_json::Value>> for Payload {
    fn from(value: Option<serde_json::Value>) -> Self {
        match value {
            None => Self::Json(Value::Null),
            Some(value) => Self::Json(value),
        }
    }
}

impl From<Vec<serde_json::Value>> for Payload {
    fn from(value: Vec<serde_json::Value>) -> Self {
        if value.len() == 1 {
            Self::Json(value.first().unwrap().to_owned())
        } else {
            Self::Multi(value.into_iter().map(|v| v.into()).collect())
        }
    }
}

impl From<Vec<u8>> for Payload {
    fn from(val: Vec<u8>) -> Self {
        Self::Binary(Bytes::from(val))
    }
}

impl From<&'static [u8]> for Payload {
    fn from(val: &'static [u8]) -> Self {
        Self::Binary(Bytes::from_static(val))
    }
}

impl From<Bytes> for Payload {
    fn from(bytes: Bytes) -> Self {
        Self::Binary(bytes)
    }
}

impl From<serde_json::Value> for RawPayload {
    fn from(value: serde_json::Value) -> Self {
        Self::Json(value)
    }
}

impl From<Vec<u8>> for RawPayload {
    fn from(val: Vec<u8>) -> Self {
        Self::Binary(Bytes::from(val))
    }
}

impl From<&'static [u8]> for RawPayload {
    fn from(val: &'static [u8]) -> Self {
        Self::Binary(Bytes::from_static(val))
    }
}

impl From<Bytes> for RawPayload {
    fn from(bytes: Bytes) -> Self {
        Self::Binary(bytes)
    }
}

impl From<RawPayload> for Payload {
    fn from(val: RawPayload) -> Self {
        match val {
            RawPayload::Json(data) => Payload::Json(data),
            RawPayload::Binary(bin) => Payload::Binary(bin),
        }
    }
}

#[cfg(test)]
mod tests {
    use serde_json::json;

    use super::*;

    #[test]
    fn test_from() {
        let sut = Payload::from(json!("foo ™"));
        assert_eq!(Payload::Json(json!("foo ™")), sut);

        let sut = Payload::from(vec![1, 2, 3]);
        assert_eq!(Payload::Binary(Bytes::from_static(&[1, 2, 3])), sut);

        let sut = Payload::from(&[1_u8, 2_u8, 3_u8][..]);
        assert_eq!(Payload::Binary(Bytes::from_static(&[1, 2, 3])), sut);

        let sut = Payload::from(Bytes::from_static(&[1, 2, 3]));
        assert_eq!(Payload::Binary(Bytes::from_static(&[1, 2, 3])), sut);

        let sut = Payload::from(json!(5));
        assert_eq!(Payload::Json(json!(5)), sut);

        let sut = Payload::from(json!("5"));
        assert_eq!(Payload::Json(json!("5")), sut);
    }
}