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}