1use xso::{AsXml, FromXml};
8
9use crate::iq::{IqResultPayload, IqSetPayload};
10use crate::ns;
11use jid::{FullJid, Jid};
12
13#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
15#[xml(namespace = ns::BIND, name = "bind")]
16pub struct BindFeature {
17 #[xml(flag)]
19 required: bool,
20}
21
22#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
27#[xml(namespace = ns::BIND, name = "bind")]
28pub struct BindQuery {
29 #[xml(extract(default, fields(text(type_ = String))))]
34 resource: Option<String>,
35}
36
37impl BindQuery {
38 pub fn new(resource: Option<String>) -> BindQuery {
40 BindQuery { resource }
41 }
42}
43
44impl IqSetPayload for BindQuery {}
45
46#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
50#[xml(namespace = ns::BIND, name = "bind")]
51pub struct BindResponse {
52 #[xml(extract(fields(text(type_ = FullJid))))]
54 jid: FullJid,
55}
56
57impl IqResultPayload for BindResponse {}
58
59impl From<BindResponse> for FullJid {
60 fn from(bind: BindResponse) -> FullJid {
61 bind.jid
62 }
63}
64
65impl From<BindResponse> for Jid {
66 fn from(bind: BindResponse) -> Jid {
67 Jid::from(bind.jid)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use minidom::Element;
75 #[cfg(not(feature = "disable-validation"))]
76 use xso::error::{Error, FromElementError};
77
78 #[cfg(target_pointer_width = "32")]
79 #[test]
80 fn test_size() {
81 assert_size!(BindFeature, 1);
82 assert_size!(BindQuery, 12);
83 assert_size!(BindResponse, 16);
84 }
85
86 #[cfg(target_pointer_width = "64")]
87 #[test]
88 fn test_size() {
89 assert_size!(BindFeature, 1);
90 assert_size!(BindQuery, 24);
91 assert_size!(BindResponse, 32);
92 }
93
94 #[test]
95 fn test_simple() {
96 let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
97 .parse()
98 .unwrap();
99 let bind = BindQuery::try_from(elem).unwrap();
100 assert_eq!(bind.resource, None);
101
102 let elem: Element =
103 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>Hello™</resource></bind>"
104 .parse()
105 .unwrap();
106 let bind = BindQuery::try_from(elem).unwrap();
107 assert_eq!(bind.resource.unwrap(), "Hello™");
110
111 let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>coucou@linkmauve.fr/Hello™</jid></bind>"
112 .parse()
113 .unwrap();
114 let bind = BindResponse::try_from(elem).unwrap();
115 assert_eq!(
116 bind.jid,
117 FullJid::new("coucou@linkmauve.fr/HelloTM").unwrap()
118 );
119 }
120
121 #[cfg(not(feature = "disable-validation"))]
122 #[test]
123 fn test_invalid_resource() {
124 let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource attr='coucou'>resource</resource></bind>"
125 .parse()
126 .unwrap();
127 let error = BindQuery::try_from(elem).unwrap_err();
128 let message = match error {
129 FromElementError::Invalid(Error::Other(string)) => string,
130 _ => panic!(),
131 };
132 assert_eq!(
133 message,
134 "Unknown attribute in extraction for field 'resource' in BindQuery element."
135 );
136
137 let elem: Element = "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource><hello-world/>resource</resource></bind>"
138 .parse()
139 .unwrap();
140 let error = BindQuery::try_from(elem).unwrap_err();
141 let message = match error {
142 FromElementError::Invalid(Error::Other(string)) => string,
143 _ => panic!(),
144 };
145 assert_eq!(
146 message,
147 "Unknown child in extraction for field 'resource' in BindQuery element."
148 );
149 }
150}