Add rustfmt and clippy to CI and address clippy warnings.
This commit is contained in:
parent
a92e71f873
commit
6a09f1f754
@ -1 +0,0 @@
|
|||||||
merge_imports = true
|
|
@ -1,4 +1,12 @@
|
|||||||
language: "rust"
|
language: "rust"
|
||||||
|
before_script:
|
||||||
|
- "rustup component add rustfmt"
|
||||||
|
- "rustup component add clippy"
|
||||||
|
script:
|
||||||
|
- "cargo fmt --all -- --check"
|
||||||
|
- "cargo clippy --all-targets --all-features -- -D warnings"
|
||||||
|
- "cargo build --verbose"
|
||||||
|
- "cargo test --verbose"
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
irc:
|
irc:
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
|
//! Details of the `metadata` section of the procedural macro.
|
||||||
|
|
||||||
use syn::{punctuated::Pair, Expr, FieldValue, Lit, Member};
|
use syn::{punctuated::Pair, Expr, FieldValue, Lit, Member};
|
||||||
|
|
||||||
|
/// The result of processing the `metadata` section of the macro.
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
|
/// The description field.
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
/// The method field.
|
||||||
pub method: String,
|
pub method: String,
|
||||||
|
/// The name field.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// The path field.
|
||||||
pub path: String,
|
pub path: String,
|
||||||
|
/// The rate_limited field.
|
||||||
pub rate_limited: bool,
|
pub rate_limited: bool,
|
||||||
|
/// The description field.
|
||||||
pub requires_authentication: bool,
|
pub requires_authentication: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +110,7 @@ impl From<Vec<FieldValue>> for Metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Metadata {
|
Self {
|
||||||
description: description.expect("ruma_api! `metadata` is missing `description`"),
|
description: description.expect("ruma_api! `metadata` is missing `description`"),
|
||||||
method: method.expect("ruma_api! `metadata` is missing `method`"),
|
method: method.expect("ruma_api! `metadata` is missing `method`"),
|
||||||
name: name.expect("ruma_api! `metadata` is missing `name`"),
|
name: name.expect("ruma_api! `metadata` is missing `name`"),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Details of the `ruma-api` procedural macro.
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::{
|
use syn::{
|
||||||
@ -12,6 +14,7 @@ mod response;
|
|||||||
|
|
||||||
use self::{metadata::Metadata, request::Request, response::Response};
|
use self::{metadata::Metadata, request::Request, response::Response};
|
||||||
|
|
||||||
|
/// Removes `serde` attributes from struct fields.
|
||||||
pub fn strip_serde_attrs(field: &Field) -> Field {
|
pub fn strip_serde_attrs(field: &Field) -> Field {
|
||||||
let mut field = field.clone();
|
let mut field = field.clone();
|
||||||
|
|
||||||
@ -39,15 +42,19 @@ pub fn strip_serde_attrs(field: &Field) -> Field {
|
|||||||
field
|
field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of processing the `ruma_api` macro, ready for output back to source code.
|
||||||
pub struct Api {
|
pub struct Api {
|
||||||
|
/// The `metadata` section of the macro.
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
|
/// The `request` section of the macro.
|
||||||
request: Request,
|
request: Request,
|
||||||
|
/// The `response` section of the macro.
|
||||||
response: Response,
|
response: Response,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RawApi> for Api {
|
impl From<RawApi> for Api {
|
||||||
fn from(raw_api: RawApi) -> Self {
|
fn from(raw_api: RawApi) -> Self {
|
||||||
Api {
|
Self {
|
||||||
metadata: raw_api.metadata.into(),
|
metadata: raw_api.metadata.into(),
|
||||||
request: raw_api.request.into(),
|
request: raw_api.request.into(),
|
||||||
response: raw_api.response.into(),
|
response: raw_api.response.into(),
|
||||||
@ -88,7 +95,7 @@ impl ToTokens for Api {
|
|||||||
|
|
||||||
let request_path_init_fields = self.request.request_path_init_fields();
|
let request_path_init_fields = self.request.request_path_init_fields();
|
||||||
|
|
||||||
let path_segments = path_str[1..].split('/').into_iter();
|
let path_segments = path_str[1..].split('/');
|
||||||
let path_segment_push = path_segments.clone().map(|segment| {
|
let path_segment_push = path_segments.clone().map(|segment| {
|
||||||
let arg = if segment.starts_with(':') {
|
let arg = if segment.starts_with(':') {
|
||||||
let path_var = &segment[1..];
|
let path_var = &segment[1..];
|
||||||
@ -450,6 +457,7 @@ impl ToTokens for Api {
|
|||||||
type Request = Request;
|
type Request = Request;
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
|
|
||||||
|
/// Metadata for this endpoint.
|
||||||
const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata {
|
const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata {
|
||||||
description: #description,
|
description: #description,
|
||||||
method: ::http::Method::#method,
|
method: ::http::Method::#method,
|
||||||
@ -465,6 +473,7 @@ impl ToTokens for Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Custom keyword macros for syn.
|
||||||
mod kw {
|
mod kw {
|
||||||
use syn::custom_keyword;
|
use syn::custom_keyword;
|
||||||
|
|
||||||
@ -473,9 +482,13 @@ mod kw {
|
|||||||
custom_keyword!(response);
|
custom_keyword!(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The entire `ruma_api!` macro structure directly as it appears in the source code..
|
||||||
pub struct RawApi {
|
pub struct RawApi {
|
||||||
|
/// The `metadata` section of the macro.
|
||||||
pub metadata: Vec<FieldValue>,
|
pub metadata: Vec<FieldValue>,
|
||||||
|
/// The `request` section of the macro.
|
||||||
pub request: Vec<Field>,
|
pub request: Vec<Field>,
|
||||||
|
/// The `response` section of the macro.
|
||||||
pub response: Vec<Field>,
|
pub response: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +506,7 @@ impl Parse for RawApi {
|
|||||||
let response;
|
let response;
|
||||||
braced!(response in input);
|
braced!(response in input);
|
||||||
|
|
||||||
Ok(RawApi {
|
Ok(Self {
|
||||||
metadata: metadata
|
metadata: metadata
|
||||||
.parse_terminated::<FieldValue, Token![,]>(FieldValue::parse)?
|
.parse_terminated::<FieldValue, Token![,]>(FieldValue::parse)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
|
//! Details of the `request` section of the procedural macro.
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, quote_spanned, ToTokens};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::{spanned::Spanned, Field, Ident, Lit, Meta, NestedMeta};
|
use syn::{spanned::Spanned, Field, Ident, Lit, Meta, NestedMeta};
|
||||||
|
|
||||||
use crate::api::strip_serde_attrs;
|
use crate::api::strip_serde_attrs;
|
||||||
|
|
||||||
|
/// The result of processing the `request` section of the macro.
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
|
/// The fields of the request.
|
||||||
fields: Vec<RequestField>,
|
fields: Vec<RequestField>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
|
/// Produces code to add necessary HTTP headers to an `http::Request`.
|
||||||
pub fn add_headers_to_request(&self) -> TokenStream {
|
pub fn add_headers_to_request(&self) -> TokenStream {
|
||||||
let append_stmts = self.header_fields().map(|request_field| {
|
let append_stmts = self.header_fields().map(|request_field| {
|
||||||
let (field, header_name_string) = match request_field {
|
let (field, header_name_string) = match request_field {
|
||||||
@ -33,6 +38,7 @@ impl Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code to extract fields from the HTTP headers in an `http::Request`.
|
||||||
pub fn parse_headers_from_request(&self) -> TokenStream {
|
pub fn parse_headers_from_request(&self) -> TokenStream {
|
||||||
let fields = self.header_fields().map(|request_field| {
|
let fields = self.header_fields().map(|request_field| {
|
||||||
let (field, header_name_string) = match request_field {
|
let (field, header_name_string) = match request_field {
|
||||||
@ -56,43 +62,50 @@ impl Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request has any data in the HTTP body.
|
||||||
pub fn has_body_fields(&self) -> bool {
|
pub fn has_body_fields(&self) -> bool {
|
||||||
self.fields.iter().any(|field| field.is_body())
|
self.fields.iter().any(|field| field.is_body())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request has any data in HTTP headers.
|
||||||
pub fn has_header_fields(&self) -> bool {
|
pub fn has_header_fields(&self) -> bool {
|
||||||
self.fields.iter().any(|field| field.is_header())
|
self.fields.iter().any(|field| field.is_header())
|
||||||
}
|
}
|
||||||
|
/// Whether or not this request has any data in the URL path.
|
||||||
pub fn has_path_fields(&self) -> bool {
|
pub fn has_path_fields(&self) -> bool {
|
||||||
self.fields.iter().any(|field| field.is_path())
|
self.fields.iter().any(|field| field.is_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request has any data in the query string.
|
||||||
pub fn has_query_fields(&self) -> bool {
|
pub fn has_query_fields(&self) -> bool {
|
||||||
self.fields.iter().any(|field| field.is_query())
|
self.fields.iter().any(|field| field.is_query())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces an iterator over all the header fields.
|
||||||
pub fn header_fields(&self) -> impl Iterator<Item = &RequestField> {
|
pub fn header_fields(&self) -> impl Iterator<Item = &RequestField> {
|
||||||
self.fields.iter().filter(|field| field.is_header())
|
self.fields.iter().filter(|field| field.is_header())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the number of path fields.
|
||||||
pub fn path_field_count(&self) -> usize {
|
pub fn path_field_count(&self) -> usize {
|
||||||
self.fields.iter().filter(|field| field.is_path()).count()
|
self.fields.iter().filter(|field| field.is_path()).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the path field with the given name.
|
||||||
pub fn path_field(&self, name: &str) -> Option<&Field> {
|
pub fn path_field(&self, name: &str) -> Option<&Field> {
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|f| f.field_(RequestFieldKind::Path))
|
.flat_map(|f| f.field_of_kind(RequestFieldKind::Path))
|
||||||
.find(|field| {
|
.find(|field| {
|
||||||
field
|
field
|
||||||
.ident
|
.ident
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("expected field to have an identifier")
|
.expect("expected field to have an identifier")
|
||||||
.to_string()
|
|
||||||
== name
|
== name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the body field.
|
||||||
pub fn newtype_body_field(&self) -> Option<&Field> {
|
pub fn newtype_body_field(&self) -> Option<&Field> {
|
||||||
for request_field in self.fields.iter() {
|
for request_field in self.fields.iter() {
|
||||||
match *request_field {
|
match *request_field {
|
||||||
@ -106,33 +119,41 @@ impl Request {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a struct initializer for body fields on a variable named `request`.
|
||||||
pub fn request_body_init_fields(&self) -> TokenStream {
|
pub fn request_body_init_fields(&self) -> TokenStream {
|
||||||
self.struct_init_fields(RequestFieldKind::Body, quote!(request))
|
self.struct_init_fields(RequestFieldKind::Body, quote!(request))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a struct initializer for path fields on a variable named `request`.
|
||||||
pub fn request_path_init_fields(&self) -> TokenStream {
|
pub fn request_path_init_fields(&self) -> TokenStream {
|
||||||
self.struct_init_fields(RequestFieldKind::Path, quote!(request))
|
self.struct_init_fields(RequestFieldKind::Path, quote!(request))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a struct initializer for query string fields on a variable named `request`.
|
||||||
pub fn request_query_init_fields(&self) -> TokenStream {
|
pub fn request_query_init_fields(&self) -> TokenStream {
|
||||||
self.struct_init_fields(RequestFieldKind::Query, quote!(request))
|
self.struct_init_fields(RequestFieldKind::Query, quote!(request))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a struct initializer for body fields on a variable named `request_body`.
|
||||||
pub fn request_init_body_fields(&self) -> TokenStream {
|
pub fn request_init_body_fields(&self) -> TokenStream {
|
||||||
self.struct_init_fields(RequestFieldKind::Body, quote!(request_body))
|
self.struct_init_fields(RequestFieldKind::Body, quote!(request_body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a struct initializer for query string fields on a variable named
|
||||||
|
/// `request_query`.
|
||||||
pub fn request_init_query_fields(&self) -> TokenStream {
|
pub fn request_init_query_fields(&self) -> TokenStream {
|
||||||
self.struct_init_fields(RequestFieldKind::Query, quote!(request_query))
|
self.struct_init_fields(RequestFieldKind::Query, quote!(request_query))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a struct initializer for the given field kind to be accessed through the
|
||||||
|
/// given variable name.
|
||||||
fn struct_init_fields(
|
fn struct_init_fields(
|
||||||
&self,
|
&self,
|
||||||
request_field_kind: RequestFieldKind,
|
request_field_kind: RequestFieldKind,
|
||||||
src: TokenStream,
|
src: TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let fields = self.fields.iter().filter_map(|f| {
|
let fields = self.fields.iter().filter_map(|f| {
|
||||||
f.field_(request_field_kind).map(|field| {
|
f.field_of_kind(request_field_kind).map(|field| {
|
||||||
let field_name = field
|
let field_name = field
|
||||||
.ident
|
.ident
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -222,7 +243,7 @@ impl From<Vec<Field>> for Request {
|
|||||||
RequestField::new(field_kind, field, header)
|
RequestField::new(field_kind, field, header)
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
Request { fields }
|
Self { fields }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,16 +366,23 @@ impl ToTokens for Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The types of fields that a request can have.
|
||||||
pub enum RequestField {
|
pub enum RequestField {
|
||||||
|
/// JSON data in the body of the request.
|
||||||
Body(Field),
|
Body(Field),
|
||||||
|
/// Data in an HTTP header.
|
||||||
Header(Field, String),
|
Header(Field, String),
|
||||||
|
/// A specific data type in the body of the request.
|
||||||
NewtypeBody(Field),
|
NewtypeBody(Field),
|
||||||
|
/// Data that appears in the URL path.
|
||||||
Path(Field),
|
Path(Field),
|
||||||
|
/// Data that appears in the query string.
|
||||||
Query(Field),
|
Query(Field),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RequestField {
|
impl RequestField {
|
||||||
fn new(kind: RequestFieldKind, field: Field, header: Option<String>) -> RequestField {
|
/// Creates a new `RequestField`.
|
||||||
|
fn new(kind: RequestFieldKind, field: Field, header: Option<String>) -> Self {
|
||||||
match kind {
|
match kind {
|
||||||
RequestFieldKind::Body => RequestField::Body(field),
|
RequestFieldKind::Body => RequestField::Body(field),
|
||||||
RequestFieldKind::Header => {
|
RequestFieldKind::Header => {
|
||||||
@ -366,6 +394,7 @@ impl RequestField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the kind of the request field.
|
||||||
fn kind(&self) -> RequestFieldKind {
|
fn kind(&self) -> RequestFieldKind {
|
||||||
match *self {
|
match *self {
|
||||||
RequestField::Body(..) => RequestFieldKind::Body,
|
RequestField::Body(..) => RequestFieldKind::Body,
|
||||||
@ -376,33 +405,39 @@ impl RequestField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request field is a body kind.
|
||||||
fn is_body(&self) -> bool {
|
fn is_body(&self) -> bool {
|
||||||
self.kind() == RequestFieldKind::Body
|
self.kind() == RequestFieldKind::Body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request field is a header kind.
|
||||||
fn is_header(&self) -> bool {
|
fn is_header(&self) -> bool {
|
||||||
self.kind() == RequestFieldKind::Header
|
self.kind() == RequestFieldKind::Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request field is a path kind.
|
||||||
fn is_path(&self) -> bool {
|
fn is_path(&self) -> bool {
|
||||||
self.kind() == RequestFieldKind::Path
|
self.kind() == RequestFieldKind::Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this request field is a query string kind.
|
||||||
fn is_query(&self) -> bool {
|
fn is_query(&self) -> bool {
|
||||||
self.kind() == RequestFieldKind::Query
|
self.kind() == RequestFieldKind::Query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the inner `Field` value.
|
||||||
fn field(&self) -> &Field {
|
fn field(&self) -> &Field {
|
||||||
match *self {
|
match *self {
|
||||||
RequestField::Body(ref field) => field,
|
RequestField::Body(ref field)
|
||||||
RequestField::Header(ref field, _) => field,
|
| RequestField::Header(ref field, _)
|
||||||
RequestField::NewtypeBody(ref field) => field,
|
| RequestField::NewtypeBody(ref field)
|
||||||
RequestField::Path(ref field) => field,
|
| RequestField::Path(ref field)
|
||||||
RequestField::Query(ref field) => field,
|
| RequestField::Query(ref field) => field,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn field_(&self, kind: RequestFieldKind) -> Option<&Field> {
|
/// Gets the inner `Field` value if it's of the provided kind.
|
||||||
|
fn field_of_kind(&self, kind: RequestFieldKind) -> Option<&Field> {
|
||||||
if self.kind() == kind {
|
if self.kind() == kind {
|
||||||
Some(self.field())
|
Some(self.field())
|
||||||
} else {
|
} else {
|
||||||
@ -411,11 +446,17 @@ impl RequestField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The types of fields that a request can have, without their values.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
enum RequestFieldKind {
|
enum RequestFieldKind {
|
||||||
|
/// See the similarly named variant of `RequestField`.
|
||||||
Body,
|
Body,
|
||||||
|
/// See the similarly named variant of `RequestField`.
|
||||||
Header,
|
Header,
|
||||||
|
/// See the similarly named variant of `RequestField`.
|
||||||
NewtypeBody,
|
NewtypeBody,
|
||||||
|
/// See the similarly named variant of `RequestField`.
|
||||||
Path,
|
Path,
|
||||||
|
/// See the similarly named variant of `RequestField`.
|
||||||
Query,
|
Query,
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,39 @@
|
|||||||
|
//! Details of the `response` section of the procedural macro.
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, quote_spanned, ToTokens};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::{spanned::Spanned, Field, Ident, Lit, Meta, NestedMeta};
|
use syn::{spanned::Spanned, Field, Ident, Lit, Meta, NestedMeta};
|
||||||
|
|
||||||
use crate::api::strip_serde_attrs;
|
use crate::api::strip_serde_attrs;
|
||||||
|
|
||||||
|
/// The result of processing the `request` section of the macro.
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
|
/// The fields of the response.
|
||||||
fields: Vec<ResponseField>,
|
fields: Vec<ResponseField>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
|
/// Whether or not this response has any data in the HTTP body.
|
||||||
pub fn has_body_fields(&self) -> bool {
|
pub fn has_body_fields(&self) -> bool {
|
||||||
self.fields.iter().any(|field| field.is_body())
|
self.fields.iter().any(|field| field.is_body())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this response has any fields.
|
||||||
pub fn has_fields(&self) -> bool {
|
pub fn has_fields(&self) -> bool {
|
||||||
!self.fields.is_empty()
|
!self.fields.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this response has any data in HTTP headers.
|
||||||
pub fn has_header_fields(&self) -> bool {
|
pub fn has_header_fields(&self) -> bool {
|
||||||
self.fields.iter().any(|field| field.is_header())
|
self.fields.iter().any(|field| field.is_header())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this response has any data in the HTTP body.
|
||||||
pub fn has_body(&self) -> bool {
|
pub fn has_body(&self) -> bool {
|
||||||
self.fields.iter().any(|field| !field.is_header())
|
self.fields.iter().any(|field| !field.is_header())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code for a request struct initializer.
|
||||||
pub fn init_fields(&self) -> TokenStream {
|
pub fn init_fields(&self) -> TokenStream {
|
||||||
let fields = self
|
let fields = self
|
||||||
.fields
|
.fields
|
||||||
@ -75,6 +84,7 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code to add necessary HTTP headers to an `http::Response`.
|
||||||
pub fn apply_header_fields(&self) -> TokenStream {
|
pub fn apply_header_fields(&self) -> TokenStream {
|
||||||
let header_calls = self.fields.iter().filter_map(|response_field| {
|
let header_calls = self.fields.iter().filter_map(|response_field| {
|
||||||
if let ResponseField::Header(ref field, ref header) = *response_field {
|
if let ResponseField::Header(ref field, ref header) = *response_field {
|
||||||
@ -98,8 +108,9 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces code to initialize the struct that will be used to create the response body.
|
||||||
pub fn to_body(&self) -> TokenStream {
|
pub fn to_body(&self) -> TokenStream {
|
||||||
if let Some(ref field) = self.newtype_body_field() {
|
if let Some(field) = self.newtype_body_field() {
|
||||||
let field_name = field
|
let field_name = field
|
||||||
.ident
|
.ident
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -131,6 +142,7 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the newtype body field, if this request has one.
|
||||||
pub fn newtype_body_field(&self) -> Option<&Field> {
|
pub fn newtype_body_field(&self) -> Option<&Field> {
|
||||||
for response_field in self.fields.iter() {
|
for response_field in self.fields.iter() {
|
||||||
match *response_field {
|
match *response_field {
|
||||||
@ -217,7 +229,7 @@ impl From<Vec<Field>> for Response {
|
|||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
Response { fields }
|
Self { fields }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,28 +303,35 @@ impl ToTokens for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The types of fields that a response can have.
|
||||||
pub enum ResponseField {
|
pub enum ResponseField {
|
||||||
|
/// JSON data in the body of the response.
|
||||||
Body(Field),
|
Body(Field),
|
||||||
|
/// Data in an HTTP header.
|
||||||
Header(Field, String),
|
Header(Field, String),
|
||||||
|
/// A specific data type in the body of the response.
|
||||||
NewtypeBody(Field),
|
NewtypeBody(Field),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseField {
|
impl ResponseField {
|
||||||
|
/// Gets the inner `Field` value.
|
||||||
fn field(&self) -> &Field {
|
fn field(&self) -> &Field {
|
||||||
match *self {
|
match *self {
|
||||||
ResponseField::Body(ref field) => field,
|
ResponseField::Body(ref field)
|
||||||
ResponseField::Header(ref field, _) => field,
|
| ResponseField::Header(ref field, _)
|
||||||
ResponseField::NewtypeBody(ref field) => field,
|
| ResponseField::NewtypeBody(ref field) => field,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this response field is a body kind.
|
||||||
fn is_body(&self) -> bool {
|
fn is_body(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
ResponseField::Body(..) => true,
|
ResponseField::Body(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not this response field is a header kind.
|
||||||
fn is_header(&self) -> bool {
|
fn is_header(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
ResponseField::Header(..) => true,
|
ResponseField::Header(..) => true,
|
||||||
@ -321,8 +340,12 @@ impl ResponseField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The types of fields that a response can have, without their values.
|
||||||
enum ResponseFieldKind {
|
enum ResponseFieldKind {
|
||||||
|
/// See the similarly named variant of `ResponseField`.
|
||||||
Body,
|
Body,
|
||||||
|
/// See the similarly named variant of `ResponseField`.
|
||||||
Header,
|
Header,
|
||||||
|
/// See the similarly named variant of `ResponseField`.
|
||||||
NewtypeBody,
|
NewtypeBody,
|
||||||
}
|
}
|
||||||
|
26
src/lib.rs
26
src/lib.rs
@ -3,7 +3,31 @@
|
|||||||
//!
|
//!
|
||||||
//! See the documentation for the `ruma_api!` macro for usage details.
|
//! See the documentation for the `ruma_api!` macro for usage details.
|
||||||
|
|
||||||
#![deny(missing_debug_implementations)]
|
#![deny(
|
||||||
|
missing_copy_implementations,
|
||||||
|
missing_debug_implementations,
|
||||||
|
// missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
|
||||||
|
warnings
|
||||||
|
)]
|
||||||
|
#![warn(
|
||||||
|
clippy::empty_line_after_outer_attr,
|
||||||
|
clippy::expl_impl_clone_on_copy,
|
||||||
|
clippy::if_not_else,
|
||||||
|
clippy::items_after_statements,
|
||||||
|
clippy::match_same_arms,
|
||||||
|
clippy::mem_forget,
|
||||||
|
clippy::missing_docs_in_private_items,
|
||||||
|
clippy::multiple_inherent_impl,
|
||||||
|
clippy::mut_mut,
|
||||||
|
clippy::needless_borrow,
|
||||||
|
clippy::needless_continue,
|
||||||
|
clippy::single_match_else,
|
||||||
|
clippy::unicode_not_nfc,
|
||||||
|
clippy::use_self,
|
||||||
|
clippy::used_underscore_binding,
|
||||||
|
clippy::wrong_pub_self_convention,
|
||||||
|
clippy::wrong_self_convention
|
||||||
|
)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user