messagebird_async/sms/
payload.rs

1use super::*;
2
3use serde::de::{self, Deserialize, Deserializer, Unexpected, Visitor};
4use serde::ser::{Serialize, Serializer};
5
6use std::fmt;
7
8/// SMS encoding enum
9///
10/// Defines how to interpret the message encoding for text messages.
11/// For binary SMS see `PayloadType`
12#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
13#[serde(rename_all = "camelCase")]
14#[serde(rename = "encoding")]
15pub enum PayloadEncoding {
16    Plain,
17    Unicode,
18    Auto,
19}
20
21/// SMS message type enum
22///
23/// Determines the type of the message payload
24#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
25#[serde(rename_all = "lowercase")]
26pub enum PayloadType {
27    /// regular text SMS, encoding defined by `PayloadEncoding`
28    Sms,
29    /// raw binary encoding of bytes, some providers are incapable of handling those with their base stations, be warned
30    Binary,
31    /// priority notification style SMS, there is no guarantee that this is stored on the phone
32    Flash,
33}
34
35impl FromStr for PayloadType {
36    type Err = MessageBirdError;
37    fn from_str(s: &str) -> Result<Self, Self::Err> {
38        serde_plain::from_str::<Self>(s).map_err(|_e| MessageBirdError::ParseError)
39    }
40}
41
42impl ToString for PayloadType {
43    fn to_string(&self) -> String {
44        serde_plain::to_string(self).unwrap()
45    }
46}
47
48impl PayloadType {
49    pub fn as_str(&self) -> &str {
50        match self {
51            PayloadType::Sms => "sms",
52            PayloadType::Binary => "binary",
53            PayloadType::Flash => "flash",
54        }
55    }
56}
57
58/// Payload data
59///
60/// Enum representing both raw bytes/binary as well as text based sms messages.
61///
62/// Used for the sending direction.
63///
64/// `PayloadType` and `PayloadEncoding` are unrelated and used for querying.
65#[derive(Clone, Debug, Eq, PartialEq)]
66pub enum Payload {
67    Bytes(Vec<u8>),
68    Text(String),
69}
70
71impl Default for Payload {
72    fn default() -> Self {
73        Payload::Text("default".to_string())
74    }
75}
76
77// You can even choose to implement multiple traits, like Lower and UpperHex
78impl fmt::LowerHex for Payload {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        match self {
81            Payload::Bytes(ref bytes) => {
82                for byte in bytes {
83                    write!(f, "{:x} ", byte)?;
84                }
85            }
86            Payload::Text(ref s) => {
87                for byte in s.as_bytes() {
88                    write!(f, "{:x} ", byte)?;
89                }
90            }
91        }
92        Ok(())
93    }
94}
95
96impl FromStr for Payload {
97    type Err = MessageBirdError;
98
99    fn from_str(s: &str) -> Result<Self, Self::Err> {
100        Ok(Payload::Text(String::from(s)))
101    }
102}
103
104impl Serialize for Payload {
105    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
106    where
107        S: Serializer,
108    {
109        match self {
110            Payload::Bytes(_) => {
111                let data = format!("{:x}", self);
112                serializer.serialize_str(data.as_str())
113            }
114            Payload::Text(ref s) => serializer.serialize_str(s.as_str()),
115        }
116    }
117}
118
119struct PayloadVisitor;
120
121impl<'de> Visitor<'de> for PayloadVisitor {
122    type Value = Payload;
123
124    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
125        formatter.write_str("a valid payload, either string or binary")
126    }
127
128    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
129    where
130        E: de::Error,
131    {
132        // TODO this actually requires context
133        // TODO on how to parse the `value`
134        // TODO without the type it is impossible to decide
135        // TODO if i.e. 1234 is a Binary repr or a Text
136        Payload::from_str(value)
137            .map_err(|_e| de::Error::invalid_value(Unexpected::Str(value), &self))
138    }
139}
140
141impl<'de> Deserialize<'de> for Payload {
142    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
143    where
144        D: Deserializer<'de>,
145    {
146        deserializer.deserialize_str(PayloadVisitor)
147    }
148}
149
150#[cfg(test)]
151mod test {
152    use super::*;
153
154    static RAW: &str = r#"
155"16483910"
156"#;
157    deser_roundtrip!(payload_deser, Payload, RAW);
158    serde_roundtrip!(payload_serde, Payload, Payload::default());
159}