Add macros to create identifiers from string slices

This commit is contained in:
Jonas Platte 2020-07-24 22:22:25 +02:00
parent ce04ea10bf
commit c8b1aad189
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
9 changed files with 260 additions and 0 deletions

View File

@ -0,0 +1,19 @@
[package]
authors = ["Jonas Platte <jplatte@posteo.de>"]
description = "Procedural macros for creating Matrix identifiers."
homepage = "https://www.ruma.io/"
keywords = ["matrix", "chat", "messaging", "ruma"]
license = "MIT"
name = "ruma-identifiers-macros"
repository = "https://github.com/ruma/ruma"
version = "0.17.0"
edition = "2018"
[dependencies]
ruma-identifiers = "=0.17.0"
quote = "1.0.7"
proc-macro2 = "1.0.19"
syn = "1.0.35"
[lib]
proc-macro = true

View File

@ -0,0 +1,19 @@
Copyright (c) 2020 Jonas Platte
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,117 @@
use proc_macro::TokenStream;
use std::convert::TryFrom;
use quote::quote;
use ruma_identifiers::{
DeviceKeyId, EventId, RoomAliasId, RoomId, RoomVersionId, ServerKeyId, ServerName, UserId,
};
use syn::{parse_macro_input, LitStr};
#[proc_macro]
pub fn device_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
let output = quote! {
::std::boxed::Box<::ruma::identifiers::DeviceId>::from(#id)
};
output.into()
}
// w/o macro: UserId::try_from("@user:example.org").unwrap()
// w/ macro: user_id!("@user:example.org")
#[proc_macro]
pub fn device_key_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(DeviceKeyId::try_from(id.value()).is_ok(), "Invalid device key id");
let output = quote! {
<::ruma::identifiers::DeviceKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn event_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(EventId::try_from(id.value()).is_ok(), "Invalid event id");
let output = quote! {
<::ruma::identifiers::EventId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn room_alias_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(RoomAliasId::try_from(id.value()).is_ok(), "Invalid room_alias_id");
let output = quote! {
<::ruma::identifiers::RoomAliasId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn room_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(RoomId::try_from(id.value()).is_ok(), "Invalid room_id");
let output = quote! {
<::ruma::identifiers::RoomId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn room_version_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(RoomVersionId::try_from(id.value()).is_ok(), "Invalid room_version_id");
let output = quote! {
<::ruma::identifiers::RoomVersionId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn server_key_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(ServerKeyId::try_from(id.value()).is_ok(), "Invalid server_key_id");
let output = quote! {
<::ruma::identifiers::ServerKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn server_name(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(<&ServerName>::try_from(id.value().as_str()).is_ok(), "Invalid server_name");
let output = quote! {
<::std::boxed::Box::<::ruma::identifiers::ServerName> as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}
#[proc_macro]
pub fn user_id(input: TokenStream) -> TokenStream {
let id = parse_macro_input!(input as LitStr);
assert!(UserId::try_from(id.value()).is_ok(), "Invalid user_id");
let output = quote! {
<::ruma::identifiers::UserId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
};
output.into()
}

View File

@ -25,6 +25,7 @@ federation-api = ["ruma-api", "ruma-federation-api", "ruma-signatures"]
[dependencies]
ruma-common = { version = "0.2.0", path = "../ruma-common" }
ruma-identifiers = { version = "0.17.0", path = "../ruma-identifiers", features = ["serde"] }
ruma-identifiers-macros = { version = "0.17.0", path = "../ruma-identifiers-macros" }
ruma-events = { version = "0.21.3", path = "../ruma-events", optional = true }
ruma-signatures = { version = "0.6.0-dev.1", path = "../ruma-signatures", optional = true }
@ -33,3 +34,6 @@ ruma-api = { version = "0.16.1", path = "../ruma-api", optional = true }
ruma-appservice-api = { version = "0.1.0", path = "../ruma-appservice-api", optional = true }
ruma-client-api = { version = "0.9.0", path = "../ruma-client-api", optional = true }
ruma-federation-api = { version = "0.0.2", path = "../ruma-federation-api", optional = true }
[dev-dependencies]
trybuild = "1.0.30"

View File

@ -16,6 +16,7 @@
pub use ruma_common::*;
#[doc(inline)]
pub use ruma_identifiers as identifiers;
pub use ruma_identifiers_macros::*;
#[cfg(feature = "ruma-events")]
#[doc(inline)]

6
ruma/tests/id-macros.rs Normal file
View File

@ -0,0 +1,6 @@
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.pass("tests/ui/01-valid-id-macros.rs");
t.compile_fail("tests/ui/02-invalid-id-macros.rs");
}

View File

@ -0,0 +1,12 @@
fn main() {
let _ = ruma::device_key_id!("ed25519:JLAFKJWSCS");
let _ = ruma::event_id!("$39hvsi03hlne:example.com");
let _ = ruma::event_id!("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk");
let _ = ruma::room_alias_id!("#alias:server.tld");
let _ = ruma::room_id!("!1234567890:matrix.org");
let _ = ruma::room_version_id!("1");
let _ = ruma::room_version_id!("1-custom");
let _ = ruma::server_key_id!("ed25519:Abc_1");
let _ = ruma::server_name!("myserver.fish");
let _ = ruma::user_id!("@user:ruma.io");
}

View File

@ -0,0 +1,11 @@
fn main() {
let _ = ruma::device_key_id!("ed2519:JLAFKJWSCS");
let _ = ruma::event_id!("39hvsi03hlne:example.com");
let _ = ruma::event_id!("acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk");
let _ = ruma::room_alias_id!("alias:server.tld");
let _ = ruma::room_id!("1234567890:matrix.org");
let _ = ruma::room_version_id!("");
let _ = ruma::server_key_id!("ed219:Abc_1");
let _ = ruma::server_name!("");
let _ = ruma::user_id!("user:ruma.io");
}

View File

@ -0,0 +1,71 @@
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:2:13
|
2 | let _ = ruma::device_key_id!("ed2519:JLAFKJWSCS");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid device key id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:3:13
|
3 | let _ = ruma::event_id!("39hvsi03hlne:example.com");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid event id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:4:13
|
4 | let _ = ruma::event_id!("acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid event id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:5:13
|
5 | let _ = ruma::room_alias_id!("alias:server.tld");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid room_alias_id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:6:13
|
6 | let _ = ruma::room_id!("1234567890:matrix.org");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid room_id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:7:13
|
7 | let _ = ruma::room_version_id!("");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid room_version_id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:8:13
|
8 | let _ = ruma::server_key_id!("ed219:Abc_1");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid server_key_id
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:9:13
|
9 | let _ = ruma::server_name!("");
| ^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid server_name
error: proc macro panicked
--> $DIR/02-invalid-id-macros.rs:10:13
|
10 | let _ = ruma::user_id!("user:ruma.io");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: Invalid user_id