diff --git a/Cargo.toml b/Cargo.toml index 9ad93586..9edc6d6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,10 +18,29 @@ serde_json = "1.0.40" serde_urlencoded = "0.6.0" ruma-identifiers = "0.14.0" -[dev-dependencies] -url = "2.0.0" -percent-encoding = "2.0.0" +[dependencies.percent-encoding] +version = "2.0.0" +optional = true -[dev-dependencies.serde] +[dependencies.ruma-api-macros] +version = "0.6.0" +path = "ruma-api-macros" +optional = true + +[dependencies.serde] version = "1.0.98" features = ["derive"] +optional = true + +[dependencies.url] +version = "2.0.0" +optional = true + +[features] +default = ["with-ruma-api-macros"] +with-ruma-api-macros = ["percent-encoding", "ruma-api-macros", "serde", "url"] + +[workspace] +members = [ + "ruma-api-macros", +] diff --git a/ruma-api-macros/src/api/mod.rs b/ruma-api-macros/src/api/mod.rs index a656becb..90f7b28b 100644 --- a/ruma-api-macros/src/api/mod.rs +++ b/ruma-api-macros/src/api/mod.rs @@ -142,10 +142,10 @@ impl ToTokens for Api { #path_var_ident: { let segment = path_segments.get(#i).unwrap().as_bytes(); let decoded = - ::url::percent_encoding::percent_decode(segment) + ruma_api::exports::percent_encoding::percent_decode(segment) .decode_utf8_lossy(); #ty::deserialize(decoded.into_deserializer()) - .map_err(|e: ::serde_json::error::Error| e)? + .map_err(|e: ruma_api::exports::serde_json::error::Error| e)? } } }); @@ -171,7 +171,7 @@ impl ToTokens for Api { #request_query_init_fields }; - url.set_query(Some(&::serde_urlencoded::to_string(request_query)?)); + url.set_query(Some(&ruma_api::exports::serde_urlencoded::to_string(request_query)?)); } } else { TokenStream::new() @@ -180,7 +180,7 @@ impl ToTokens for Api { let extract_request_query = if self.request.has_query_fields() { quote! { let request_query: RequestQuery = - ::serde_urlencoded::from_str(&request.uri().query().unwrap_or(""))?; + ruma_api::exports::serde_urlencoded::from_str(&request.uri().query().unwrap_or(""))?; } } else { TokenStream::new() @@ -225,7 +225,7 @@ impl ToTokens for Api { quote! { let request_body = RequestBody(request.#field_name); - let mut http_request = ::http::Request::new(::serde_json::to_vec(&request_body)?); + let mut http_request = ruma_api::exports::http::Request::new(ruma_api::exports::serde_json::to_vec(&request_body)?); } } else if self.request.has_body_fields() { let request_body_init_fields = self.request.request_body_init_fields(); @@ -235,11 +235,11 @@ impl ToTokens for Api { #request_body_init_fields }; - let mut http_request = ::http::Request::new(::serde_json::to_vec(&request_body)?); + let mut http_request = ruma_api::exports::http::Request::new(ruma_api::exports::serde_json::to_vec(&request_body)?); } } else { quote! { - let mut http_request = ::http::Request::new(Vec::new()); + let mut http_request = ruma_api::exports::http::Request::new(Vec::new()); } }; @@ -247,12 +247,12 @@ impl ToTokens for Api { let ty = &field.ty; quote! { let request_body: #ty = - ::serde_json::from_slice(request.body().as_slice())?; + ruma_api::exports::serde_json::from_slice(request.body().as_slice())?; } } else if self.request.has_body_fields() { quote! { let request_body: RequestBody = - ::serde_json::from_slice(request.body().as_slice())?; + ruma_api::exports::serde_json::from_slice(request.body().as_slice())?; } } else { TokenStream::new() @@ -278,11 +278,11 @@ impl ToTokens for Api { let field_type = &field.ty; quote! { - ::serde_json::from_slice::<#field_type>(http_response.into_body().as_slice())? + ruma_api::exports::serde_json::from_slice::<#field_type>(http_response.into_body().as_slice())? } } else if self.response.has_body_fields() { quote! { - ::serde_json::from_slice::(http_response.into_body().as_slice())? + ruma_api::exports::serde_json::from_slice::(http_response.into_body().as_slice())? } } else { quote! { @@ -309,7 +309,7 @@ impl ToTokens for Api { let try_serialize_response_body = if self.response.has_body() { let body = self.response.to_body(); quote! { - ::serde_json::to_vec(&#body)? + ruma_api::exports::serde_json::to_vec(&#body)? } } else { quote! { @@ -317,29 +317,28 @@ impl ToTokens for Api { } }; - let endpoint_doc = format!("The `{}` API endpoint.\n\n{}", name, description.value()); - let request_doc = format!("Data for a request to the `{}` API endpoint.", name); + let request_doc = format!( + "Data for a request to the `{}` API endpoint.\n\n{}", + name, + description.value() + ); let response_doc = format!("Data in the response from the `{}` API endpoint.", name); let api = quote! { - use ::ruma_api::Endpoint as _; - use ::serde::Deserialize as _; - use ::serde::de::{Error as _, IntoDeserializer as _}; + use ruma_api::Endpoint as _; + use ruma_api::exports::serde::Deserialize as _; + use ruma_api::exports::serde::de::{Error as _, IntoDeserializer as _}; - use ::std::convert::{TryInto as _}; - - #[doc = #endpoint_doc] - #[derive(Debug)] - pub struct Endpoint; + use std::convert::{TryInto as _}; #[doc = #request_doc] #request_types - impl ::std::convert::TryFrom<::http::Request>> for Request { - type Error = ::ruma_api::Error; + impl std::convert::TryFrom>> for Request { + type Error = ruma_api::Error; #[allow(unused_variables)] - fn try_from(request: ::http::Request>) -> Result { + fn try_from(request: ruma_api::exports::http::Request>) -> Result { #extract_request_path #extract_request_query #extract_request_headers @@ -354,24 +353,24 @@ impl ToTokens for Api { } } - impl ::std::convert::TryFrom for ::http::Request> { - type Error = ::ruma_api::Error; + impl std::convert::TryFrom for ruma_api::exports::http::Request> { + type Error = ruma_api::Error; #[allow(unused_mut, unused_variables)] fn try_from(request: Request) -> Result { - let metadata = Endpoint::METADATA; + let metadata = Request::METADATA; // Use dummy homeserver url which has to be overwritten in // the calling code. Previously (with http::Uri) this was // not required, but Url::parse only accepts absolute urls. - let mut url = ::url::Url::parse("http://invalid-host-please-change/").unwrap(); + let mut url = ruma_api::exports::url::Url::parse("http://invalid-host-please-change/").unwrap(); { #set_request_path } { #set_request_query } #create_http_request - *http_request.method_mut() = ::http::Method::#method; + *http_request.method_mut() = ruma_api::exports::http::Method::#method; *http_request.uri_mut() = url.into_string().parse().unwrap(); { #add_headers_to_request } @@ -383,13 +382,13 @@ impl ToTokens for Api { #[doc = #response_doc] #response_types - impl ::std::convert::TryFrom for ::http::Response> { - type Error = ::ruma_api::Error; + impl std::convert::TryFrom for ruma_api::exports::http::Response> { + type Error = ruma_api::Error; #[allow(unused_variables)] fn try_from(response: Response) -> Result { - let response = ::http::Response::builder() - .header(::http::header::CONTENT_TYPE, "application/json") + let response = ruma_api::exports::http::Response::builder() + .header(ruma_api::exports::http::header::CONTENT_TYPE, "application/json") #serialize_response_headers .body(#try_serialize_response_body) .unwrap(); @@ -397,11 +396,11 @@ impl ToTokens for Api { } } - impl ::std::convert::TryFrom<::http::Response>> for Response { - type Error = ::ruma_api::Error; + impl std::convert::TryFrom>> for Response { + type Error = ruma_api::Error; #[allow(unused_variables)] - fn try_from(http_response: ::http::Response>) -> Result { + fn try_from(http_response: ruma_api::exports::http::Response>) -> Result { if http_response.status().is_success() { #extract_response_headers @@ -415,14 +414,13 @@ impl ToTokens for Api { } } - impl ::ruma_api::Endpoint for Endpoint { - type Request = Request; + impl ruma_api::Endpoint for Request { type Response = Response; /// Metadata for the `#name` endpoint. - const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata { + const METADATA: ruma_api::Metadata = ruma_api::Metadata { description: #description, - method: ::http::Method::#method, + method: ruma_api::exports::http::Method::#method, name: #name, path: #path, rate_limited: #rate_limited, diff --git a/ruma-api-macros/src/api/request.rs b/ruma-api-macros/src/api/request.rs index 865f040e..e6ac4451 100644 --- a/ruma-api-macros/src/api/request.rs +++ b/ruma-api-macros/src/api/request.rs @@ -28,8 +28,8 @@ impl Request { quote! { headers.append( - ::http::header::#header_name, - ::http::header::HeaderValue::from_str(request.#field_name.as_ref()) + ruma_api::exports::http::header::#header_name, + ruma_api::exports::http::header::HeaderValue::from_str(request.#field_name.as_ref()) .expect("failed to convert value into HeaderValue"), ); } @@ -52,9 +52,9 @@ impl Request { let header_name_string = header_name.to_string(); quote! { - #field_name: headers.get(::http::header::#header_name) + #field_name: headers.get(ruma_api::exports::http::header::#header_name) .and_then(|v| v.to_str().ok()) - .ok_or(::serde_json::Error::missing_field(#header_name_string))? + .ok_or(ruma_api::exports::serde_json::Error::missing_field(#header_name_string))? .to_owned() } }); @@ -261,7 +261,7 @@ impl ToTokens for Request { quote_spanned! {span=> /// Data in the request body. - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, ruma_api::exports::serde::Deserialize, ruma_api::exports::serde::Serialize)] struct RequestBody(#ty); } } else if self.has_body_fields() { @@ -278,7 +278,7 @@ impl ToTokens for Request { quote! { /// Data in the request body. - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, ruma_api::exports::serde::Deserialize, ruma_api::exports::serde::Serialize)] struct RequestBody { #(#fields),* } @@ -302,7 +302,7 @@ impl ToTokens for Request { quote! { /// Data in the request path. - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, ruma_api::exports::serde::Deserialize, ruma_api::exports::serde::Serialize)] struct RequestPath { #(#fields),* } @@ -325,7 +325,7 @@ impl ToTokens for Request { quote! { /// Data in the request's query string. - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, ruma_api::exports::serde::Deserialize, ruma_api::exports::serde::Serialize)] struct RequestQuery { #(#fields),* } diff --git a/ruma-api-macros/src/api/response.rs b/ruma-api-macros/src/api/response.rs index 32263702..2bac5765 100644 --- a/ruma-api-macros/src/api/response.rs +++ b/ruma-api-macros/src/api/response.rs @@ -61,7 +61,7 @@ impl Response { let span = field.span(); quote_spanned! {span=> - #field_name: headers.remove(::http::header::#header_name) + #field_name: headers.remove(ruma_api::exports::http::header::#header_name) .expect("response missing expected header") .to_str() .expect("failed to convert HeaderValue to str") @@ -97,7 +97,7 @@ impl Response { let span = field.span(); Some(quote_spanned! {span=> - .header(::http::header::#header_name, response.#field_name) + .header(ruma_api::exports::http::header::#header_name, response.#field_name) }) } else { None @@ -247,7 +247,7 @@ impl ToTokens for Response { quote_spanned! {span=> /// Data in the response body. - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, ruma_api::exports::serde::Deserialize, ruma_api::exports::serde::Serialize)] struct ResponseBody(#ty); } } else if self.has_body_fields() { @@ -264,7 +264,7 @@ impl ToTokens for Response { quote! { /// Data in the response body. - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, ruma_api::exports::serde::Deserialize, ruma_api::exports::serde::Serialize)] struct ResponseBody { #(#fields),* } diff --git a/ruma-api-macros/src/lib.rs b/ruma-api-macros/src/lib.rs index 909463c5..b87f0100 100644 --- a/ruma-api-macros/src/lib.rs +++ b/ruma-api-macros/src/lib.rs @@ -139,11 +139,10 @@ mod api; /// /// # Examples /// -/// ```rust,no_run +/// ```rust,ignore /// # fn main() { /// pub mod some_endpoint { /// use ruma_api_macros::ruma_api; -/// use serde::{Deserialize, Serialize}; /// /// ruma_api! { /// metadata { @@ -179,7 +178,6 @@ mod api; /// /// pub mod newtype_body_endpoint { /// use ruma_api_macros::ruma_api; -/// use serde::{Deserialize, Serialize}; /// /// #[derive(Clone, Debug, Deserialize, Serialize)] /// pub struct MyCustomType { diff --git a/src/lib.rs b/src/lib.rs index a1eae490..0c5f66ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,22 @@ use ruma_identifiers; use serde_json; use serde_urlencoded; +#[cfg(feature = "with-ruma-api-macros")] +pub use ruma_api_macros::ruma_api; + +#[cfg(feature = "with-ruma-api-macros")] +#[doc(hidden)] +/// This module is used to support the generated code from ruma-api-macros. +/// It is not considered part of ruma-api's public API. +pub mod exports { + pub use http; + pub use percent_encoding; + pub use serde; + pub use serde_json; + pub use serde_urlencoded; + pub use url; +} + /// A Matrix API endpoint. /// /// The type implementing this trait contains any data needed to make a request to the endpoint. diff --git a/ruma-api-macros/tests/ruma_api_macros.rs b/tests/ruma_api_macros.rs similarity index 66% rename from ruma-api-macros/tests/ruma_api_macros.rs rename to tests/ruma_api_macros.rs index 292f1c7a..40cc030e 100644 --- a/ruma-api-macros/tests/ruma_api_macros.rs +++ b/tests/ruma_api_macros.rs @@ -1,6 +1,5 @@ pub mod some_endpoint { - use ruma_api_macros::ruma_api; - use serde::{Deserialize, Serialize}; + use ruma_api::ruma_api; ruma_api! { metadata { @@ -40,3 +39,33 @@ pub mod some_endpoint { } } } + +pub mod newtype_body_endpoint { + use ruma_api_macros::ruma_api; + + #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] + pub struct MyCustomType { + pub foo: String, + } + + ruma_api! { + metadata { + description: "Does something.", + method: GET, + name: "newtype_body_endpoint", + path: "/_matrix/some/newtype/body/endpoint", + rate_limited: false, + requires_authentication: false, + } + + request { + #[ruma_api(body)] + pub file: Vec, + } + + response { + #[ruma_api(body)] + pub my_custom_type: MyCustomType, + } + } +}