| 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 | |