8 unstable releases (3 breaking)
Uses new Rust 2024
new 0.4.1 | Apr 28, 2025 |
---|---|
0.4.0 | Apr 28, 2025 |
0.3.0 | Apr 27, 2025 |
0.2.1 | Apr 26, 2025 |
0.1.1 | Jan 19, 2025 |
#423 in WebSocket
225 downloads per month
Used in 3 crates
395KB
9K
SLoC
battler-wamprat-uri
battler-wamprat-uri is a utility crate for battler-wamprat
. It provides a procedural macro for dynamically matching URIs for WAMP subscriptions and procedure registrations.
Pattern-based subscriptions and procedure registrations can be complex. They provide an
additional avenue of input for WAMP messages, outside the arguments
and arguments_keyword
fields expressed by battler_wamprat_message::WampApplicationMessage
types.
For example, a callee can register a procedure on the wildcard URI com.test.add..v2
. A caller
can then call this procedure using any URI that matches this pattern. One caller may call
com.test.add.integers.v2
while another may call com.test.add.strings.v2
. The wildcard URI
component (in this case, integers
or strings
) is likely very important to the callee!
This crate provides runtime type checking and pattern matching to incoming and outgoing WAMP URI
patterns through the WampUriMatcher
derive macro. A URI matcher can be thought of as a
glorified regular expression: each wildcard component is a named capture group that can
be referenced after matching. The end result is that URIs going out from a peer can be formatted
automatically, and URIs coming into a peer can be pattern matched, allowing the extracted URI
components to be easily read by application logic.
Basic Usage
A struct using the WampUriMatcher
derive macro must have a uri
attribute. The URI
describes the wildcard pattern, which is used for formatting outgoing URIs and matching incoming
URIs.
In the simplest case, a struct with no fields can match a static URI:
use battler_wamprat_uri::WampUriMatcher;
#[derive(WampUriMatcher)]
#[uri("com.test.add")]
struct AddUri {}
For each field you add, that field must be represented in the URI pattern. Otherwise, the struct would be impossible to construct for incoming URIs.
use battler_wamprat_uri::WampUriMatcher;
#[derive(WampUriMatcher)]
#[uri("com.test.add.{name}.v2")]
struct AddUri {
name: String,
}
Each struct field must be convertible to and from a string, using
Display
and FromStr
respectively.
use battler_wamprat_uri::WampUriMatcher;
#[derive(WampUriMatcher)]
#[uri("com.test.add.{name}.{count}")]
struct AddUri {
name: String,
count: u64,
}
Advanced Features
Prefix Matching
In some cases, a URI pattern may need to match in prefix form. Prefix matching is only possible
if the last field in the struct is marked with the rest
attribute. This attribute requires
that an iterator of String
s can be collected into its type.
use battler_wamprat_uri::WampUriMatcher;
#[derive(WampUriMatcher)]
#[uri("com.test.fn.{a}.{rest}")]
struct PrefixUri {
a: String,
#[rest]
rest: Vec<String>,
}
Field Repetition
Fields can be repeated in the URI pattern. The first use of the field will be treated as the source of truth, and all later uses of the field must match this first value.
use battler_wamprat_uri::WampUriMatcher;
#[derive(WampUriMatcher)]
#[uri("com.test.fn.{a}.{b}.{a}")]
struct RepeatedUri {
a: u64,
b: u64,
}
Regular Expression Component Matching
In most cases, struct fields should be isolated to their own URI components for simplicity. However, this is not a strict requirement of the URI matcher macro.
Strings and struct fields can be combined into the same URI component. If this is done, the URI pattern matching is less enforceable on the router, but the peer will still validate and match the URI as expected.
use battler_wamprat_uri::WampUriMatcher;
#[derive(WampUriMatcher)]
#[uri("com.test.math.{a}log{b}")]
struct RegExUri {
a: u64,
b: u64,
}
Note that in the above case, the URI registered on the router will be the wildcard
com.test.math.
, so the last component can be matched by any string. However, the RegExUri
type will enforce the additional restrictions. For instance, the URI com.test.math.abc
will
be rejected by the peer, while com.test.math.2log12
will be accepted.
Note: URI such as the one above will generate a dependency on the regex
crate.
Generators
It can sometimes be useful to generate partial-wildcard URIs based on a URI pattern. For
example, one peer may be publishing messages to com.chat.{version}.{channel}.{author}
, and
another peer may want to subscribe to messages for a specific channel using the
com.chat.1.main.{author}
. Rather than requiring the subscriber to generate this
wildcard URI manually, it can use a derived generator struct from base URI pattern.
A generator struct implements the WampWildcardUriGenerator
trait and can be generated
automatically with the generator
macro attribute. You can generate multiple generators for a
single matcher.
use std::marker::PhantomData;
use battler_wamprat_uri::{
WampUriMatcher,
Wildcard,
WampWildcardUriGenerator,
};
#[derive(Clone, WampUriMatcher)]
#[uri("com.chat.{version}.{channel}.{author}")]
#[generator(ChannelMessageUri, fixed(version = 1u64), require(channel), derive(Clone))]
struct MessageUri {
version: u64,
channel: String,
author: String,
}
fn main() {
assert_matches::assert_matches!(ChannelMessageUri {
version: PhantomData,
channel: "main".to_owned(),
author: Wildcard::Wildcard,
}.wamp_generate_wildcard_uri(), Ok(uri) => {
assert_eq!(uri.as_ref(), "com.chat.1.main.");
});
}
You can also create generators for patterns with unnamed fields, but indices must be prefixed
with an underscore (e.g., _0
, _1
) in the generator
attribute.
Note: Generators are limited to simple wildcard URI patterns only. URI patterns with prefix matching and/or regular expression matching cannot use generators.
battler-wamprat-uri
battler-wamprat-uri is a utility crate for battler-wamprat
. It provides a procedural macro for dynamically matching URIs for WAMP subscriptions and procedure registrations.
Dependencies
~19–30MB
~552K SLoC