File size: 3,776 Bytes
2409829 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
use crate::helpers::call_site_ident;
use proc_macro2::Ident;
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Token;
use syn::parse::{Parse, ParseStream};
use syn::{ItemEnum, TypePath};
struct MessageArgs {
pub _top_parent: TypePath,
pub _comma1: Token![,],
pub parent: TypePath,
pub _comma2: Token![,],
pub variant: Ident,
}
impl Parse for MessageArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self {
_top_parent: input.parse()?,
_comma1: input.parse()?,
parent: input.parse()?,
_comma2: input.parse()?,
variant: input.parse()?,
})
}
}
struct TopLevelMessageArgs {
pub parent: TypePath,
pub _comma2: Token![,],
pub variant: Ident,
}
impl Parse for TopLevelMessageArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self {
parent: input.parse()?,
_comma2: input.parse()?,
variant: input.parse()?,
})
}
}
pub fn combined_message_attrs_impl(attr: TokenStream, input_item: TokenStream) -> syn::Result<TokenStream> {
if attr.is_empty() {
return top_level_impl(input_item);
}
let mut input = syn::parse2::<ItemEnum>(input_item)?;
let (parent_is_top, parent, variant) = match syn::parse2::<MessageArgs>(attr.clone()) {
Ok(x) => (false, x.parent, x.variant),
Err(_) => {
let x = syn::parse2::<TopLevelMessageArgs>(attr)?;
(true, x.parent, x.variant)
}
};
let parent_discriminant = quote::quote! {
<#parent as ToDiscriminant>::Discriminant
};
input.attrs.push(syn::parse_quote! { #[derive(ToDiscriminant, TransitiveChild)] });
input.attrs.push(syn::parse_quote! { #[parent(#parent, #parent::#variant)] });
if parent_is_top {
input.attrs.push(syn::parse_quote! { #[parent_is_top] });
}
input
.attrs
.push(syn::parse_quote! { #[discriminant_attr(derive(Debug, Copy, Clone, PartialEq, Eq, Hash, AsMessage, TransitiveChild))] });
input
.attrs
.push(syn::parse_quote! { #[discriminant_attr(parent(#parent_discriminant, #parent_discriminant::#variant))] });
if parent_is_top {
input.attrs.push(syn::parse_quote! { #[discriminant_attr(parent_is_top)] });
}
for var in &mut input.variants {
if let Some(attr) = var.attrs.iter_mut().find(|a| a.path().is_ident("child")) {
let path = match &mut attr.meta {
syn::Meta::Path(path) => path,
syn::Meta::List(list) => &mut list.path,
syn::Meta::NameValue(named_value) => &mut named_value.path,
};
let last_segment = path.segments.last_mut().unwrap();
last_segment.ident = call_site_ident("sub_discriminant");
var.attrs.push(syn::parse_quote! {
#[discriminant_attr(child)]
});
}
}
Ok(input.into_token_stream())
}
fn top_level_impl(input_item: TokenStream) -> syn::Result<TokenStream> {
let mut input = syn::parse2::<ItemEnum>(input_item)?;
input.attrs.push(syn::parse_quote! { #[derive(ToDiscriminant)] });
input.attrs.push(syn::parse_quote! { #[discriminant_attr(derive(Debug, Copy, Clone, PartialEq, Eq, Hash, AsMessage))] });
for var in &mut input.variants {
if let Some(attr) = var.attrs.iter_mut().find(|a| a.path().is_ident("child")) {
let path = match &mut attr.meta {
syn::Meta::Path(path) => path,
syn::Meta::List(list) => &mut list.path,
syn::Meta::NameValue(named_value) => &mut named_value.path,
};
let last_segment = path.segments.last_mut().unwrap();
last_segment.ident = call_site_ident("sub_discriminant");
var.attrs.push(syn::parse_quote! {
#[discriminant_attr(child)]
});
}
}
let input_type = &input.ident;
let discriminant = call_site_ident(format!("{input_type}Discriminant"));
Ok(quote::quote! {
#input
impl TransitiveChild for #input_type {
type TopParent = Self;
type Parent = Self;
}
impl TransitiveChild for #discriminant {
type TopParent = Self;
type Parent = Self;
}
})
}
|