1 | //! Attribute parsing for the `incomparable` option. |
2 | |
3 | use proc_macro2::Span; |
4 | use syn::{spanned::Spanned, Meta, Result}; |
5 | |
6 | use 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))] |
12 | pub struct Incomparable(pub Option<Span>); |
13 | |
14 | impl 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 | |