api: Add stable_path, r0_path and unstable_path metadata fields

This commit is contained in:
Jonathan de Jong 2022-02-08 14:29:21 +01:00 committed by GitHub
parent 0dcdb57c29
commit 1e900ab58c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 16 deletions

View File

@ -48,6 +48,9 @@ impl Api {
let method = &metadata.method;
let name = &metadata.name;
let path = &metadata.path;
let unstable_path = util::map_option_literal(&metadata.unstable_path);
let r0_path = util::map_option_literal(&metadata.r0_path);
let stable_path = util::map_option_literal(&metadata.stable_path);
let rate_limited: TokenStream = metadata
.rate_limited
.iter()
@ -92,6 +95,9 @@ impl Api {
method: #http::Method::#method,
name: #name,
path: #path,
unstable_path: #unstable_path,
r0_path: #r0_path,
stable_path: #stable_path,
added: #added,
deprecated: #deprecated,
removed: #removed,

View File

@ -15,6 +15,9 @@ mod kw {
syn::custom_keyword!(method);
syn::custom_keyword!(name);
syn::custom_keyword!(path);
syn::custom_keyword!(unstable);
syn::custom_keyword!(r0);
syn::custom_keyword!(stable);
syn::custom_keyword!(rate_limited);
syn::custom_keyword!(authentication);
syn::custom_keyword!(added);
@ -42,8 +45,17 @@ pub struct Metadata {
/// The name field.
pub name: LitStr,
/// The path field.
pub path: LitStr,
/// The path field. (deprecated)
pub path: EndpointPath,
/// The unstable path field.
pub unstable_path: Option<EndpointPath>,
/// The pre-v1.1 path field.
pub r0_path: Option<EndpointPath>,
/// The stable path field.
pub stable_path: Option<EndpointPath>,
/// The rate_limited field.
pub rate_limited: Vec<MetadataField<LitBool>>,
@ -90,6 +102,9 @@ impl Parse for Metadata {
let mut method = None;
let mut name = None;
let mut path = None;
let mut unstable_path = None;
let mut r0_path = None;
let mut stable_path = None;
let mut rate_limited = vec![];
let mut authentication = vec![];
let mut added = None;
@ -102,6 +117,9 @@ impl Parse for Metadata {
FieldValue::Method(m) => set_field(&mut method, m)?,
FieldValue::Name(n) => set_field(&mut name, n)?,
FieldValue::Path(p) => set_field(&mut path, p)?,
FieldValue::Unstable(p) => set_field(&mut unstable_path, p)?,
FieldValue::R0(p) => set_field(&mut r0_path, p)?,
FieldValue::Stable(p) => set_field(&mut stable_path, p)?,
FieldValue::RateLimited(value, attrs) => {
rate_limited.push(MetadataField { attrs, value });
}
@ -141,11 +159,29 @@ impl Parse for Metadata {
}
}
if let Some(added) = &added {
if stable_path.is_none() {
return Err(syn::Error::new_spanned(
added,
"added version is defined, but no stable path exists",
));
}
}
if unstable_path.is_none() && r0_path.is_none() && stable_path.is_none() {
// TODO replace with error
// return Err(syn::Error::new_spanned(metadata_kw, "no path is defined"));
r0_path = path.clone();
}
Ok(Self {
description: description.ok_or_else(|| missing_field("description"))?,
method: method.ok_or_else(|| missing_field("method"))?,
name: name.ok_or_else(|| missing_field("name"))?,
path: path.ok_or_else(|| missing_field("path"))?,
unstable_path,
r0_path,
stable_path,
rate_limited: if rate_limited.is_empty() {
return Err(missing_field("rate_limited"));
} else {
@ -168,6 +204,9 @@ enum Field {
Method,
Name,
Path,
Unstable,
R0,
Stable,
RateLimited,
Authentication,
Added,
@ -191,6 +230,15 @@ impl Parse for Field {
} else if lookahead.peek(kw::path) {
let _: kw::path = input.parse()?;
Ok(Self::Path)
} else if lookahead.peek(kw::unstable) {
let _: kw::unstable = input.parse()?;
Ok(Self::Unstable)
} else if lookahead.peek(kw::r0) {
let _: kw::r0 = input.parse()?;
Ok(Self::R0)
} else if lookahead.peek(kw::stable) {
let _: kw::stable = input.parse()?;
Ok(Self::Stable)
} else if lookahead.peek(kw::rate_limited) {
let _: kw::rate_limited = input.parse()?;
Ok(Self::RateLimited)
@ -216,7 +264,10 @@ enum FieldValue {
Description(LitStr),
Method(Ident),
Name(LitStr),
Path(LitStr),
Path(EndpointPath),
Unstable(EndpointPath),
R0(EndpointPath),
Stable(EndpointPath),
RateLimited(LitBool, Vec<Attribute>),
Authentication(AuthScheme, Vec<Attribute>),
Added(MatrixVersionLiteral),
@ -242,18 +293,10 @@ impl Parse for FieldValue {
Field::Description => Self::Description(input.parse()?),
Field::Method => Self::Method(input.parse()?),
Field::Name => Self::Name(input.parse()?),
Field::Path => {
let path: LitStr = input.parse()?;
if !util::is_valid_endpoint_path(&path.value()) {
return Err(syn::Error::new_spanned(
&path,
"path may only contain printable ASCII characters with no spaces",
));
}
Self::Path(path)
}
Field::Path => Self::Path(input.parse()?),
Field::Unstable => Self::Unstable(input.parse()?),
Field::R0 => Self::R0(input.parse()?),
Field::Stable => Self::Stable(input.parse()?),
Field::RateLimited => Self::RateLimited(input.parse()?, attrs),
Field::Authentication => Self::Authentication(input.parse()?, attrs),
Field::Added => Self::Added(input.parse()?),
@ -262,3 +305,27 @@ impl Parse for FieldValue {
})
}
}
#[derive(Clone)]
pub struct EndpointPath(LitStr);
impl Parse for EndpointPath {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let path: LitStr = input.parse()?;
if util::is_valid_endpoint_path(&path.value()) {
Ok(Self(path))
} else {
Err(syn::Error::new_spanned(
&path,
"path may only contain printable ASCII characters with no spaces",
))
}
}
}
impl ToTokens for EndpointPath {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
self.0.to_tokens(tokens)
}
}

View File

@ -415,9 +415,19 @@ pub struct Metadata {
/// A unique identifier for this endpoint.
pub name: &'static str,
/// (DEPRECATED)
pub path: &'static str,
/// The unstable path of this endpoint's URL, often `None`, used for developmental purposes.
pub unstable_path: Option<&'static str>,
/// The pre-v1.1 version of this endpoint's URL, `None` for post-v1.1 endpoints, supplemental
/// to `stable_path`.
pub r0_path: Option<&'static str>,
/// The path of this endpoint's URL, with variable names where path parameters should be filled
/// in during a request.
pub path: &'static str,
pub stable_path: Option<&'static str>,
/// Whether or not this endpoint is rate limited by the server.
pub rate_limited: bool,

View File

@ -29,6 +29,9 @@ const METADATA: Metadata = Metadata {
method: Method::PUT,
name: "create_alias",
path: "/_matrix/client/r0/directory/room/:room_alias",
unstable_path: None,
r0_path: None,
stable_path: None,
rate_limited: false,
authentication: AuthScheme::None,
added: None,

View File

@ -8,6 +8,9 @@ ruma_api! {
method: POST, // An `http::Method` constant. No imports required.
name: "some_endpoint",
path: "/_matrix/some/endpoint/:baz",
unstable: "/_matrix/some/msc1234/endpoint/:baz",
r0: "/_matrix/some/r0/endpoint/:baz",
stable: "/_matrix/some/v1/endpoint/:baz",
rate_limited: false,
authentication: None,
added: 1.0,
@ -56,6 +59,10 @@ ruma_api! {
fn main() {
use ruma_api::MatrixVersion;
assert_eq!(METADATA.unstable_path, Some("/_matrix/some/msc1234/endpoint/:baz"));
assert_eq!(METADATA.r0_path, Some("/_matrix/some/r0/endpoint/:baz"));
assert_eq!(METADATA.stable_path, Some("/_matrix/some/v1/endpoint/:baz"));
assert_eq!(METADATA.added, Some(MatrixVersion::V1_0));
assert_eq!(METADATA.deprecated, Some(MatrixVersion::V1_1));
assert_eq!(METADATA.removed, Some(MatrixVersion::V1_2));