1
0
mirror of https://gitlab.com/xmpp-rs/xmpp-rs.git synced 2024-06-26 08:58:27 +02:00

macros: Use a nicer syntax when declaring attributes.

The previous version had a => required|optional|default token, this was
duplicating information for Option types and didn’t look very good.

This new version looks like a type, which can be either Required<_>,
Option<_> or Default<_>, and means the same thing.
This commit is contained in:
Emmanuel Gil Peyrot 2019-02-24 20:26:40 +01:00
parent f2c3f45a6f
commit bcd42a26e3
27 changed files with 162 additions and 137 deletions

View File

@ -24,22 +24,22 @@ generate_element!(
Info, "info", AVATAR_METADATA,
attributes: [
/// The size of the image data in bytes.
bytes: u16 = "bytes" => required,
bytes: Required<u16> = "bytes",
/// The width of the image in pixels.
width: Option<u8> = "width" => optional,
width: Option<u8> = "width",
/// The height of the image in pixels.
height: Option<u8> = "height" => optional,
height: Option<u8> = "height",
/// The SHA-1 hash of the image data for the specified content-type.
id: Sha1HexAttribute = "id" => required,
id: Required<Sha1HexAttribute> = "id",
/// The IANA-registered content type of the image data.
type_: String = "type" => required,
type_: Required<String> = "type",
/// The http: or https: URL at which the image data file is hosted.
url: Option<String> = "url" => optional,
url: Option<String> = "url",
]
);

View File

@ -18,13 +18,13 @@ generate_element!(
Conference, "conference", BOOKMARKS,
attributes: [
/// Whether a conference bookmark should be joined automatically.
autojoin: Autojoin = "autojoin" => default,
autojoin: Default<Autojoin> = "autojoin",
/// The JID of the conference.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// A user-defined name for this conference.
name: String = "name" => required
name: Required<String> = "name",
],
children: [
/// The nick the user will use to join this conference.
@ -40,10 +40,10 @@ generate_element!(
Url, "url", BOOKMARKS,
attributes: [
/// A user-defined name for this URL.
name: String = "name" => required,
name: Required<String> = "name",
/// The URL of this bookmark.
url: String = "url" => required
url: Required<String> = "url",
]
);

View File

@ -15,7 +15,7 @@ generate_element!(
Option_, "option", DATA_FORMS,
attributes: [
/// The optional label to be displayed to the user for this option.
label: Option<String> = "label" => optional
label: Option<String> = "label"
],
children: [
/// The value returned to the server when selecting this option.

View File

@ -15,10 +15,10 @@ generate_element!(
Delay, "delay", DELAY,
attributes: [
/// The entity which delayed this message.
from: Option<Jid> = "from" => optional,
from: Option<Jid> = "from",
/// The time at which this message got stored.
stamp: DateTime = "stamp" => required
stamp: Required<DateTime> = "stamp"
],
text: (
/// The optional reason this message got delayed.

View File

@ -20,7 +20,7 @@ generate_element!(
DiscoInfoQuery, "query", DISCO_INFO,
attributes: [
/// Node on which we are doing the discovery.
node: Option<String> = "node" => optional,
node: Option<String> = "node",
]);
impl IqGetPayload for DiscoInfoQuery {}
@ -31,7 +31,7 @@ generate_element!(
Feature, "feature", DISCO_INFO,
attributes: [
/// Namespace of the feature we want to represent.
var: String = "var" => required,
var: Required<String> = "var",
]);
impl Feature {
@ -206,7 +206,7 @@ generate_element!(
DiscoItemsQuery, "query", DISCO_ITEMS,
attributes: [
/// Node on which we are doing the discovery.
node: Option<String> = "node" => optional,
node: Option<String> = "node",
]);
impl IqGetPayload for DiscoItemsQuery {}
@ -216,11 +216,11 @@ generate_element!(
Item, "item", DISCO_ITEMS,
attributes: [
/// JID of the entity pointed by this item.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// Node of the entity pointed by this item.
node: Option<String> = "node" => optional,
node: Option<String> = "node",
/// Name of the entity pointed by this item.
name: Option<String> = "name" => optional,
name: Option<String> = "name",
]);
generate_element!(
@ -232,7 +232,7 @@ generate_element!(
DiscoItemsResult, "query", DISCO_ITEMS,
attributes: [
/// Node on which we have done this discovery.
node: Option<String> = "node" => optional
node: Option<String> = "node"
],
children: [
/// List of items pointed by this entity.

View File

@ -11,11 +11,11 @@ generate_element!(
ExplicitMessageEncryption, "encryption", EME,
attributes: [
/// Namespace of the encryption scheme used.
namespace: String = "namespace" => required,
namespace: Required<String> = "namespace",
/// User-friendly name for the encryption scheme, should be `None` for OTR,
/// legacy OpenPGP and OX.
name: Option<String> = "name" => optional,
name: Option<String> = "name",
]
);

View File

@ -102,7 +102,7 @@ generate_element!(
Hash, "hash", HASHES,
attributes: [
/// The algorithm used to create this hash.
algo: Algo = "algo" => required
algo: Required<Algo> = "algo"
],
text: (
/// The hash value, as a vector of bytes.

View File

@ -30,13 +30,13 @@ generate_element!(
Open, "open", IBB,
attributes: [
/// Maximum size in bytes for each chunk.
block_size: u16 = "block-size" => required,
block_size: Required<u16> = "block-size",
/// The identifier to be used to create a stream.
sid: StreamId = "sid" => required,
sid: Required<StreamId> = "sid",
/// Which stanza type to use to exchange data.
stanza: Stanza = "stanza" => default,
stanza: Default<Stanza> = "stanza",
]);
impl IqSetPayload for Open {}
@ -46,10 +46,10 @@ generate_element!(
Data, "data", IBB,
attributes: [
/// Sequence number of this chunk, must wraparound after 65535.
seq: u16 = "seq" => required,
seq: Required<u16> = "seq",
/// The identifier of the stream on which data is being exchanged.
sid: StreamId = "sid" => required
sid: Required<StreamId> = "sid"
],
text: (
/// Vector of bytes to be exchanged.
@ -64,7 +64,7 @@ generate_element!(
Close, "close", IBB,
attributes: [
/// The identifier of the stream to be closed.
sid: StreamId = "sid" => required,
sid: Required<StreamId> = "sid",
]);
impl IqSetPayload for Close {}

View File

@ -12,7 +12,7 @@ generate_element!(
Idle, "idle", IDLE,
attributes: [
/// The time at which the user stopped interacting.
since: DateTime = "since" => required,
since: Required<DateTime> = "since",
]
);

View File

@ -169,16 +169,16 @@ generate_element!(
Content, "content", JINGLE,
attributes: [
/// Who created this content.
creator: Creator = "creator" => required,
creator: Required<Creator> = "creator",
/// How the content definition is to be interpreted by the recipient.
disposition: Disposition = "disposition" => default,
disposition: Default<Disposition> = "disposition",
/// A per-session unique identifier for this content.
name: ContentId = "name" => required,
name: Required<ContentId> = "name",
/// Who can send data for this content.
senders: Senders = "senders" => default
senders: Default<Senders> = "senders",
],
children: [
/// What to send.

View File

@ -20,11 +20,11 @@ generate_element!(
Range, "range", JINGLE_FT,
attributes: [
/// The offset in bytes from the beginning of the file.
offset: u64 = "offset" => default,
offset: Default<u64> = "offset",
/// The length in bytes of the range, or None to be the entire
/// remaining of the file.
length: Option<u64> = "length" => optional
length: Option<u64> = "length"
],
children: [
/// List of hashes for this range.
@ -344,10 +344,10 @@ generate_element!(
Received, "received", JINGLE_FT,
attributes: [
/// The content identifier of this Jingle session.
name: ContentId = "name" => required,
name: Required<ContentId> = "name",
/// The creator of this file transfer.
creator: Creator = "creator" => required,
creator: Required<Creator> = "creator",
]
);

View File

@ -12,13 +12,13 @@ generate_element!(
Transport, "transport", JINGLE_IBB,
attributes: [
/// Maximum size in bytes for each chunk.
block_size: u16 = "block-size" => required,
block_size: Required<u16> = "block-size",
/// The identifier to be used to create a stream.
sid: StreamId = "sid" => required,
sid: Required<StreamId> = "sid",
/// Which stanza type to use to exchange data.
stanza: Stanza = "stanza" => default,
stanza: Default<Stanza> = "stanza",
]);
#[cfg(test)]

View File

@ -55,23 +55,23 @@ generate_element!(
Candidate, "candidate", JINGLE_S5B,
attributes: [
/// The identifier for this candidate.
cid: CandidateId = "cid" => required,
cid: Required<CandidateId> = "cid",
/// The host to connect to.
host: IpAddr = "host" => required,
host: Required<IpAddr> = "host",
/// The JID to request at the given end.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// The port to connect to.
port: Option<u16> = "port" => optional,
port: Option<u16> = "port",
/// The priority of this candidate, computed using this formula:
/// priority = (2^16)*(type preference) + (local preference)
priority: u32 = "priority" => required,
priority: Required<u32> = "priority",
/// The type of the connection being proposed by this candidate.
type_: Type = "type" => default,
type_: Default<Type> = "type",
]
);

View File

@ -27,10 +27,10 @@ generate_element!(
attributes: [
/// An optional identifier for matching forwarded messages to this
/// query.
queryid: Option<QueryId> = "queryid" => optional,
queryid: Option<QueryId> = "queryid",
/// Must be set to Some when querying a PubSub nodes archive.
node: Option<NodeName> = "node" => optional
node: Option<NodeName> = "node"
],
children: [
/// Used for filtering the results.
@ -50,11 +50,11 @@ generate_element!(
Result_, "result", MAM,
attributes: [
/// The stanza-id under which the archive stored this stanza.
id: String = "id" => required,
id: Required<String> = "id",
/// The same queryid as the one requested in the
/// [query](struct.Query.html).
queryid: Option<QueryId> = "queryid" => optional,
queryid: Option<QueryId> = "queryid",
],
children: [
/// The actual stanza being forwarded.
@ -76,7 +76,7 @@ generate_element!(
Fin, "fin", MAM,
attributes: [
/// True when the end of a MAM query has been reached.
complete: Complete = "complete" => default
complete: Default<Complete> = "complete",
],
children: [
/// Describes the current page, it should contain at least [first]

View File

@ -17,7 +17,7 @@ generate_element!(
/// accepted too.
///
/// [1]: https://www.iana.org/assignments/media-types/media-types.xhtml
type_: String = "type" => required
type_: Required<String> = "type"
],
text: (
/// The actual URI contained.
@ -31,10 +31,10 @@ generate_element!(
MediaElement, "media", MEDIA_ELEMENT,
attributes: [
/// The recommended display width in pixels.
width: Option<usize> = "width" => optional,
width: Option<usize> = "width",
/// The recommended display height in pixels.
height: Option<usize> = "height" => optional
height: Option<usize> = "height"
],
children: [
/// A list of URIs referencing this media.

View File

@ -12,7 +12,7 @@ generate_element!(
Replace, "replace", MESSAGE_CORRECT,
attributes: [
/// The 'id' attribute of the message getting corrected.
id: String = "id" => required,
id: Required<String> = "id",
]
);

View File

@ -14,16 +14,16 @@ generate_element!(
History, "history", MUC,
attributes: [
/// How many characters of history to send, in XML characters.
maxchars: Option<u32> = "maxchars" => optional,
maxchars: Option<u32> = "maxchars",
/// How many messages to send.
maxstanzas: Option<u32> = "maxstanzas" => optional,
maxstanzas: Option<u32> = "maxstanzas",
/// Only send messages received in these last seconds.
seconds: Option<u32> = "seconds" => optional,
seconds: Option<u32> = "seconds",
/// Only send messages after this date.
since: Option<DateTime> = "since" => optional,
since: Option<DateTime> = "since",
]
);

View File

@ -128,7 +128,7 @@ generate_element!(
Continue, "continue", MUC_USER,
attributes: [
/// The thread to continue in this room.
thread: Option<String> = "thread" => optional,
thread: Option<String> = "thread",
]
);
@ -187,16 +187,16 @@ generate_element!(
/// An item representing a user in a room.
Item, "item", MUC_USER, attributes: [
/// The affiliation of this user with the room.
affiliation: Affiliation = "affiliation" => required,
affiliation: Required<Affiliation> = "affiliation",
/// The real JID of this user, if you are allowed to see it.
jid: Option<Jid> = "jid" => optional,
jid: Option<Jid> = "jid",
/// The current nickname of this user.
nick: Option<String> = "nick" => optional,
nick: Option<String> = "nick",
/// The current role of this user.
role: Role = "role" => required
role: Required<Role> = "role",
], children: [
/// The actor affected by this item.
actor: Option<Actor> = ("actor", MUC_USER) => Actor,

View File

@ -20,7 +20,7 @@ generate_element!(
Affiliations, "affiliations", PUBSUB,
attributes: [
/// The optional node name this request pertains to.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
],
children: [
/// The actual list of affiliation elements.
@ -56,10 +56,10 @@ generate_element!(
Affiliation, "affiliation", PUBSUB,
attributes: [
/// The node this affiliation pertains to.
node: NodeName = "node" => required,
node: Required<NodeName> = "node",
/// The affiliation you currently have on this node.
affiliation: AffiliationAttribute = "affiliation" => required,
affiliation: Required<AffiliationAttribute> = "affiliation",
]
);
@ -77,7 +77,7 @@ generate_element!(
Create, "create", PUBSUB,
attributes: [
/// The node name to create, if `None` the service will generate one.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
]
);
@ -86,10 +86,10 @@ generate_element!(
Default, "default", PUBSUB,
attributes: [
/// The node targetted by this request, otherwise the entire service.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
// TODO: do we really want to support collection nodes?
// type: String = "type" => optional,
// type: Option<String> = "type",
]
);
@ -99,13 +99,13 @@ generate_element!(
attributes: [
// TODO: should be an xs:positiveInteger, that is, an unbounded int ≥ 1.
/// Maximum number of items returned.
max_items: Option<u32> = "max_items" => optional,
max_items: Option<u32> = "max_items",
/// The node queried by this request.
node: NodeName = "node" => required,
node: Required<NodeName> = "node",
/// The subscription identifier related to this request.
subid: Option<SubscriptionId> = "subid" => optional,
subid: Option<SubscriptionId> = "subid",
],
children: [
/// The actual list of items returned.
@ -124,13 +124,13 @@ generate_element!(
Options, "options", PUBSUB,
attributes: [
/// The JID affected by this request.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// The node affected by this request.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
/// The subscription identifier affected by this request.
subid: Option<SubscriptionId> = "subid" => optional,
subid: Option<SubscriptionId> = "subid",
],
children: [
/// The form describing the subscription.
@ -143,7 +143,7 @@ generate_element!(
Publish, "publish", PUBSUB,
attributes: [
/// The target node for this operation.
node: NodeName = "node" => required,
node: Required<NodeName> = "node",
],
children: [
/// The items you want to publish.
@ -172,10 +172,10 @@ generate_element!(
Retract, "retract", PUBSUB,
attributes: [
/// The node affected by this request.
node: NodeName = "node" => required,
node: Required<NodeName> = "node",
/// Whether a retract request should notify subscribers or not.
notify: Notify = "notify" => default,
notify: Default<Notify> = "notify",
],
children: [
/// The items affected by this request.
@ -233,10 +233,10 @@ generate_element!(
Subscribe, "subscribe", PUBSUB,
attributes: [
/// The JID being subscribed.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// The node to subscribe to.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
]
);
@ -245,7 +245,7 @@ generate_element!(
Subscriptions, "subscriptions", PUBSUB,
attributes: [
/// The node to query.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
],
children: [
/// The list of subscription elements returned.
@ -258,16 +258,16 @@ generate_element!(
SubscriptionElem, "subscription", PUBSUB,
attributes: [
/// The JID affected by this subscription.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// The node affected by this subscription.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
/// The subscription identifier for this subscription.
subid: Option<SubscriptionId> = "subid" => optional,
subid: Option<SubscriptionId> = "subid",
/// The state of the subscription.
subscription: Option<Subscription> = "subscription" => optional,
subscription: Option<Subscription> = "subscription",
],
children: [
/// The options related to this subscription.
@ -280,13 +280,13 @@ generate_element!(
Unsubscribe, "unsubscribe", PUBSUB,
attributes: [
/// The JID affected by this request.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// The node affected by this request.
node: Option<NodeName> = "node" => optional,
node: Option<NodeName> = "node",
/// The subscription identifier for this subscription.
subid: Option<SubscriptionId> = "subid" => optional,
subid: Option<SubscriptionId> = "subid",
]
);

View File

@ -22,7 +22,7 @@ generate_element!(
Received, "received", RECEIPTS,
attributes: [
/// The 'id' attribute of the received message.
id: Option<String> = "id" => optional,
id: Option<String> = "id",
]
);

View File

@ -50,16 +50,16 @@ generate_element!(
Item, "item", ROSTER,
attributes: [
/// JID of this contact.
jid: Jid = "jid" => required,
jid: Required<Jid> = "jid",
/// Name of this contact.
name: Option<String> = "name" => optional_empty,
name: OptionEmpty<String> = "name",
/// Subscription status of this contact.
subscription: Subscription = "subscription" => default,
subscription: Default<Subscription> = "subscription",
/// Indicates “Pending Out” sub-states for this contact.
ask: Ask = "ask" => default,
ask: Default<Ask> = "ask",
],
children: [
@ -77,7 +77,7 @@ generate_element!(
/// This is an opaque string that should only be sent back to the server on
/// a new connection, if this client is storing the contact list between
/// connections.
ver: Option<String> = "ver" => optional
ver: Option<String> = "ver"
],
children: [
/// List of the contacts of the user.

View File

@ -49,7 +49,7 @@ generate_element!(
Auth, "auth", SASL,
attributes: [
/// The mechanism used.
mechanism: Mechanism = "mechanism" => required
mechanism: Required<Mechanism> = "mechanism"
],
text: (
/// The content of the handshake.

View File

@ -11,7 +11,7 @@ generate_element!(
A, "a", SM,
attributes: [
/// The last handled stanza.
h: u32 = "h" => required,
h: Required<u32> = "h",
]
);
@ -36,10 +36,10 @@ generate_element!(
attributes: [
/// The preferred resumption time in seconds by the client.
// TODO: should be the infinite integer set ≥ 1.
max: Option<u32> = "max" => optional,
max: Option<u32> = "max",
/// Whether the client wants to be allowed to resume the stream.
resume: ResumeAttr = "resume" => default,
resume: Default<ResumeAttr> = "resume",
]
);
@ -72,18 +72,18 @@ generate_element!(
Enabled, "enabled", SM,
attributes: [
/// A random identifier used for stream resumption.
id: Option<StreamId> = "id" => optional,
id: Option<StreamId> = "id",
/// The preferred IP, domain, IP:port or domain:port location for
/// resumption.
location: Option<String> = "location" => optional,
location: Option<String> = "location",
/// The preferred resumption time in seconds by the server.
// TODO: should be the infinite integer set ≥ 1.
max: Option<u32> = "max" => optional,
max: Option<u32> = "max",
/// Whether stream resumption is allowed.
resume: ResumeAttr = "resume" => default,
resume: Default<ResumeAttr> = "resume",
]
);
@ -92,7 +92,7 @@ generate_element!(
Failed, "failed", SM,
attributes: [
/// The last handled stanza.
h: Option<u32> = "h" => optional,
h: Option<u32> = "h",
],
children: [
/// The error returned.
@ -113,11 +113,11 @@ generate_element!(
Resume, "resume", SM,
attributes: [
/// The last handled stanza.
h: u32 = "h" => required,
h: Required<u32> = "h",
/// The previous id given by the server on
/// [enabled](struct.Enabled.html).
previd: StreamId = "previd" => required,
previd: Required<StreamId> = "previd",
]
);
@ -126,11 +126,11 @@ generate_element!(
Resumed, "resumed", SM,
attributes: [
/// The last handled stanza.
h: u32 = "h" => required,
h: Required<u32> = "h",
/// The previous id given by the server on
/// [enabled](struct.Enabled.html).
previd: StreamId = "previd" => required,
previd: Required<StreamId> = "previd",
]
);

View File

@ -13,10 +13,10 @@ generate_element!(
StanzaId, "stanza-id", SID,
attributes: [
/// The id associated to this stanza by another entity.
id: String = "id" => required,
id: Required<String> = "id",
/// The entity who stamped this stanza-id.
by: Jid = "by" => required,
by: Required<Jid> = "by",
]
);
@ -28,7 +28,7 @@ generate_element!(
OriginId, "origin-id", SID,
attributes: [
/// The id this client set for this stanza.
id: String = "id" => required,
id: Required<String> = "id",
]
);

View File

@ -11,20 +11,20 @@ generate_element!(
Stream, "stream", STREAM,
attributes: [
/// The JID of the entity opening this stream.
from: Option<Jid> = "from" => optional,
from: Option<Jid> = "from",
/// The JID of the entity receiving this stream opening.
to: Option<Jid> = "to" => optional,
to: Option<Jid> = "to",
/// The id of the stream, used for authentication challenges.
id: Option<String> = "id" => optional,
id: Option<String> = "id",
/// The XMPP version used during this stream.
version: Option<String> = "version" => optional,
version: Option<String> = "version",
/// The default human language for all subsequent stanzas, which will
/// be transmitted to other entities for better localisation.
xml_lang: Option<String> = "xml:lang" => optional,
xml_lang: Option<String> = "xml:lang",
]
);

View File

@ -8,20 +8,20 @@ macro_rules! get_attr {
($elem:ident, $attr:tt, $type:tt) => {
get_attr!($elem, $attr, $type, value, value.parse()?)
};
($elem:ident, $attr:tt, optional_empty, $value:ident, $func:expr) => {
($elem:ident, $attr:tt, OptionEmpty, $value:ident, $func:expr) => {
match $elem.attr($attr) {
Some("") => None,
Some($value) => Some($func),
None => None,
}
};
($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => {
($elem:ident, $attr:tt, Option, $value:ident, $func:expr) => {
match $elem.attr($attr) {
Some($value) => Some($func),
None => None,
}
};
($elem:ident, $attr:tt, required, $value:ident, $func:expr) => {
($elem:ident, $attr:tt, Required, $value:ident, $func:expr) => {
match $elem.attr($attr) {
Some($value) => $func,
None => {
@ -33,12 +33,22 @@ macro_rules! get_attr {
}
}
};
($elem:ident, $attr:tt, default, $value:ident, $func:expr) => {
($elem:ident, $attr:tt, Default, $value:ident, $func:expr) => {
match $elem.attr($attr) {
Some($value) => $func,
None => ::std::default::Default::default(),
}
};
// The remaining ones are only for backwards-compatibility.
($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => {
get_attr!($elem, $attr, Option, $value, $func)
};
($elem:ident, $attr:tt, required, $value:ident, $func:expr) => {
get_attr!($elem, $attr, Required, $value, $func)
};
($elem:ident, $attr:tt, default, $value:ident, $func:expr) => {
get_attr!($elem, $attr, Default, $value, $func)
};
}
macro_rules! generate_attribute {
@ -398,6 +408,21 @@ macro_rules! generate_elem_id {
);
}
macro_rules! decl_attr {
(OptionEmpty, $type:ty) => (
Option<$type>
);
(Option, $type:ty) => (
Option<$type>
);
(Required, $type:ty) => (
$type
);
(Default, $type:ty) => (
$type
);
}
macro_rules! start_decl {
(Vec, $type:ty) => (
Vec<$type>
@ -503,31 +528,31 @@ macro_rules! generate_serialiser {
}
macro_rules! generate_element {
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+,]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: []);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+,]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: []);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),*,], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*]) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+], text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+], text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
);
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*] $(, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >))*) => (
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),*], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*] $(, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >))*) => (
$(#[$meta])*
#[derive(Debug, Clone)]
pub struct $elem {
$(
$(#[$attr_meta])*
pub $attr: $attr_type,
pub $attr: decl_attr!($attr_action, $attr_type),
)*
$(
$(#[$child_meta])*

View File

@ -11,20 +11,20 @@ generate_element!(
Open, "open", WEBSOCKET,
attributes: [
/// The JID of the entity opening this stream.
from: Option<Jid> = "from" => optional,
from: Option<Jid> = "from",
/// The JID of the entity receiving this stream opening.
to: Option<Jid> = "to" => optional,
to: Option<Jid> = "to",
/// The id of the stream, used for authentication challenges.
id: Option<String> = "id" => optional,
id: Option<String> = "id",
/// The XMPP version used during this stream.
version: Option<String> = "version" => optional,
version: Option<String> = "version",
/// The default human language for all subsequent stanzas, which will
/// be transmitted to other entities for better localisation.
xml_lang: Option<String> = "xml:lang" => optional,
xml_lang: Option<String> = "xml:lang",
]
);