use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Lit, MetaNameValue};
macro_rules! litstr {
($lit: expr) => {
if let Lit::Str(s) = $lit {
s.value()
} else {
panic!("invalid string value")
}
};
}
#[proc_macro_derive(Sorting, attributes(sorting))]
pub fn sorting_derive(input: TokenStream) -> TokenStream {
let sitem = parse_macro_input!(input as syn::ItemStruct);
let sid = &sitem.ident;
let mut owned = true;
for param in sitem.generics.params {
if let syn::GenericParam::Lifetime(_) = param {
owned = false;
}
}
let mut id = "id".to_owned();
for a in &sitem.attrs {
if a.path.is_ident("sorting") {
if let Ok(nameval) = a.parse_args::<MetaNameValue>() {
if nameval.path.is_ident("id") {
id = litstr!(nameval.lit);
}
}
}
}
let i_id = format_ident!("{}", id);
let tr = if owned {
quote! {
impl Eq for #sid {}
impl Ord for #sid {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.#i_id.cmp(&other.#i_id)
}
}
impl PartialOrd for #sid {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for #sid {
fn eq(&self, other: &Self) -> bool {
self.#i_id == other.#i_id
}
}
}
} else {
quote! {
impl<'srt> Eq for #sid<'srt> {}
impl<'srt> Ord for #sid<'srt> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.#i_id.cmp(&other.#i_id)
}
}
impl<'srt> PartialOrd for #sid<'srt> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'srt> PartialEq for #sid<'srt> {
fn eq(&self, other: &Self) -> bool {
self.#i_id == other.#i_id
}
}
}
};
TokenStream::from(tr)
}