jingle: Wrap all supported and unknown transports in an enum.

Emmanuel Gil Peyrot created

Change summary

src/jingle.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 82 insertions(+), 7 deletions(-)

Detailed changes

src/jingle.rs 🔗

@@ -6,6 +6,9 @@
 
 use crate::util::error::Error;
 use crate::iq::IqSetPayload;
+use crate::jingle_ice_udp::Transport as IceUdpTransport;
+use crate::jingle_ibb::Transport as IbbTransport;
+use crate::jingle_s5b::Transport as Socks5Transport;
 use crate::ns;
 use jid::Jid;
 use crate::Element;
@@ -164,6 +167,78 @@ generate_id!(
     ContentId
 );
 
+/// Enum wrapping all of the various supported transports of a Content.
+#[derive(Debug, Clone)]
+pub enum Transport {
+    /// Jingle ICE-UDP Bytestreams (XEP-0176) transport.
+    IceUdp(IceUdpTransport),
+
+    /// Jingle In-Band Bytestreams (XEP-0261) transport.
+    Ibb(IbbTransport),
+
+    /// Jingle SOCKS5 Bytestreams (XEP-0260) transport.
+    Socks5(Socks5Transport),
+
+    /// To be used for any transport that isn’t known at compile-time.
+    Unknown(Element),
+}
+
+impl TryFrom<Element> for Transport {
+    type Error = Error;
+
+    fn try_from(elem: Element) -> Result<Transport, Error> {
+        Ok(if elem.is("transport", ns::JINGLE_ICE_UDP) {
+            Transport::IceUdp(IceUdpTransport::try_from(elem)?)
+        } else if elem.is("transport", ns::JINGLE_IBB) {
+            Transport::Ibb(IbbTransport::try_from(elem)?)
+        } else if elem.is("transport", ns::JINGLE_S5B) {
+            Transport::Socks5(Socks5Transport::try_from(elem)?)
+        } else {
+            Transport::Unknown(elem)
+        })
+    }
+}
+
+impl From<IceUdpTransport> for Transport {
+    fn from(transport: IceUdpTransport) -> Transport {
+        Transport::IceUdp(transport)
+    }
+}
+
+impl From<IbbTransport> for Transport {
+    fn from(transport: IbbTransport) -> Transport {
+        Transport::Ibb(transport)
+    }
+}
+
+impl From<Socks5Transport> for Transport {
+    fn from(transport: Socks5Transport) -> Transport {
+        Transport::Socks5(transport)
+    }
+}
+
+impl From<Transport> for Element {
+    fn from(transport: Transport) -> Element {
+        match transport {
+            Transport::IceUdp(transport) => transport.into(),
+            Transport::Ibb(transport) => transport.into(),
+            Transport::Socks5(transport) => transport.into(),
+            Transport::Unknown(elem) => elem,
+        }
+    }
+}
+
+impl Transport {
+    fn get_ns(&self) -> String {
+        match self {
+            Transport::IceUdp(_) => String::from(ns::JINGLE_ICE_UDP),
+            Transport::Ibb(_) => String::from(ns::JINGLE_IBB),
+            Transport::Socks5(_) => String::from(ns::JINGLE_S5B),
+            Transport::Unknown(elem) => elem.ns().unwrap_or_else(|| String::new()),
+        }
+    }
+}
+
 generate_element!(
     /// Describes a session’s content, there can be multiple content in one
     /// session.
@@ -186,7 +261,7 @@ generate_element!(
         description: Option<Element> = ("description", JINGLE) => Element,
 
         /// How to send it.
-        transport: Option<Element> = ("transport", JINGLE) => Element,
+        transport: Option<Transport> = ("transport", *) => Transport,
 
         /// With which security.
         security: Option<Element> = ("security", JINGLE) => Element
@@ -226,8 +301,8 @@ impl Content {
     }
 
     /// Set the transport of this content.
-    pub fn with_transport(mut self, transport: Element) -> Content {
-        self.transport = Some(transport);
+    pub fn with_transport<T: Into<Transport>>(mut self, transport: T) -> Content {
+        self.transport = Some(transport.into());
         self
     }
 
@@ -575,7 +650,7 @@ mod tests {
         assert_size!(Senders, 1);
         assert_size!(Disposition, 1);
         assert_size!(ContentId, 24);
-        assert_size!(Content, 344);
+        assert_size!(Content, 384);
         assert_size!(Reason, 1);
         assert_size!(ReasonElement, 32);
         assert_size!(SessionId, 24);
@@ -626,18 +701,18 @@ mod tests {
 
     #[test]
     fn test_content() {
-        let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou'><description/><transport/></content></jingle>".parse().unwrap();
+        let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou'><description/><transport xmlns='urn:xmpp:jingle:transports:stub:0'/></content></jingle>".parse().unwrap();
         let jingle = Jingle::try_from(elem).unwrap();
         assert_eq!(jingle.contents[0].creator, Creator::Initiator);
         assert_eq!(jingle.contents[0].name, ContentId(String::from("coucou")));
         assert_eq!(jingle.contents[0].senders, Senders::Both);
         assert_eq!(jingle.contents[0].disposition, Disposition::Session);
 
-        let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' senders='both'><description/><transport/></content></jingle>".parse().unwrap();
+        let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' senders='both'><description/><transport xmlns='urn:xmpp:jingle:transports:stub:0'/></content></jingle>".parse().unwrap();
         let jingle = Jingle::try_from(elem).unwrap();
         assert_eq!(jingle.contents[0].senders, Senders::Both);
 
-        let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' disposition='early-session'><description/><transport/></content></jingle>".parse().unwrap();
+        let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' disposition='early-session'><description/><transport xmlns='urn:xmpp:jingle:transports:stub:0'/></content></jingle>".parse().unwrap();
         let jingle = Jingle::try_from(elem).unwrap();
         assert_eq!(jingle.contents[0].disposition, Disposition::EarlySession);
     }