1//! Attribute parsing for the `incomparable` option.
2
3use proc_macro2::Span;
4use syn::{spanned::Spanned, Meta, Result};
5
6use crate::{attr::DeriveTrait, DeriveWhere, Error};
7
8/// Stores if this variant should be incomparable when implementing
9/// [`PartialEq`] or [`PartialOrd`].
10#[derive(Clone, Copy, Default)]
11#[cfg_attr(test, derive(Debug))]
12pub struct Incomparable(pub Option<Span>);
13
14impl Incomparable {
15 /// Token used for the `incomparable` option.
16 pub const INCOMPARABLE: &'static str = "incomparable";
17
18 /// Adds a [`Meta`] to this [`Incomparable`].
19 pub fn add_attribute(&mut self, meta: &Meta, derive_wheres: &[DeriveWhere]) -> Result<()> {
20 debug_assert!(meta.path().is_ident(Self::INCOMPARABLE));
21
22 if let Meta::Path(path) = meta {
23 if self.0.is_some() {
24 Err(Error::option_duplicate(path.span(), Self::INCOMPARABLE))
25 } else {
26 let mut impl_cmp = false;
27
28 for trait_ in derive_wheres
29 .iter()
30 .flat_map(|derive_where| derive_where.traits.iter())
31 {
32 match trait_ {
33 DeriveTrait::Eq | DeriveTrait::Ord => {
34 return Err(Error::non_partial_incomparable(path.span()));
35 }
36 DeriveTrait::PartialEq | DeriveTrait::PartialOrd => impl_cmp = true,
37 _ => {}
38 }
39 }
40
41 if impl_cmp {
42 self.0 = Some(path.span());
43 Ok(())
44 } else {
45 Err(Error::incomparable(path.span()))
46 }
47 }
48 } else {
49 Err(Error::option_syntax(meta.span()))
50 }
51 }
52}
53