Outgoing derive: Replace incoming_no_deserialize with incoming_derive(!Deserialize)

This commit is contained in:
Jonas Platte 2020-08-17 22:08:56 +02:00
parent a1ee6c74c0
commit 30a0a39d2b
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
8 changed files with 70 additions and 35 deletions

View File

@ -494,7 +494,7 @@ impl ToTokens for Request {
let request = quote! { let request = quote! {
#[derive(Debug, Clone, #import_path::Outgoing)] #[derive(Debug, Clone, #import_path::Outgoing)]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
#( #struct_attributes )* #( #struct_attributes )*
pub struct Request #request_generics #request_def pub struct Request #request_generics #request_def

View File

@ -283,7 +283,7 @@ impl ToTokens for Response {
let response = quote! { let response = quote! {
#[derive(Debug, Clone, #import_path::Outgoing)] #[derive(Debug, Clone, #import_path::Outgoing)]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
#( #struct_attributes )* #( #struct_attributes )*
pub struct Response #response_def pub struct Response #response_def

View File

@ -1,10 +1,12 @@
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use syn::{ use syn::{
parse_quote, AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields, parse::{Parse, ParseStream},
GenericArgument, GenericParam, Generics, ImplGenerics, Meta, MetaList, parse_quote,
ParenthesizedGenericArguments, PathArguments, Type, TypeGenerics, TypePath, TypeReference, punctuated::Punctuated,
TypeSlice, Variant, AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields, GenericArgument,
GenericParam, Generics, Ident, ImplGenerics, ParenthesizedGenericArguments, PathArguments,
Token, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant,
}; };
use crate::util::import_ruma_api; use crate::util::import_ruma_api;
@ -24,29 +26,28 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
let import_path = import_ruma_api(); let import_path = import_ruma_api();
let mut derives = vec![quote! { Debug }]; let mut derives = vec![quote! { Debug }];
if !no_deserialize_in_attrs(&input.attrs) { let mut derive_deserialize = true;
derives.push(quote! { #import_path::exports::serde::Deserialize });
}
derives.extend( derives.extend(
input input
.attrs .attrs
.iter() .iter()
.filter(|attr| attr.path.is_ident("incoming_derive")) .filter(|attr| attr.path.is_ident("incoming_derive"))
.map(|attr| { .map(|attr| attr.parse_args())
let meta = attr.parse_meta()?; .collect::<syn::Result<Vec<Meta>>>()?
match meta {
Meta::List(MetaList { nested, .. }) => Ok(nested),
_ => Err(syn::Error::new_spanned(
meta,
"incoming_derive should be used as `#[incoming_derive(A, B, C)]`",
)),
}
})
.collect::<syn::Result<Vec<_>>>()?
.into_iter() .into_iter()
.flatten() .flat_map(|meta| meta.derive_macs)
.map(|derive_mac| quote! { #derive_mac }), .filter_map(|derive_mac| match derive_mac {
DeriveMac::Regular(id) => Some(quote! { #id }),
DeriveMac::NegativeDeserialize => {
derive_deserialize = false;
None
}
}),
); );
if derive_deserialize {
derives.push(quote! { #import_path::exports::serde::Deserialize });
}
let input_attrs = let input_attrs =
input.attrs.iter().filter(|attr| filter_input_attrs(attr)).collect::<Vec<_>>(); input.attrs.iter().filter(|attr| filter_input_attrs(attr)).collect::<Vec<_>>();
@ -149,10 +150,6 @@ fn filter_input_attrs(attr: &Attribute) -> bool {
attr.path.is_ident("serde") || attr.path.is_ident("non_exhaustive") attr.path.is_ident("serde") || attr.path.is_ident("non_exhaustive")
} }
fn no_deserialize_in_attrs(attrs: &[Attribute]) -> bool {
attrs.iter().any(|attr| attr.path.is_ident("incoming_no_deserialize"))
}
fn impl_outgoing_with_incoming_self(input: &DeriveInput, import_path: &TokenStream) -> TokenStream { fn impl_outgoing_with_incoming_self(input: &DeriveInput, import_path: &TokenStream) -> TokenStream {
let ident = &input.ident; let ident = &input.ident;
let (impl_gen, ty_gen, _) = input.generics.split_for_impl(); let (impl_gen, ty_gen, _) = input.generics.split_for_impl();
@ -283,3 +280,41 @@ fn strip_lifetimes(field_type: &mut Type) -> bool {
_ => false, _ => false,
} }
} }
pub struct Meta {
derive_macs: Vec<DeriveMac>,
}
impl Parse for Meta {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self {
derive_macs: Punctuated::<_, Token![,]>::parse_terminated(input)?.into_iter().collect(),
})
}
}
pub enum DeriveMac {
Regular(Ident),
NegativeDeserialize,
}
impl Parse for DeriveMac {
fn parse(input: ParseStream) -> syn::Result<Self> {
if input.peek(Token![!]) {
let _: Token![!] = input.parse()?;
let mac: Ident = input.parse()?;
if mac != "Deserialize" {
return Err(syn::Error::new_spanned(
mac,
"Negative incoming_derive can only be used for Deserialize",
));
}
Ok(Self::NegativeDeserialize)
} else {
let mac = input.parse()?;
Ok(Self::Regular(mac))
}
}
}

View File

@ -76,7 +76,7 @@ struct IncomingMyType {
``` ```
*/ */
#[proc_macro_derive(Outgoing, attributes(incoming_derive, incoming_no_deserialize))] #[proc_macro_derive(Outgoing, attributes(incoming_derive))]
pub fn derive_outgoing(input: TokenStream) -> TokenStream { pub fn derive_outgoing(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);
expand_derive_outgoing(input).unwrap_or_else(|err| err.to_compile_error()).into() expand_derive_outgoing(input).unwrap_or_else(|err| err.to_compile_error()).into()

View File

@ -21,7 +21,7 @@ pub struct OtherThing<'t> {
} }
#[derive(Outgoing)] #[derive(Outgoing)]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct FakeRequest<'a, T> { pub struct FakeRequest<'a, T> {
pub abc: &'a str, pub abc: &'a str,
pub thing: Thing<'a, T>, pub thing: Thing<'a, T>,
@ -35,7 +35,7 @@ pub struct FakeRequest<'a, T> {
} }
#[derive(Outgoing)] #[derive(Outgoing)]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub enum EnumThing<'a, T> { pub enum EnumThing<'a, T> {
Abc(&'a str), Abc(&'a str),
Stuff(Thing<'a, T>), Stuff(Thing<'a, T>),

View File

@ -19,7 +19,7 @@ use serde_json::value::RawValue as RawJsonValue;
/// Send a message event to a room. /// Send a message event to a room.
#[derive(Clone, Debug, Outgoing)] #[derive(Clone, Debug, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct Request<'a> { pub struct Request<'a> {
/// The room to send the event to. /// The room to send the event to.
pub room_id: &'a RoomId, pub room_id: &'a RoomId,
@ -45,7 +45,7 @@ impl<'a> Request<'a> {
/// Data in the response from the `send_message_event` API endpoint. /// Data in the response from the `send_message_event` API endpoint.
#[derive(Clone, Debug, Outgoing)] #[derive(Clone, Debug, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct Response { pub struct Response {
/// A unique identifier for the event. /// A unique identifier for the event.
pub event_id: EventId, pub event_id: EventId,

View File

@ -19,7 +19,7 @@ use serde_json::value::RawValue as RawJsonValue;
/// Send a state event to a room associated with the empty state key. /// Send a state event to a room associated with the empty state key.
#[derive(Clone, Debug, Outgoing)] #[derive(Clone, Debug, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct Request<'a> { pub struct Request<'a> {
/// The room to set the state in. /// The room to set the state in.
pub room_id: &'a RoomId, pub room_id: &'a RoomId,
@ -38,7 +38,7 @@ impl<'a> Request<'a> {
/// Data in the response from the `send_state_event_for_empty_key` API endpoint. /// Data in the response from the `send_state_event_for_empty_key` API endpoint.
#[derive(Clone, Debug, Outgoing)] #[derive(Clone, Debug, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct Response { pub struct Response {
/// A unique identifier for the event. /// A unique identifier for the event.
pub event_id: EventId, pub event_id: EventId,

View File

@ -19,7 +19,7 @@ use serde_json::value::RawValue as RawJsonValue;
/// Send a state event to a room associated with a given state key. /// Send a state event to a room associated with a given state key.
#[derive(Clone, Debug, Outgoing)] #[derive(Clone, Debug, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct Request<'a> { pub struct Request<'a> {
/// The room to set the state in. /// The room to set the state in.
pub room_id: &'a RoomId, pub room_id: &'a RoomId,
@ -41,7 +41,7 @@ impl<'a> Request<'a> {
/// Data in the response from the `send_message_event` API endpoint. /// Data in the response from the `send_message_event` API endpoint.
#[derive(Clone, Debug, Outgoing)] #[derive(Clone, Debug, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
#[incoming_no_deserialize] #[incoming_derive(!Deserialize)]
pub struct Response { pub struct Response {
/// A unique identifier for the event. /// A unique identifier for the event.
pub event_id: EventId, pub event_id: EventId,