use core::ops::{Deref, DerefMut};
use proc_macro2::TokenStream;
use quote::quote;
use syn::{
Ident, Lit, Meta, Token, Visibility, braced,
parse::{Parse, ParseStream},
punctuated::Punctuated,
token::Brace,
};
use crate::attr::AllAttrs;
#[derive(Clone)]
pub enum Order {
Method(OrderMethod),
Trait(OrderTrait),
}
#[derive(Clone)]
pub struct OrderMethod {
pub vis: Visibility,
pub const_token: Option<Token![const]>,
pub ident: Ident,
pub config: OrderConfigList,
}
#[derive(Clone)]
pub struct OrderTrait {
pub _impl_token: Token![impl],
pub ident: Ident,
pub config: OrderConfigList,
}
#[derive(Clone)]
pub enum OrderConfigList {
None,
Single(Lit),
Multiple {
#[expect(unused)]
brace: Brace,
configs: Punctuated<OrderConfig, Token![,]>,
},
}
#[derive(Clone)]
pub struct OrderConfig {
pub ident: Ident,
#[expect(unused)]
pub eq_token: Token![=],
pub literal: Lit,
}
impl OrderMethod {
pub fn keywords(&self) -> TokenStream {
let Self {
vis, const_token, ..
} = self;
quote! { #vis #const_token }
}
}
impl Parse for OrderConfig {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
Ok(Self {
ident: input.parse()?,
eq_token: input.parse()?,
literal: input.parse()?,
})
}
}
#[derive(Default, Clone)]
pub struct Orders(Vec<Order>);
impl Deref for Orders {
type Target = Vec<Order>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Orders {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Extend<Order> for Orders {
fn extend<T: IntoIterator<Item = Order>>(&mut self, iter: T) {
self.0.extend(iter)
}
}
impl IntoIterator for Orders {
type Item = Order;
type IntoIter = <Vec<Order> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Orders {
fn try_from_meta(meta: &Meta) -> syn::Result<Self> {
let Meta::List(list) = meta else {
return Err(syn::Error::new_spanned(meta, "expected list of arguments"));
};
list.parse_args::<Self>()
}
}
impl Parse for Order {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if input.peek(Token![impl]) {
input.parse().map(Self::Trait)
} else {
input.parse().map(Self::Method)
}
}
}
impl Parse for OrderMethod {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
Ok(Self {
vis: input.parse()?,
const_token: input.parse()?,
ident: input.parse()?,
config: input.parse()?,
})
}
}
impl Parse for OrderTrait {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
Ok(Self {
_impl_token: input.parse()?,
ident: input.parse()?,
config: input.parse()?,
})
}
}
impl Parse for OrderConfigList {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
if input.peek(Token![=]) {
let _eq_token = input.parse::<Token![=]>()?;
if input.peek(Lit) {
input.parse().map(Self::Single)
} else {
let content;
Ok(OrderConfigList::Multiple {
brace: braced!(content in input),
configs: content.call(Punctuated::parse_terminated)?,
})
}
} else {
Ok(OrderConfigList::None)
}
}
}
impl Parse for Orders {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let content = Punctuated::<Order, Token![,]>::parse_terminated(input)?;
Ok(Self(content.into_iter().collect()))
}
}
#[derive(Clone, Default)]
pub struct AllOrders {
global: Orders,
all: Orders,
per_item: Vec<Orders>,
}
impl AllOrders {
pub fn try_from_attrs(
global_from_args: Orders,
all_from_args: Orders,
attrs: AllAttrs,
) -> syn::Result<Self> {
let mut all_orders = Self {
global: global_from_args,
all: all_from_args,
per_item: Vec::with_capacity(attrs.per_item.len()),
};
for attr in attrs.global.quick_impl {
all_orders.global.extend(Orders::try_from_meta(&attr.meta)?);
}
for attr in attrs.global.quick_impl_all {
all_orders.all.extend(Orders::try_from_meta(&attr.meta)?);
}
for per_item in attrs.per_item {
let mut orders = Orders::default();
for attr in per_item.quick_impl {
orders.extend(Orders::try_from_meta(&attr.meta)?);
}
all_orders.per_item.push(orders);
if let Some(first) = per_item.quick_impl_all.first() {
return Err(syn::Error::new_spanned(
first,
"`quick_impl_all` attribute is only allowed above the enum/struct definition",
));
}
}
Ok(all_orders)
}
pub fn global(&self) -> impl Iterator<Item = &Order> {
self.global.iter()
}
pub fn per_item(&self, i: usize) -> impl Iterator<Item = &Order> {
self.all.iter().chain(self.per_item[i].iter())
}
}