From 6877c2f38d60c17f4e91a2a1fbb978fea911d8be Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Mon, 10 Aug 2020 16:34:14 -0400 Subject: [PATCH] Use ruma_api crate from ruma or if renamed or not in crate prelude --- ruma-api-macros/Cargo.toml | 1 + ruma-api-macros/src/api.rs | 101 ++++++++++++++++------------ ruma-api-macros/src/api/request.rs | 44 ++++++------ ruma-api-macros/src/api/response.rs | 31 ++++++--- 4 files changed, 105 insertions(+), 72 deletions(-) diff --git a/ruma-api-macros/Cargo.toml b/ruma-api-macros/Cargo.toml index 6738ed1d..05305904 100644 --- a/ruma-api-macros/Cargo.toml +++ b/ruma-api-macros/Cargo.toml @@ -19,6 +19,7 @@ edition = "2018" proc-macro2 = "1.0.19" quote = "1.0.7" syn = { version = "1.0.38", features = ["full", "extra-traits"] } +proc-macro-crate = "0.1.5" [lib] proc-macro = true diff --git a/ruma-api-macros/src/api.rs b/ruma-api-macros/src/api.rs index 4bdca48e..391ca02a 100644 --- a/ruma-api-macros/src/api.rs +++ b/ruma-api-macros/src/api.rs @@ -2,13 +2,14 @@ use std::convert::{TryFrom, TryInto as _}; -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; +use proc_macro_crate::crate_name; use quote::{quote, ToTokens}; use syn::{ braced, parse::{Parse, ParseStream}, spanned::Spanned, - Field, FieldValue, Token, Type, + Field, FieldValue, Ident, Token, Type, }; pub(crate) mod attribute; @@ -26,6 +27,15 @@ pub fn strip_serde_attrs(field: &Field) -> Field { field } +pub fn import_ruma_api() -> TokenStream { + if let Ok(name) = crate_name("ruma-api") { + let import = Ident::new(&name, Span::call_site()); + quote! { ::#import } + } else { + quote! { ::ruma_api } + } +} + /// The result of processing the `ruma_api` macro, ready for output back to source code. pub struct Api { /// The `metadata` section of the macro. @@ -82,6 +92,9 @@ impl TryFrom for Api { impl ToTokens for Api { fn to_tokens(&self, tokens: &mut TokenStream) { + // Guarantee `ruma_api` is available and named something we can refer to. + let ruma_api_import = import_ruma_api(); + let description = &self.metadata.description; let method = &self.metadata.method; // We don't (currently) use this literal as a literal in the generated code. Instead we just @@ -130,12 +143,12 @@ impl ToTokens for Api { let mut header_kvs = self.request.append_header_kvs(); if requires_authentication.value { header_kvs.push(quote! { - ::ruma_api::exports::http::header::AUTHORIZATION, - ::ruma_api::exports::http::header::HeaderValue::from_str( + #ruma_api_import::exports::http::header::AUTHORIZATION, + #ruma_api_import::exports::http::header::HeaderValue::from_str( &::std::format!( "Bearer {}", access_token.ok_or_else( - ::ruma_api::error::IntoHttpError::needs_authentication + #ruma_api_import::error::IntoHttpError::needs_authentication )? ) )? @@ -162,10 +175,10 @@ impl ToTokens for Api { TokenStream::new() }; quote! { - let request_body: ::Incoming = - ::ruma_api::try_deserialize!( + let request_body: ::Incoming = + #ruma_api_import::try_deserialize!( request, - ::ruma_api::exports::serde_json::from_slice(request.body().as_slice()) + #ruma_api_import::exports::serde_json::from_slice(request.body().as_slice()) ); } } else { @@ -190,18 +203,19 @@ impl ToTokens for Api { TokenStream::new() }; - let typed_response_body_decl = - if self.response.has_body_fields() || self.response.newtype_body_field().is_some() { - quote! { - let response_body: ::Incoming = - ::ruma_api::try_deserialize!( - response, - ::ruma_api::exports::serde_json::from_slice(response.body().as_slice()), - ); - } - } else { - TokenStream::new() - }; + let typed_response_body_decl = if self.response.has_body_fields() + || self.response.newtype_body_field().is_some() + { + quote! { + let response_body: ::Incoming = + #ruma_api_import::try_deserialize!( + response, + #ruma_api_import::exports::serde_json::from_slice(response.body().as_slice()), + ); + } + } else { + TokenStream::new() + }; let response_init_fields = self.response.init_fields(); @@ -224,22 +238,23 @@ impl ToTokens for Api { TokenStream::new() } else { quote! { - impl #request_lifetimes ::ruma_api::NonAuthEndpoint + impl #request_lifetimes #ruma_api_import::NonAuthEndpoint for Request #request_lifetimes {} } }; let api = quote! { + #[doc = #request_doc] #request_type - impl ::std::convert::TryFrom<::ruma_api::exports::http::Request>> for #request_try_from_type { - type Error = ::ruma_api::error::FromHttpRequestError; + impl ::std::convert::TryFrom<#ruma_api_import::exports::http::Request>> for #request_try_from_type { + type Error = #ruma_api_import::error::FromHttpRequestError; #[allow(unused_variables)] fn try_from( - request: ::ruma_api::exports::http::Request> + request: #ruma_api_import::exports::http::Request> ) -> ::std::result::Result { #extract_request_path #extract_request_query @@ -258,13 +273,13 @@ impl ToTokens for Api { #[doc = #response_doc] #response_type - impl ::std::convert::TryFrom for ::ruma_api::exports::http::Response> { - type Error = ::ruma_api::error::IntoHttpError; + impl ::std::convert::TryFrom for #ruma_api_import::exports::http::Response> { + type Error = #ruma_api_import::error::IntoHttpError; #[allow(unused_variables)] fn try_from(response: Response) -> ::std::result::Result { - let response = ::ruma_api::exports::http::Response::builder() - .header(::ruma_api::exports::http::header::CONTENT_TYPE, "application/json") + let response = #ruma_api_import::exports::http::Response::builder() + .header(#ruma_api_import::exports::http::header::CONTENT_TYPE, "application/json") #serialize_response_headers .body(#body) // Since we require header names to come from the `http::header` module, @@ -274,12 +289,12 @@ impl ToTokens for Api { } } - impl ::std::convert::TryFrom<::ruma_api::exports::http::Response>> for Response { - type Error = ::ruma_api::error::FromHttpResponseError<#error>; + impl ::std::convert::TryFrom<#ruma_api_import::exports::http::Response>> for Response { + type Error = #ruma_api_import::error::FromHttpResponseError<#error>; #[allow(unused_variables)] fn try_from( - response: ::ruma_api::exports::http::Response>, + response: #ruma_api_import::exports::http::Response>, ) -> ::std::result::Result { if response.status().as_u16() < 400 { #extract_response_headers @@ -290,26 +305,26 @@ impl ToTokens for Api { #response_init_fields }) } else { - match <#error as ::ruma_api::EndpointError>::try_from_response(response) { - Ok(err) => Err(::ruma_api::error::ServerError::Known(err).into()), + match <#error as #ruma_api_import::EndpointError>::try_from_response(response) { + Ok(err) => Err(#ruma_api_import::error::ServerError::Known(err).into()), Err(response_err) => { - Err(::ruma_api::error::ServerError::Unknown(response_err).into()) + Err(#ruma_api_import::error::ServerError::Unknown(response_err).into()) } } } } } - impl #request_lifetimes ::ruma_api::Endpoint for Request #request_lifetimes { + impl #request_lifetimes #ruma_api_import::Endpoint for Request #request_lifetimes { type Response = Response; type ResponseError = #error; - type IncomingRequest = ::Incoming; - type IncomingResponse = ::Incoming; + type IncomingRequest = ::Incoming; + type IncomingResponse = ::Incoming; /// Metadata for the `#name` endpoint. - const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata { + const METADATA: #ruma_api_import::Metadata = #ruma_api_import::Metadata { description: #description, - method: ::ruma_api::exports::http::Method::#method, + method: #ruma_api_import::exports::http::Method::#method, name: #name, path: #path, rate_limited: #rate_limited, @@ -322,13 +337,13 @@ impl ToTokens for Api { base_url: &::std::primitive::str, access_token: ::std::option::Option<&str>, ) -> ::std::result::Result< - ::ruma_api::exports::http::Request>, - ::ruma_api::error::IntoHttpError, + #ruma_api_import::exports::http::Request>, + #ruma_api_import::error::IntoHttpError, > { let metadata = Request::METADATA; - let http_request = ::ruma_api::exports::http::Request::builder() - .method(::ruma_api::exports::http::Method::#method) + let http_request = #ruma_api_import::exports::http::Request::builder() + .method(#ruma_api_import::exports::http::Method::#method) .uri(::std::format!( "{}{}{}", base_url.strip_suffix("/").unwrap_or(base_url), diff --git a/ruma-api-macros/src/api/request.rs b/ruma-api-macros/src/api/request.rs index 9b991bec..c2b576df 100644 --- a/ruma-api-macros/src/api/request.rs +++ b/ruma-api-macros/src/api/request.rs @@ -9,7 +9,7 @@ use syn::{spanned::Spanned, Field, Ident, Lifetime}; use crate::{ api::{ attribute::{Meta, MetaNameValue}, - strip_serde_attrs, RawRequest, + import_ruma_api, strip_serde_attrs, RawRequest, }, util, }; @@ -29,11 +29,15 @@ pub struct Request { /// The collected lifetime identifiers from the declared fields. lifetimes: RequestLifetimes, + + // Guarantee `ruma_api` is available and named something we can refer to. + ruma_api_import: TokenStream, } impl Request { /// Produces code to add necessary HTTP headers to an `http::Request`. pub fn append_header_kvs(&self) -> Vec { + let ruma_api = &self.ruma_api_import; self.header_fields().map(|request_field| { let (field, header_name) = match request_field { RequestField::Header(field, header_name) => (field, header_name), @@ -43,14 +47,15 @@ impl Request { let field_name = &field.ident; quote! { - ::ruma_api::exports::http::header::#header_name, - ::ruma_api::exports::http::header::HeaderValue::from_str(self.#field_name.as_ref())? + #ruma_api::exports::http::header::#header_name, + #ruma_api::exports::http::header::HeaderValue::from_str(self.#field_name.as_ref())? } }).collect() } /// Produces code to extract fields from the HTTP headers in an `http::Request`. pub fn parse_headers_from_request(&self) -> TokenStream { + let ruma_api = &self.ruma_api_import; let fields = self.header_fields().map(|request_field| { let (field, header_name) = match request_field { RequestField::Header(field, header_name) => (field, header_name), @@ -62,16 +67,16 @@ impl Request { quote! { #field_name: match headers - .get(::ruma_api::exports::http::header::#header_name) + .get(#ruma_api::exports::http::header::#header_name) .and_then(|v| v.to_str().ok()) // FIXME: Should have a distinct error message { Some(header) => header.to_owned(), None => { - use ::ruma_api::exports::serde::de::Error as _; + use #ruma_api::exports::serde::de::Error as _; // FIXME: Not a missing json field, a missing header! - return Err(::ruma_api::error::RequestDeserializationError::new( - ::ruma_api::exports::serde_json::Error::missing_field( + return Err(#ruma_api::error::RequestDeserializationError::new( + #ruma_api::exports::serde_json::Error::missing_field( #header_name_string ), request, @@ -377,12 +382,13 @@ impl TryFrom for Request { )); } - Ok(Self { fields, lifetimes }) + Ok(Self { fields, lifetimes, ruma_api_import: import_ruma_api() }) } } impl ToTokens for Request { fn to_tokens(&self, tokens: &mut TokenStream) { + let ruma_api = &self.ruma_api_import; let request_def = if self.fields.is_empty() { quote!(;) } else { @@ -403,7 +409,7 @@ impl ToTokens for Request { let (derive_deserialize, lifetimes) = if self.has_body_lifetimes() { (TokenStream::new(), self.body_lifetimes()) } else { - (quote!(::ruma_api::exports::serde::Deserialize), TokenStream::new()) + (quote!(#ruma_api::exports::serde::Deserialize), TokenStream::new()) }; Some((derive_deserialize, quote! { #lifetimes (#field); })) @@ -412,7 +418,7 @@ impl ToTokens for Request { let (derive_deserialize, lifetimes) = if self.has_body_lifetimes() { (TokenStream::new(), self.body_lifetimes()) } else { - (quote!(::ruma_api::exports::serde::Deserialize), TokenStream::new()) + (quote!(#ruma_api::exports::serde::Deserialize), TokenStream::new()) }; let fields = fields.map(RequestField::field); @@ -425,8 +431,8 @@ impl ToTokens for Request { /// Data in the request body. #[derive( Debug, - ::ruma_api::Outgoing, - ::ruma_api::exports::serde::Serialize, + #ruma_api::Outgoing, + #ruma_api::exports::serde::Serialize, #derive_deserialize )] struct RequestBody #def @@ -438,15 +444,15 @@ impl ToTokens for Request { let (derive_deserialize, lifetime) = if self.has_query_lifetimes() { (TokenStream::new(), self.query_lifetimes()) } else { - (quote!(::ruma_api::exports::serde::Deserialize), TokenStream::new()) + (quote!(#ruma_api::exports::serde::Deserialize), TokenStream::new()) }; quote! { /// Data in the request's query string. #[derive( Debug, - ::ruma_api::Outgoing, - ::ruma_api::exports::serde::Serialize, + #ruma_api::Outgoing, + #ruma_api::exports::serde::Serialize, #derive_deserialize )] struct RequestQuery #lifetime (#field); @@ -456,15 +462,15 @@ impl ToTokens for Request { let (derive_deserialize, lifetime) = if self.has_query_lifetimes() { (TokenStream::new(), self.query_lifetimes()) } else { - (quote!(::ruma_api::exports::serde::Deserialize), TokenStream::new()) + (quote!(#ruma_api::exports::serde::Deserialize), TokenStream::new()) }; quote! { /// Data in the request's query string. #[derive( Debug, - ::ruma_api::Outgoing, - ::ruma_api::exports::serde::Serialize, + #ruma_api::Outgoing, + #ruma_api::exports::serde::Serialize, #derive_deserialize )] struct RequestQuery #lifetime { @@ -476,7 +482,7 @@ impl ToTokens for Request { }; let request = quote! { - #[derive(Debug, Clone, ::ruma_api::Outgoing)] + #[derive(Debug, Clone, #ruma_api::Outgoing)] #[incoming_no_deserialize] pub struct Request #request_generics #request_def diff --git a/ruma-api-macros/src/api/response.rs b/ruma-api-macros/src/api/response.rs index 47e9f05e..597ae484 100644 --- a/ruma-api-macros/src/api/response.rs +++ b/ruma-api-macros/src/api/response.rs @@ -9,7 +9,7 @@ use syn::{spanned::Spanned, Field, Ident}; use crate::{ api::{ attribute::{Meta, MetaNameValue}, - strip_serde_attrs, RawResponse, + import_ruma_api, strip_serde_attrs, RawResponse, }, util, }; @@ -18,6 +18,9 @@ use crate::{ pub struct Response { /// The fields of the response. fields: Vec, + + // Guarantee `ruma_api` is available and named something we can refer to. + ruma_api_import: TokenStream, } impl Response { @@ -33,6 +36,8 @@ impl Response { /// Produces code for a response struct initializer. pub fn init_fields(&self) -> TokenStream { + let ruma_api = &self.ruma_api_import; + let mut fields = vec![]; let mut new_type_raw_body = None; for response_field in &self.fields { @@ -51,9 +56,9 @@ impl Response { } ResponseField::Header(_, header_name) => { quote_spanned! {span=> - #field_name: ::ruma_api::try_deserialize!( + #field_name: #ruma_api::try_deserialize!( response, - headers.remove(::ruma_api::exports::http::header::#header_name) + headers.remove(#ruma_api::exports::http::header::#header_name) .expect("response missing expected header") .to_str() ) @@ -86,6 +91,8 @@ impl Response { /// Produces code to add necessary HTTP headers to an `http::Response`. pub fn apply_header_fields(&self) -> TokenStream { + let ruma_api = &self.ruma_api_import; + let header_calls = self.fields.iter().filter_map(|response_field| { if let ResponseField::Header(ref field, ref header_name) = *response_field { let field_name = @@ -93,7 +100,7 @@ impl Response { let span = field.span(); Some(quote_spanned! {span=> - .header(::ruma_api::exports::http::header::#header_name, response.#field_name) + .header(#ruma_api::exports::http::header::#header_name, response.#field_name) }) } else { None @@ -105,6 +112,8 @@ impl Response { /// Produces code to initialize the struct that will be used to create the response body. pub fn to_body(&self) -> TokenStream { + let ruma_api = &self.ruma_api_import; + if let Some(field) = self.newtype_raw_body_field() { let field_name = field.ident.as_ref().expect("expected field to have an identifier"); let span = field.span(); @@ -138,7 +147,7 @@ impl Response { } }; - quote!(::ruma_api::exports::serde_json::to_vec(&#body)?) + quote!(#ruma_api::exports::serde_json::to_vec(&#body)?) } /// Gets the newtype body field, if this response has one. @@ -225,12 +234,14 @@ impl TryFrom for Response { )); } - Ok(Self { fields }) + Ok(Self { fields, ruma_api_import: import_ruma_api() }) } } impl ToTokens for Response { fn to_tokens(&self, tokens: &mut TokenStream) { + let ruma_api = &self.ruma_api_import; + let response_def = if self.fields.is_empty() { quote!(;) } else { @@ -258,15 +269,15 @@ impl ToTokens for Response { /// Data in the response body. #[derive( Debug, - ::ruma_api::Outgoing, - ::ruma_api::exports::serde::Deserialize, - ::ruma_api::exports::serde::Serialize, + #ruma_api::Outgoing, + #ruma_api::exports::serde::Deserialize, + #ruma_api::exports::serde::Serialize, )] struct ResponseBody #def }; let response = quote! { - #[derive(Debug, Clone, ::ruma_api::Outgoing)] + #[derive(Debug, Clone, #ruma_api::Outgoing)] #[incoming_no_deserialize] pub struct Response #response_def