Add a generate_attribute! macro, and use it for the common case.

This commit is contained in:
Emmanuel Gil Peyrot 2017-06-14 00:50:57 +01:00
commit 0f297d2d2d
10 changed files with 158 additions and 499 deletions

View file

@ -14,19 +14,18 @@ use ns;
use media_element::MediaElement; use media_element::MediaElement;
#[derive(Debug, Clone, PartialEq)] generate_attribute!(FieldType, "type", {
pub enum FieldType { Boolean => "boolean",
Boolean, Fixed => "fixed",
Fixed, Hidden => "hidden",
Hidden, JidMulti => "jid-multi",
JidMulti, JidSingle => "jid-single",
JidSingle, ListMulti => "list-multi",
ListMulti, ListSingle => "list-single",
ListSingle, TextMulti => "text-multi",
TextMulti, TextPrivate => "text-private",
TextPrivate, TextSingle => "text-single",
TextSingle, });
}
impl Default for FieldType { impl Default for FieldType {
fn default() -> FieldType { fn default() -> FieldType {
@ -34,44 +33,6 @@ impl Default for FieldType {
} }
} }
impl FromStr for FieldType {
type Err = Error;
fn from_str(s: &str) -> Result<FieldType, Error> {
Ok(match s {
"boolean" => FieldType::Boolean,
"fixed" => FieldType::Fixed,
"hidden" => FieldType::Hidden,
"jid-multi" => FieldType::JidMulti,
"jid-single" => FieldType::JidSingle,
"list-multi" => FieldType::ListMulti,
"list-single" => FieldType::ListSingle,
"text-multi" => FieldType::TextMulti,
"text-private" => FieldType::TextPrivate,
"text-single" => FieldType::TextSingle,
_ => return Err(Error::ParseError("Invalid 'type' attribute in field element.")),
})
}
}
impl IntoAttributeValue for FieldType {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
FieldType::Boolean => "boolean",
FieldType::Fixed => "fixed",
FieldType::Hidden => "hidden",
FieldType::JidMulti => "jid-multi",
FieldType::JidSingle => "jid-single",
FieldType::ListMulti => "list-multi",
FieldType::ListSingle => "list-single",
FieldType::TextMulti => "text-multi",
FieldType::TextPrivate => "text-private",
FieldType::TextSingle => "text-single",
}))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Option_ { pub struct Option_ {
pub label: Option<String>, pub label: Option<String>,
@ -131,39 +92,12 @@ impl IntoElements for Field {
} }
} }
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Subscription, "subscription", {
pub enum DataFormType { Cancel => "cancel",
Cancel, Form => "form",
Form, Result_ => "result",
Result_, Submit => "submit",
Submit, });
}
impl FromStr for DataFormType {
type Err = Error;
fn from_str(s: &str) -> Result<DataFormType, Error> {
Ok(match s {
"cancel" => DataFormType::Cancel,
"form" => DataFormType::Form,
"result" => DataFormType::Result_,
"submit" => DataFormType::Submit,
_ => return Err(Error::ParseError("Unknown data form type.")),
})
}
}
impl IntoAttributeValue for DataFormType {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
DataFormType::Cancel => "cancel",
DataFormType::Form => "form",
DataFormType::Result_ => "result",
DataFormType::Submit => "submit",
}))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DataForm { pub struct DataForm {

View file

@ -14,39 +14,10 @@ use error::Error;
use ns; use ns;
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Stanza, "stanza", {
pub enum Stanza { Iq => "iq",
Iq, Message => "message",
Message, }, Default = Iq);
}
impl Default for Stanza {
fn default() -> Stanza {
Stanza::Iq
}
}
impl FromStr for Stanza {
type Err = Error;
fn from_str(s: &str) -> Result<Stanza, Error> {
Ok(match s {
"iq" => Stanza::Iq,
"message" => Stanza::Message,
_ => return Err(Error::ParseError("Invalid 'stanza' attribute.")),
})
}
}
impl IntoAttributeValue for Stanza {
fn into_attribute_value(self) -> Option<String> {
match self {
Stanza::Iq => None,
Stanza::Message => Some(String::from("message")),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum IBB { pub enum IBB {

View file

@ -13,108 +13,35 @@ use jid::Jid;
use error::Error; use error::Error;
use ns; use ns;
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Action, "action", {
pub enum Action { ContentAccept => "content-accept",
ContentAccept, ContentAdd => "content-add",
ContentAdd, ContentModify => "content-modify",
ContentModify, ContentReject => "content-reject",
ContentReject, ContentRemove => "content-remove",
ContentRemove, DescriptionInfo => "description-info",
DescriptionInfo, SecurityInfo => "security-info",
SecurityInfo, SessionAccept => "session-accept",
SessionAccept, SessionInfo => "session-info",
SessionInfo, SessionInitiate => "session-initiate",
SessionInitiate, SessionTerminate => "session-terminate",
SessionTerminate, TransportAccept => "transport-accept",
TransportAccept, TransportInfo => "transport-info",
TransportInfo, TransportReject => "transport-reject",
TransportReject, TransportReplace => "transport-replace",
TransportReplace, });
}
impl FromStr for Action { generate_attribute!(Creator, "creator", {
type Err = Error; Initiator => "initiator",
Responder => "responder",
});
fn from_str(s: &str) -> Result<Action, Error> { generate_attribute!(Senders, "senders", {
Ok(match s { Both => "both",
"content-accept" => Action::ContentAccept, Initiator => "initiator",
"content-add" => Action::ContentAdd, None => "none",
"content-modify" => Action::ContentModify, Responder => "responder",
"content-reject" => Action::ContentReject, });
"content-remove" => Action::ContentRemove,
"description-info" => Action::DescriptionInfo,
"security-info" => Action::SecurityInfo,
"session-accept" => Action::SessionAccept,
"session-info" => Action::SessionInfo,
"session-initiate" => Action::SessionInitiate,
"session-terminate" => Action::SessionTerminate,
"transport-accept" => Action::TransportAccept,
"transport-info" => Action::TransportInfo,
"transport-reject" => Action::TransportReject,
"transport-replace" => Action::TransportReplace,
_ => return Err(Error::ParseError("Unknown action.")),
})
}
}
impl IntoAttributeValue for Action {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
Action::ContentAccept => "content-accept",
Action::ContentAdd => "content-add",
Action::ContentModify => "content-modify",
Action::ContentReject => "content-reject",
Action::ContentRemove => "content-remove",
Action::DescriptionInfo => "description-info",
Action::SecurityInfo => "security-info",
Action::SessionAccept => "session-accept",
Action::SessionInfo => "session-info",
Action::SessionInitiate => "session-initiate",
Action::SessionTerminate => "session-terminate",
Action::TransportAccept => "transport-accept",
Action::TransportInfo => "transport-info",
Action::TransportReject => "transport-reject",
Action::TransportReplace => "transport-replace",
}))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Creator {
Initiator,
Responder,
}
impl FromStr for Creator {
type Err = Error;
fn from_str(s: &str) -> Result<Creator, Error> {
Ok(match s {
"initiator" => Creator::Initiator,
"responder" => Creator::Responder,
_ => return Err(Error::ParseError("Unknown creator.")),
})
}
}
impl IntoAttributeValue for Creator {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
Creator::Initiator => "initiator",
Creator::Responder => "responder",
}))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Senders {
Both,
Initiator,
None_,
Responder,
}
impl Default for Senders { impl Default for Senders {
fn default() -> Senders { fn default() -> Senders {
@ -122,32 +49,6 @@ impl Default for Senders {
} }
} }
impl FromStr for Senders {
type Err = Error;
fn from_str(s: &str) -> Result<Senders, Error> {
Ok(match s {
"both" => Senders::Both,
"initiator" => Senders::Initiator,
"none" => Senders::None_,
"responder" => Senders::Responder,
_ => return Err(Error::ParseError("Unknown senders.")),
})
}
}
impl IntoAttributeValue for Senders {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
Senders::Both => "both",
Senders::Initiator => "initiator",
Senders::None_ => "none",
Senders::Responder => "responder",
}))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Content { pub struct Content {
pub creator: Creator, pub creator: Creator,
@ -448,7 +349,7 @@ mod tests {
Error::ParseError(string) => string, Error::ParseError(string) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown action."); assert_eq!(message, "Unknown value for 'action' attribute.");
} }
#[test] #[test]
@ -493,7 +394,7 @@ mod tests {
Error::ParseError(string) => string, Error::ParseError(string) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown creator."); assert_eq!(message, "Unknown value for 'creator' attribute.");
let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' senders='coucou'/></jingle>".parse().unwrap(); let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' senders='coucou'/></jingle>".parse().unwrap();
let error = Jingle::try_from(elem).unwrap_err(); let error = Jingle::try_from(elem).unwrap_err();
@ -501,7 +402,7 @@ mod tests {
Error::ParseError(string) => string, Error::ParseError(string) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown senders."); assert_eq!(message, "Unknown value for 'senders' attribute.");
let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' senders=''/></jingle>".parse().unwrap(); let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><content creator='initiator' name='coucou' senders=''/></jingle>".parse().unwrap();
let error = Jingle::try_from(elem).unwrap_err(); let error = Jingle::try_from(elem).unwrap_err();
@ -509,7 +410,7 @@ mod tests {
Error::ParseError(string) => string, Error::ParseError(string) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown senders."); assert_eq!(message, "Unknown value for 'senders' attribute.");
} }
#[test] #[test]

View file

@ -13,45 +13,12 @@ use error::Error;
use ns; use ns;
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Type, "type", {
pub enum Type { Assisted => "assisted",
Assisted, Direct => "direct",
Direct, Proxy => "proxy",
Proxy, Tunnel => "tunnel",
Tunnel, }, Default = Direct);
}
impl Default for Type {
fn default() -> Type {
Type::Direct
}
}
impl FromStr for Type {
type Err = Error;
fn from_str(s: &str) -> Result<Type, Error> {
Ok(match s {
"assisted" => Type::Assisted,
"direct" => Type::Direct,
"proxy" => Type::Proxy,
"tunnel" => Type::Tunnel,
_ => return Err(Error::ParseError("Invalid 'type' attribute in candidate element.")),
})
}
}
impl IntoAttributeValue for Type {
fn into_attribute_value(self) -> Option<String> {
Some(match self {
Type::Assisted => String::from("assisted"),
Type::Direct => return None,
Type::Proxy => String::from("proxy"),
Type::Tunnel => String::from("tunnel"),
})
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Candidate { pub struct Candidate {
@ -77,39 +44,10 @@ impl Into<Element> for Candidate {
} }
} }
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Mode, "mode", {
pub enum Mode { Tcp => "tcp",
Tcp, Udp => "udp",
Udp, }, Default = Tcp);
}
impl Default for Mode {
fn default() -> Mode {
Mode::Tcp
}
}
impl FromStr for Mode {
type Err = Error;
fn from_str(s: &str) -> Result<Mode, Error> {
Ok(match s {
"tcp" => Mode::Tcp,
"udp" => Mode::Udp,
_ => return Err(Error::ParseError("Invalid 'mode' attribute.")),
})
}
}
impl IntoAttributeValue for Mode {
fn into_attribute_value(self) -> Option<String> {
match self {
Mode::Tcp => None,
Mode::Udp => Some(String::from("udp")),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum TransportPayload { pub enum TransportPayload {

View file

@ -49,6 +49,66 @@ macro_rules! get_attr {
); );
} }
macro_rules! generate_attribute {
($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}) => (
generate_attribute!($elem, $name, {$($a => $b),+});
);
($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}, Default = $default:ident) => (
generate_attribute!($elem, $name, {$($a => $b),+}, Default = $default);
);
($elem:ident, $name:tt, {$($a:ident => $b:tt),+}) => (
#[derive(Debug, Clone, PartialEq)]
pub enum $elem {
$($a),+
}
impl FromStr for $elem {
type Err = Error;
fn from_str(s: &str) -> Result<$elem, Error> {
Ok(match s {
$($b => $elem::$a),+,
_ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
})
}
}
impl IntoAttributeValue for $elem {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
$($elem::$a => $b),+
}))
}
}
);
($elem:ident, $name:tt, {$($a:ident => $b:tt),+}, Default = $default:ident) => (
#[derive(Debug, Clone, PartialEq)]
pub enum $elem {
$($a),+
}
impl FromStr for $elem {
type Err = Error;
fn from_str(s: &str) -> Result<$elem, Error> {
Ok(match s {
$($b => $elem::$a),+,
_ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
})
}
}
impl IntoAttributeValue for $elem {
#[allow(unreachable_patterns)]
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
$elem::$default => return None,
$($elem::$a => $b),+
}))
}
}
impl Default for $elem {
fn default() -> $elem {
$elem::$default
}
}
);
}
/// Error type returned by every parser on failure. /// Error type returned by every parser on failure.
pub mod error; pub mod error;
/// XML namespace definitions used through XMPP. /// XML namespace definitions used through XMPP.

View file

@ -39,36 +39,11 @@ pub struct Fin {
pub set: Set, pub set: Set,
} }
#[derive(Debug, Clone)] generate_attribute!(DefaultPrefs, "default", {
pub enum DefaultPrefs { Always => "always",
Always, Never => "never",
Never, Roster => "roster",
Roster, });
}
impl FromStr for DefaultPrefs {
type Err = Error;
fn from_str(s: &str) -> Result<DefaultPrefs, Error> {
Ok(match s {
"always" => DefaultPrefs::Always,
"never" => DefaultPrefs::Never,
"roster" => DefaultPrefs::Roster,
_ => return Err(Error::ParseError("Invalid 'default' attribute.")),
})
}
}
impl IntoAttributeValue for DefaultPrefs {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
DefaultPrefs::Always => "always",
DefaultPrefs::Never => "never",
DefaultPrefs::Roster => "roster",
}))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Prefs { pub struct Prefs {

View file

@ -102,14 +102,13 @@ impl Into<Element> for MessagePayload {
} }
} }
#[derive(Debug, Clone, PartialEq)] generate_attribute!(MessageType, "type", {
pub enum MessageType { Chat => "chat",
Chat, Error => "error",
Error, Groupchat => "groupchat",
Groupchat, Headline => "headline",
Headline, Normal => "normal",
Normal, });
}
impl Default for MessageType { impl Default for MessageType {
fn default() -> MessageType { fn default() -> MessageType {
@ -117,34 +116,6 @@ impl Default for MessageType {
} }
} }
impl FromStr for MessageType {
type Err = Error;
fn from_str(s: &str) -> Result<MessageType, Error> {
Ok(match s {
"chat" => MessageType::Chat,
"error" => MessageType::Error,
"groupchat" => MessageType::Groupchat,
"headline" => MessageType::Headline,
"normal" => MessageType::Normal,
_ => return Err(Error::ParseError("Invalid 'type' attribute on message element.")),
})
}
}
impl IntoAttributeValue for MessageType {
fn into_attribute_value(self) -> Option<String> {
Some(match self {
MessageType::Chat => "chat",
MessageType::Error => "error",
MessageType::Groupchat => "groupchat",
MessageType::Headline => "headline",
MessageType::Normal => "normal",
}.to_owned())
}
}
type Lang = String; type Lang = String;
type Body = String; type Body = String;
type Subject = String; type Subject = String;

View file

@ -43,45 +43,12 @@ impl IntoElements for Item {
} }
} }
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Subscription, "subscription", {
pub enum Subscription { None => "none",
None, Pending => "pending",
Pending, Subscribed => "subscribed",
Subscribed, Unconfigured => "unconfigured",
Unconfigured, }, Default = None);
}
impl Default for Subscription {
fn default() -> Subscription {
Subscription::None
}
}
impl FromStr for Subscription {
type Err = Error;
fn from_str(s: &str) -> Result<Subscription, Error> {
Ok(match s {
"none" => Subscription::None,
"pending" => Subscription::Pending,
"subscribed" => Subscription::Subscribed,
"unconfigured" => Subscription::Unconfigured,
_ => return Err(Error::ParseError("Invalid 'subscription' attribute.")),
})
}
}
impl IntoAttributeValue for Subscription {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
Subscription::None => return None,
Subscription::Pending => "pending",
Subscription::Subscribed => "subscribed",
Subscription::Unconfigured => "unconfigured",
}))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum PubSubEvent { pub enum PubSubEvent {

View file

@ -15,42 +15,13 @@ use ns;
type Group = String; type Group = String;
#[derive(Debug, Clone, PartialEq)] generate_attribute!(Subscription, "subscription", {
pub enum Subscription { None => "none",
None, From => "from",
From, To => "to",
To, Both => "both",
Both, Remove => "remove",
Remove, });
}
impl FromStr for Subscription {
type Err = Error;
fn from_str(s: &str) -> Result<Subscription, Error> {
Ok(match s {
"none" => Subscription::None,
"from" => Subscription::From,
"to" => Subscription::To,
"both" => Subscription::Both,
"remove" => Subscription::Remove,
_ => return Err(Error::ParseError("Unknown value for attribute 'subscription'.")),
})
}
}
impl IntoAttributeValue for Subscription {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
Subscription::None => "none",
Subscription::From => "from",
Subscription::To => "to",
Subscription::Both => "both",
Subscription::Remove => "remove",
}))
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Item { pub struct Item {

View file

@ -14,42 +14,13 @@ use error::Error;
use jid::Jid; use jid::Jid;
use ns; use ns;
#[derive(Debug, Clone, PartialEq)] generate_attribute!(ErrorType, "type", {
pub enum ErrorType { Auth => "auth",
Auth, Cancel => "cancel",
Cancel, Continue => "continue",
Continue, Modify => "modify",
Modify, Wait => "wait",
Wait, });
}
impl FromStr for ErrorType {
type Err = Error;
fn from_str(s: &str) -> Result<ErrorType, Error> {
Ok(match s {
"auth" => ErrorType::Auth,
"cancel" => ErrorType::Cancel,
"continue" => ErrorType::Continue,
"modify" => ErrorType::Modify,
"wait" => ErrorType::Wait,
_ => return Err(Error::ParseError("Unknown error type.")),
})
}
}
impl IntoAttributeValue for ErrorType {
fn into_attribute_value(self) -> Option<String> {
Some(String::from(match self {
ErrorType::Auth => "auth",
ErrorType::Cancel => "cancel",
ErrorType::Continue => "continue",
ErrorType::Modify => "modify",
ErrorType::Wait => "wait",
}))
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum DefinedCondition { pub enum DefinedCondition {
@ -252,7 +223,7 @@ mod tests {
Error::ParseError(string) => string, Error::ParseError(string) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown error type."); assert_eq!(message, "Unknown value for 'type' attribute.");
} }
#[test] #[test]