//! Card primitives: ranks, cards, holdings, and hands.
//!
//! [`Rank`] is a non-zero byte in `2..=14` (J/Q/K/A as 11/12/13/14).
//! [`Card`] pairs a [`Rank`] with a [`Suit`] and packs into a
//! single byte.  [`Holding`] is a 13-bit bitset of ranks within one suit,
//! and [`Hand`] is four holdings packed into a `u64`.  Set operations on
//! holdings and hands are exposed through the standard bitwise operators.
//!
//! Iteration yields cards in descending suit order (spades first) and
//! descending rank order within each suit, matching the conventional
//! display order.
//!
//! # Panic policy
//!
//! [`Rank::new`] panics when the input is outside `2..=14` and has
//! [`Rank::try_new`] for fallible construction.  In const contexts the panic
//! becomes a compile-time error.

use crate::Suit;
use core::fmt::{self, Write as _};
use core::iter::FusedIterator;
use core::num::NonZero;
use core::ops;
use core::str::FromStr;
use thiserror::Error;

/// Error indicating an invalid rank
///
/// The rank of a card must be in `2..=14`, where J, Q, K, A are denoted as 11,
/// 12, 13, 14 respectively.
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[error("{0} is not a valid rank (2..=14)")]
pub struct InvalidRank(u8);

/// The rank of a card, from 2 to 14, where J, Q, K, A are internally denoted as
/// 11, 12, 13, 14 respectively.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[repr(transparent)]
pub struct Rank(NonZero<u8>);

impl Rank {
    /// Ace
    pub const A: Self = Self(NonZero::new(14).unwrap());

    /// King
    pub const K: Self = Self(NonZero::new(13).unwrap());

    /// Queen
    pub const Q: Self = Self(NonZero::new(12).unwrap());

    /// Jack
    pub const J: Self = Self(NonZero::new(11).unwrap());

    /// Ten
    pub const T: Self = Self(NonZero::new(10).unwrap());

    /// Create a rank from a number
    ///
    /// # Panics
    ///
    /// When the rank is not in `2..=14`.  In const contexts, this is a
    /// compile-time error.
    #[must_use]
    #[inline]
    pub const fn new(rank: u8) -> Self {
        match Self::try_new(rank) {
            Ok(r) => r,
            Err(_) => panic!("rank must be in 2..=14"),
        }
    }

    /// Try to create a rank from a number
    ///
    /// # Errors
    ///
    /// When the rank is not in `2..=14`.
    #[inline]
    pub const fn try_new(rank: u8) -> Result<Self, InvalidRank> {
        match NonZero::new(rank) {
            Some(nonzero) if rank >= 2 && rank <= 14 => Ok(Self(nonzero)),
            _ => Err(InvalidRank(rank)),
        }
    }

    /// Get the stored rank as [`u8`]
    #[must_use]
    #[inline]
    pub const fn get(self) -> u8 {
        self.0.get()
    }

    /// Display character for this rank
    #[must_use]
    #[inline]
    pub const fn letter(self) -> char {
        b"23456789TJQKA"[self.get() as usize - 2] as char
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_char(self.letter())
    }
}

/// Error returned when parsing a [`Rank`] fails
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
#[error("Invalid rank: expected 2-10, T, J, Q, K, A")]
pub struct ParseRankError;

impl FromStr for Rank {
    type Err = ParseRankError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_ascii_uppercase().as_str() {
            "A" => Ok(Self::A),
            "K" => Ok(Self::K),
            "Q" => Ok(Self::Q),
            "J" => Ok(Self::J),
            "T" | "10" => Ok(Self::T),
            "9" => Ok(Self::new(9)),
            "8" => Ok(Self::new(8)),
            "7" => Ok(Self::new(7)),
            "6" => Ok(Self::new(6)),
            "5" => Ok(Self::new(5)),
            "4" => Ok(Self::new(4)),
            "3" => Ok(Self::new(3)),
            "2" => Ok(Self::new(2)),
            _ => Err(ParseRankError),
        }
    }
}

/// A playing card
///
/// Internally packed as `(rank << 2) | suit` in a single byte.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(
    feature = "serde",
    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
)]
pub struct Card {
    /// The suit of the card
    pub suit: Suit,
    /// The rank of the card
    pub rank: Rank,
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}{}", self.suit, self.rank)
    }
}

/// Error returned when parsing a [`Card`] fails
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ParseCardError {
    /// Invalid suit in card
    #[error("Invalid suit in card: expected one of C, D, H, S, ♣, ♦, ♥, ♠, ♧, ♢, ♡, ♤")]
    Suit,
    /// Invalid rank in card
    #[error("Invalid rank in card: expected 2-10, T, J, Q, K, A")]
    Rank,
}

impl FromStr for Card {
    type Err = ParseCardError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let rank_len = if s.ends_with("10") {
            2
        } else {
            s.chars().next_back().map_or(0, char::len_utf8)
        };
        let border = s.len().saturating_sub(rank_len);
        let (suit, rank) = s.split_at(border);
        let suit: Suit = suit.parse().map_err(|_| ParseCardError::Suit)?;
        let rank: Rank = rank.parse().map_err(|_| ParseCardError::Rank)?;
        Ok(Self { suit, rank })
    }
}

/// A set of cards of the same suit
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(
    feature = "serde",
    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
)]
#[repr(transparent)]
pub struct Holding(u16);

/// Iterator over the ranks in a [`Holding`], yielding [`Rank`]s in descending order
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HoldingIter {
    rest: u16,
    cursor: u8,
}

impl Iterator for HoldingIter {
    type Item = Rank;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rest == 0 {
            return None;
        }

        // For non-zero u16, leading_zeros is in 0..=15, fitting in u8.
        // Bit 15 is never set in a valid Holding (max rank is 14), so pos <= 14.
        #[allow(clippy::cast_possible_truncation)]
        let pos = 15 - self.rest.leading_zeros() as u8;
        self.rest &= !(1u16 << pos);
        let rank = self.cursor + pos;

        // SAFETY: rank is in 2..=14 by construction from a valid Holding
        Some(Rank(unsafe { core::num::NonZero::new_unchecked(rank) }))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let count = self.rest.count_ones() as usize;
        (count, Some(count))
    }

    fn count(self) -> usize {
        self.rest.count_ones() as usize
    }
}

impl DoubleEndedIterator for HoldingIter {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.rest == 0 {
            return None;
        }

        // 1. Trailing zeros are in the range of 0..=15, which fits in `u8`
        // 2. Trailing zeros cannot be 15 since the bitset is from a `Holding`
        #[allow(clippy::cast_possible_truncation)]
        let step = self.rest.trailing_zeros() as u8 + 1;
        self.rest >>= step;
        self.cursor += step;

        // SAFETY: cursor is in 2..=14 by construction from a valid Holding
        Some(Rank(unsafe {
            core::num::NonZero::new_unchecked(self.cursor - 1)
        }))
    }
}

impl ExactSizeIterator for HoldingIter {
    fn len(&self) -> usize {
        self.rest.count_ones() as usize
    }
}

impl FusedIterator for HoldingIter {}

impl Holding {
    /// The empty set
    pub const EMPTY: Self = Self(0);

    /// The set containing all possible ranks (2..=14)
    pub const ALL: Self = Self(0x7FFC);

    /// The number of cards in the holding
    #[must_use]
    #[inline]
    pub const fn len(self) -> usize {
        self.0.count_ones() as usize
    }

    /// Whether the holding is empty
    #[must_use]
    #[inline]
    pub const fn is_empty(self) -> bool {
        self.0 == 0
    }

    /// Whether the holding contains a rank
    #[must_use]
    #[inline]
    pub const fn contains(self, rank: Rank) -> bool {
        self.0 & 1 << rank.get() != 0
    }

    /// Insert a rank into the holding, returning whether it was newly inserted
    #[inline]
    pub const fn insert(&mut self, rank: Rank) -> bool {
        let insertion = 1 << rank.get() & Self::ALL.0;
        let inserted = insertion & !self.0 != 0;
        self.0 |= insertion;
        inserted
    }

    /// Remove a rank from the holding, returning whether it was present
    #[inline]
    pub const fn remove(&mut self, rank: Rank) -> bool {
        let removed = self.contains(rank);
        self.0 &= !(1 << rank.get());
        removed
    }

    /// Toggle a rank in the holding, returning whether it is now present
    #[inline]
    pub const fn toggle(&mut self, rank: Rank) -> bool {
        self.0 ^= 1 << rank.get() & Self::ALL.0;
        self.contains(rank)
    }

    /// Conditionally insert/remove a rank from the holding
    #[inline]
    pub const fn set(&mut self, rank: Rank, condition: bool) {
        let flag = 1 << rank.get();
        let mask = (condition as u16).wrapping_neg();
        self.0 = (self.0 & !flag) | (mask & flag);
    }

    /// Iterate over the ranks in the holding
    #[inline]
    #[must_use]
    pub const fn iter(self) -> HoldingIter {
        HoldingIter {
            rest: self.0,
            cursor: 0,
        }
    }

    /// As a bitset of ranks
    #[must_use]
    #[inline]
    pub const fn to_bits(self) -> u16 {
        self.0
    }

    /// Create a holding from a bitset of ranks, retaining invalid ranks
    #[must_use]
    #[inline]
    pub const fn from_bits_retain(bits: u16) -> Self {
        Self(bits)
    }

    /// Whether the holding contains an invalid rank
    #[must_use]
    #[inline]
    pub const fn contains_unknown_bits(self) -> bool {
        self.0 & Self::ALL.0 != self.0
    }

    /// Create a holding from a bitset of ranks, checking for invalid ranks
    #[must_use]
    #[inline]
    pub const fn from_bits(bits: u16) -> Option<Self> {
        if bits & Self::ALL.0 == bits {
            Some(Self(bits))
        } else {
            None
        }
    }

    /// Create a holding from a bitset of ranks, removing invalid ranks
    #[must_use]
    #[inline]
    pub const fn from_bits_truncate(bits: u16) -> Self {
        Self(bits & Self::ALL.0)
    }

    /// Create a holding from a rank
    #[must_use]
    #[inline]
    pub const fn from_rank(rank: Rank) -> Self {
        Self(1 << rank.get())
    }
}

impl IntoIterator for Holding {
    type Item = Rank;
    type IntoIter = HoldingIter;

    fn into_iter(self) -> HoldingIter {
        self.iter()
    }
}

impl ops::BitAnd for Holding {
    type Output = Self;

    #[inline]
    fn bitand(self, rhs: Self) -> Self {
        Self(self.0 & rhs.0)
    }
}

impl ops::BitOr for Holding {
    type Output = Self;

    #[inline]
    fn bitor(self, rhs: Self) -> Self {
        Self(self.0 | rhs.0)
    }
}

impl ops::BitXor for Holding {
    type Output = Self;

    #[inline]
    fn bitxor(self, rhs: Self) -> Self {
        Self(self.0 ^ rhs.0)
    }
}

impl ops::Not for Holding {
    type Output = Self;

    #[inline]
    fn not(self) -> Self {
        Self::from_bits_truncate(!self.0)
    }
}

impl ops::Sub for Holding {
    type Output = Self;

    #[inline]
    fn sub(self, rhs: Self) -> Self {
        Self(self.0 & !rhs.0)
    }
}

impl ops::BitAndAssign for Holding {
    #[inline]
    fn bitand_assign(&mut self, rhs: Self) {
        *self = *self & rhs;
    }
}

impl ops::BitOrAssign for Holding {
    #[inline]
    fn bitor_assign(&mut self, rhs: Self) {
        *self = *self | rhs;
    }
}

impl ops::BitXorAssign for Holding {
    #[inline]
    fn bitxor_assign(&mut self, rhs: Self) {
        *self = *self ^ rhs;
    }
}

impl ops::SubAssign for Holding {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}

/// Show cards in descending order
///
/// 1. The ten is shown as `T` for PBN compatibility.
/// 2. This implementation ignores formatting flags for simplicity and speed.
///    If you want to pad or align the output, use [`fmt::Formatter::pad`].
impl fmt::Display for Holding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for rank in (2u8..15).rev() {
            if self.0 & 1 << rank != 0 {
                f.write_char(b"23456789TJQKA"[rank as usize - 2] as char)?;
            }
        }
        Ok(())
    }
}

/// An error which can be returned when parsing a [`Holding`]
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ParseHoldingError {
    /// Ranks are not all valid or in descending order
    #[error("Ranks are not all valid or in descending order")]
    InvalidRanks,

    /// The same rank appears more than once
    #[error("The same rank appears more than once")]
    RepeatedRank,

    /// A suit contains more than 13 cards
    #[error("A suit contains more than 13 cards")]
    TooManyCards,
}

/// An error which can be returned when parsing a [`Hand`]
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ParseHandError {
    /// Error in a holding
    #[error(transparent)]
    Holding(#[from] ParseHoldingError),

    /// The hand does not contain 4 suits
    #[error("The hand does not contain 4 suits")]
    NotFourSuits,
}

impl FromStr for Holding {
    type Err = ParseHoldingError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // 13 cards + 1 extra char for "10"
        if s.len() > 14 {
            return Err(ParseHoldingError::TooManyCards);
        }

        let bytes = s.as_bytes();
        let mut i = 0;
        let mut prev_rank: u8 = 15;
        let mut explicit = Self::EMPTY;

        while i < bytes.len() {
            let c = bytes[i].to_ascii_uppercase();
            let rank: u8 = match c {
                b'A' => 14,
                b'K' => 13,
                b'Q' => 12,
                b'J' => 11,
                b'T' => 10,
                b'1' => {
                    if bytes.get(i + 1) != Some(&b'0') {
                        return Err(ParseHoldingError::InvalidRanks);
                    }
                    i += 1;
                    10
                }
                b'2'..=b'9' => c - b'0',
                b'X' => break,
                _ => return Err(ParseHoldingError::InvalidRanks),
            };

            if rank >= prev_rank {
                return Err(ParseHoldingError::InvalidRanks);
            }
            prev_rank = rank;

            // SAFETY: rank is in 2..=14 by construction above
            let r = Rank(unsafe { core::num::NonZero::new_unchecked(rank) });
            explicit.insert(r);
            i += 1;
        }

        let spot_count = bytes.len() - i;
        if bytes[i..].iter().any(|&b| !b.eq_ignore_ascii_case(&b'x')) {
            return Err(ParseHoldingError::InvalidRanks);
        }
        if spot_count > 13 {
            return Err(ParseHoldingError::TooManyCards);
        }

        let spots = Self::from_bits_truncate((4u16 << spot_count) - 4);

        if explicit & spots == Self::EMPTY {
            Ok(explicit | spots)
        } else {
            Err(ParseHoldingError::RepeatedRank)
        }
    }
}

/// A hand of playing cards
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(
    feature = "serde",
    derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
)]
pub struct Hand([Holding; 4]);

/// Iterator over the cards in a [`Hand`], yielding [`Card`]s in descending
/// suit order and descending rank order within each suit
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HandIter {
    suits: [HoldingIter; 4],
    fwd: u8,
    bwd: u8,
}

impl Iterator for HandIter {
    type Item = Card;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.fwd > 3 {
                return None;
            }
            let suit = Suit::ASC[self.fwd as usize];
            if let Some(rank) = self.suits[self.fwd as usize].next() {
                return Some(Card { suit, rank });
            }
            if self.fwd == self.bwd {
                self.fwd = 4;
                return None;
            }
            self.fwd -= 1;
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let count = self.len();
        (count, Some(count))
    }

    fn count(self) -> usize {
        self.len()
    }
}

impl DoubleEndedIterator for HandIter {
    fn next_back(&mut self) -> Option<Self::Item> {
        loop {
            if self.fwd > 3 {
                return None;
            }
            let suit = Suit::ASC[self.bwd as usize];
            if let Some(rank) = self.suits[self.bwd as usize].next_back() {
                return Some(Card { suit, rank });
            }
            if self.fwd == self.bwd {
                self.fwd = 4;
                return None;
            }
            self.bwd += 1;
        }
    }
}

impl ExactSizeIterator for HandIter {
    fn len(&self) -> usize {
        if self.fwd > 3 {
            return 0;
        }
        (self.bwd as usize..=self.fwd as usize)
            .map(|i| self.suits[i].len())
            .sum()
    }
}

impl FusedIterator for HandIter {}

impl ops::Index<Suit> for Hand {
    type Output = Holding;

    #[inline]
    fn index(&self, suit: Suit) -> &Holding {
        &self.0[suit as usize]
    }
}

impl ops::IndexMut<Suit> for Hand {
    #[inline]
    fn index_mut(&mut self, suit: Suit) -> &mut Holding {
        &mut self.0[suit as usize]
    }
}

impl Hand {
    /// As a bitset of cards
    #[must_use]
    #[inline]
    pub const fn to_bits(self) -> u64 {
        unsafe { core::mem::transmute(self.0) }
    }

    /// Create a hand from a bitset of cards, retaining invalid cards
    #[must_use]
    #[inline]
    pub const fn from_bits_retain(bits: u64) -> Self {
        unsafe { core::mem::transmute(bits) }
    }

    /// Whether the hand contains an invalid card
    #[must_use]
    #[inline]
    pub const fn contains_unknown_bits(self) -> bool {
        self.to_bits() & Self::ALL.to_bits() != self.to_bits()
    }

    /// Create a hand from a bitset of cards, checking for invalid cards
    #[must_use]
    #[inline]
    pub const fn from_bits(bits: u64) -> Option<Self> {
        if bits & Self::ALL.to_bits() == bits {
            Some(Self::from_bits_retain(bits))
        } else {
            None
        }
    }

    /// Create a hand from a bitset of cards, removing invalid cards
    #[must_use]
    #[inline]
    pub const fn from_bits_truncate(bits: u64) -> Self {
        Self::from_bits_retain(bits & Self::ALL.to_bits())
    }

    /// Create a hand from four holdings in suit order (clubs, diamonds, hearts, spades)
    #[must_use]
    #[inline]
    pub const fn new(clubs: Holding, diamonds: Holding, hearts: Holding, spades: Holding) -> Self {
        Self([clubs, diamonds, hearts, spades])
    }

    /// The empty hand
    pub const EMPTY: Self = Self([Holding::EMPTY; 4]);

    /// The hand containing all 52 cards
    pub const ALL: Self = Self([Holding::ALL; 4]);

    /// The number of cards in the hand
    #[must_use]
    #[inline]
    pub const fn len(self) -> usize {
        self.to_bits().count_ones() as usize
    }

    /// Whether the hand is empty
    #[must_use]
    #[inline]
    pub const fn is_empty(self) -> bool {
        self.to_bits() == 0
    }

    /// Whether the hand contains a card
    #[must_use]
    #[inline]
    pub fn contains(self, card: Card) -> bool {
        self[card.suit].contains(card.rank)
    }

    /// Insert a card into the hand, returning whether it was newly inserted
    #[inline]
    pub fn insert(&mut self, card: Card) -> bool {
        self[card.suit].insert(card.rank)
    }

    /// Remove a card from the hand, returning whether it was present
    #[inline]
    pub fn remove(&mut self, card: Card) -> bool {
        self[card.suit].remove(card.rank)
    }

    /// Toggle a card in the hand, returning whether it is now present
    #[inline]
    pub fn toggle(&mut self, card: Card) -> bool {
        self[card.suit].toggle(card.rank)
    }

    /// Conditionally insert/remove a card from the hand
    #[inline]
    pub fn set(&mut self, card: Card, condition: bool) {
        self[card.suit].set(card.rank, condition);
    }

    /// Iterate over the cards in the hand
    #[inline]
    #[must_use]
    pub const fn iter(self) -> HandIter {
        HandIter {
            suits: [
                self.0[0].iter(),
                self.0[1].iter(),
                self.0[2].iter(),
                self.0[3].iter(),
            ],
            fwd: 3,
            bwd: 0,
        }
    }
}

impl IntoIterator for Hand {
    type Item = Card;
    type IntoIter = HandIter;

    #[inline]
    fn into_iter(self) -> HandIter {
        self.iter()
    }
}

impl FromIterator<Card> for Hand {
    fn from_iter<I: IntoIterator<Item = Card>>(iter: I) -> Self {
        iter.into_iter().fold(Self::EMPTY, |mut hand, card| {
            hand.insert(card);
            hand
        })
    }
}

/// PBN-compatible display of a hand
///
/// This implementation ignores formatting flags for simplicity and speed.
impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.is_empty() {
            return f.write_char('-');
        }

        self[Suit::Spades].fmt(f)?;
        f.write_char('.')?;

        self[Suit::Hearts].fmt(f)?;
        f.write_char('.')?;

        self[Suit::Diamonds].fmt(f)?;
        f.write_char('.')?;

        self[Suit::Clubs].fmt(f)
    }
}

impl FromStr for Hand {
    type Err = ParseHandError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // 52 cards + 4 tens + 3 dots
        if s.len() > 52 + 4 + 3 {
            return Err(ParseHoldingError::TooManyCards.into());
        }

        if s == "-" {
            return Ok(Self::EMPTY);
        }

        let holdings: Result<Vec<_>, _> = s.split('.').map(Holding::from_str).rev().collect();

        Ok(Self(
            holdings?
                .try_into()
                .map_err(|_| ParseHandError::NotFourSuits)?,
        ))
    }
}

impl ops::BitAnd for Hand {
    type Output = Self;

    #[inline]
    fn bitand(self, rhs: Self) -> Self {
        Self::from_bits_retain(self.to_bits() & rhs.to_bits())
    }
}

impl ops::BitOr for Hand {
    type Output = Self;

    #[inline]
    fn bitor(self, rhs: Self) -> Self {
        Self::from_bits_retain(self.to_bits() | rhs.to_bits())
    }
}

impl ops::BitXor for Hand {
    type Output = Self;

    #[inline]
    fn bitxor(self, rhs: Self) -> Self {
        Self::from_bits_retain(self.to_bits() ^ rhs.to_bits())
    }
}

impl ops::Not for Hand {
    type Output = Self;

    #[inline]
    fn not(self) -> Self {
        Self::from_bits_truncate(!self.to_bits())
    }
}

impl ops::Sub for Hand {
    type Output = Self;

    #[inline]
    fn sub(self, rhs: Self) -> Self {
        Self::from_bits_retain(self.to_bits() & !rhs.to_bits())
    }
}

impl ops::BitAndAssign for Hand {
    #[inline]
    fn bitand_assign(&mut self, rhs: Self) {
        *self = *self & rhs;
    }
}

impl ops::BitOrAssign for Hand {
    #[inline]
    fn bitor_assign(&mut self, rhs: Self) {
        *self = *self | rhs;
    }
}

impl ops::BitXorAssign for Hand {
    #[inline]
    fn bitxor_assign(&mut self, rhs: Self) {
        *self = *self ^ rhs;
    }
}

impl ops::SubAssign for Hand {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}
