Skip to main content

dds_bridge/solver/
strain_flags.rs

1//! Strain selection flags for batch solving
2
3bitflags::bitflags! {
4    /// Flags for the solver to solve for a strain
5    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7    pub struct StrainFlags : u8 {
8        /// Solve for clubs ([`Strain::Clubs`](crate::Strain::Clubs))
9        const CLUBS = 0x01;
10        /// Solve for diamonds ([`Strain::Diamonds`](crate::Strain::Diamonds))
11        const DIAMONDS = 0x02;
12        /// Solve for hearts ([`Strain::Hearts`](crate::Strain::Hearts))
13        const HEARTS = 0x04;
14        /// Solve for spades ([`Strain::Spades`](crate::Strain::Spades))
15        const SPADES = 0x08;
16        /// Solve for notrump ([`Strain::Notrump`](crate::Strain::Notrump))
17        const NOTRUMP = 0x10;
18    }
19}
20
21/// A guaranteed non-empty [`StrainFlags`]
22///
23/// Analogous to [`NonZero`](core::num::NonZero) — constructable only if the
24/// flags are non-empty, ensuring callers cannot accidentally pass an empty set
25/// to functions that require at least one strain.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27pub struct NonEmptyStrainFlags(StrainFlags);
28
29impl NonEmptyStrainFlags {
30    /// All strains
31    pub const ALL: Self = Self(StrainFlags::all());
32
33    /// Wrap `flags` if non-empty, otherwise return `None`
34    #[must_use]
35    pub const fn new(flags: StrainFlags) -> Option<Self> {
36        if flags.is_empty() {
37            None
38        } else {
39            Some(Self(flags))
40        }
41    }
42
43    /// Extract the inner [`StrainFlags`]
44    #[must_use]
45    pub const fn get(self) -> StrainFlags {
46        self.0
47    }
48}
49
50impl From<NonEmptyStrainFlags> for StrainFlags {
51    #[inline]
52    fn from(flags: NonEmptyStrainFlags) -> Self {
53        flags.0
54    }
55}