1use crate::Suit;
2use core::fmt::{self, Write as _};
3use core::iter::FusedIterator;
4use core::num::NonZero;
5use core::ops;
6use core::str::FromStr;
7use thiserror::Error;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum Seat {
13 North,
15 East,
17 South,
19 West,
21}
22
23impl Seat {
24 pub const ALL: [Self; 4] = [Self::North, Self::East, Self::South, Self::West];
26
27 #[must_use]
29 pub const fn partner(self) -> Self {
30 match self {
31 Self::North => Self::South,
32 Self::East => Self::West,
33 Self::South => Self::North,
34 Self::West => Self::East,
35 }
36 }
37
38 #[must_use]
40 pub const fn lho(self) -> Self {
41 match self {
42 Self::North => Self::East,
43 Self::East => Self::South,
44 Self::South => Self::West,
45 Self::West => Self::North,
46 }
47 }
48
49 #[must_use]
51 pub const fn rho(self) -> Self {
52 match self {
53 Self::North => Self::West,
54 Self::East => Self::North,
55 Self::South => Self::East,
56 Self::West => Self::South,
57 }
58 }
59
60 #[must_use]
62 #[inline]
63 pub const fn letter(self) -> char {
64 match self {
65 Self::North => 'N',
66 Self::East => 'E',
67 Self::South => 'S',
68 Self::West => 'W',
69 }
70 }
71}
72
73const _: () = assert!(Seat::ALL[0] as u8 == 0);
74const _: () = assert!(Seat::ALL[1] as u8 == 1);
75const _: () = assert!(Seat::ALL[2] as u8 == 2);
76const _: () = assert!(Seat::ALL[3] as u8 == 3);
77
78impl fmt::Display for Seat {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 f.write_char(self.letter())
81 }
82}
83
84#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
86#[error("Invalid seat: expected one of N, E, S, W (or full names)")]
87pub struct ParseSeatError;
88
89impl FromStr for Seat {
90 type Err = ParseSeatError;
91
92 fn from_str(s: &str) -> Result<Self, Self::Err> {
93 match s.to_ascii_uppercase().as_str() {
94 "N" | "NORTH" => Ok(Self::North),
95 "E" | "EAST" => Ok(Self::East),
96 "S" | "SOUTH" => Ok(Self::South),
97 "W" | "WEST" => Ok(Self::West),
98 _ => Err(ParseSeatError),
99 }
100 }
101}
102
103bitflags::bitflags! {
104 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107 pub struct SeatFlags: u8 {
108 const NORTH = 0b0001;
110 const EAST = 0b0010;
112 const SOUTH = 0b0100;
114 const WEST = 0b1000;
116 }
117}
118
119impl SeatFlags {
120 pub const EMPTY: Self = Self::empty();
122
123 pub const ALL: Self = Self::all();
125
126 pub const NS: Self = Self::NORTH.union(Self::SOUTH);
128
129 pub const EW: Self = Self::EAST.union(Self::WEST);
131}
132
133impl From<Seat> for SeatFlags {
134 fn from(seat: Seat) -> Self {
135 match seat {
136 Seat::North => Self::NORTH,
137 Seat::East => Self::EAST,
138 Seat::South => Self::SOUTH,
139 Seat::West => Self::WEST,
140 }
141 }
142}
143
144#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
149#[error("{0} is not a valid rank (2..=14)")]
150pub struct InvalidRank(u8);
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
155#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
156#[cfg_attr(feature = "serde", serde(transparent))]
157#[repr(transparent)]
158pub struct Rank(NonZero<u8>);
159
160impl Rank {
161 pub const A: Self = Self(NonZero::new(14).unwrap());
163
164 pub const K: Self = Self(NonZero::new(13).unwrap());
166
167 pub const Q: Self = Self(NonZero::new(12).unwrap());
169
170 pub const J: Self = Self(NonZero::new(11).unwrap());
172
173 pub const T: Self = Self(NonZero::new(10).unwrap());
175
176 #[must_use]
183 #[inline]
184 pub const fn new(rank: u8) -> Self {
185 match Self::try_new(rank) {
186 Ok(r) => r,
187 Err(_) => panic!("rank must be in 2..=14"),
188 }
189 }
190
191 #[inline]
197 pub const fn try_new(rank: u8) -> Result<Self, InvalidRank> {
198 match NonZero::new(rank) {
199 Some(nonzero) if rank >= 2 && rank <= 14 => Ok(Self(nonzero)),
200 _ => Err(InvalidRank(rank)),
201 }
202 }
203
204 #[must_use]
206 #[inline]
207 pub const fn get(self) -> u8 {
208 self.0.get()
209 }
210
211 #[must_use]
213 #[inline]
214 pub const fn letter(self) -> char {
215 b"23456789TJQKA"[self.get() as usize - 2] as char
216 }
217}
218
219impl fmt::Display for Rank {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 f.write_char(self.letter())
222 }
223}
224
225#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
227#[error("Invalid rank: expected 2-10, T, J, Q, K, A")]
228pub struct ParseRankError;
229
230impl FromStr for Rank {
231 type Err = ParseRankError;
232 fn from_str(s: &str) -> Result<Self, Self::Err> {
233 match s.to_ascii_uppercase().as_str() {
234 "A" => Ok(Self::A),
235 "K" => Ok(Self::K),
236 "Q" => Ok(Self::Q),
237 "J" => Ok(Self::J),
238 "T" | "10" => Ok(Self::T),
239 "9" => Ok(Self::new(9)),
240 "8" => Ok(Self::new(8)),
241 "7" => Ok(Self::new(7)),
242 "6" => Ok(Self::new(6)),
243 "5" => Ok(Self::new(5)),
244 "4" => Ok(Self::new(4)),
245 "3" => Ok(Self::new(3)),
246 "2" => Ok(Self::new(2)),
247 _ => Err(ParseRankError),
248 }
249 }
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
256pub struct Card {
257 pub suit: Suit,
259 pub rank: Rank,
261}
262
263impl fmt::Display for Card {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 write!(f, "{}{}", self.suit, self.rank)
266 }
267}
268
269#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
271#[non_exhaustive]
272pub enum ParseCardError {
273 #[error("Invalid suit in card: expected one of C, D, H, S, ♣, ♦, ♥, ♠, ♧, ♢, ♡, ♤")]
275 Suit,
276 #[error("Invalid rank in card: expected 2-10, T, J, Q, K, A")]
278 Rank,
279}
280
281impl FromStr for Card {
282 type Err = ParseCardError;
283 fn from_str(s: &str) -> Result<Self, Self::Err> {
284 let rank_len = if s.ends_with("10") {
285 2
286 } else {
287 s.chars().next_back().map_or(0, char::len_utf8)
288 };
289 let border = s.len().saturating_sub(rank_len);
290 let (suit, rank) = s.split_at(border);
291 let suit: Suit = suit.parse().map_err(|_| ParseCardError::Suit)?;
292 let rank: Rank = rank.parse().map_err(|_| ParseCardError::Rank)?;
293 Ok(Self { suit, rank })
294 }
295}
296
297#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
299#[repr(transparent)]
300pub struct Holding(u16);
301
302#[derive(Debug, Clone, PartialEq, Eq)]
304pub struct HoldingIter {
305 rest: u16,
306 cursor: u8,
307}
308
309impl Iterator for HoldingIter {
310 type Item = Rank;
311
312 fn next(&mut self) -> Option<Self::Item> {
313 if self.rest == 0 {
314 return None;
315 }
316
317 #[allow(clippy::cast_possible_truncation)]
320 let pos = 15 - self.rest.leading_zeros() as u8;
321 self.rest &= !(1u16 << pos);
322 let rank = self.cursor + pos;
323
324 Some(Rank(unsafe { core::num::NonZero::new_unchecked(rank) }))
326 }
327
328 fn size_hint(&self) -> (usize, Option<usize>) {
329 let count = self.rest.count_ones() as usize;
330 (count, Some(count))
331 }
332
333 fn count(self) -> usize {
334 self.rest.count_ones() as usize
335 }
336}
337
338impl DoubleEndedIterator for HoldingIter {
339 fn next_back(&mut self) -> Option<Self::Item> {
340 if self.rest == 0 {
341 return None;
342 }
343
344 #[allow(clippy::cast_possible_truncation)]
347 let step = self.rest.trailing_zeros() as u8 + 1;
348 self.rest >>= step;
349 self.cursor += step;
350
351 Some(Rank(unsafe {
353 core::num::NonZero::new_unchecked(self.cursor - 1)
354 }))
355 }
356}
357
358impl ExactSizeIterator for HoldingIter {
359 fn len(&self) -> usize {
360 self.rest.count_ones() as usize
361 }
362}
363
364impl FusedIterator for HoldingIter {}
365
366impl Holding {
367 pub const EMPTY: Self = Self(0);
369
370 pub const ALL: Self = Self(0x7FFC);
372
373 #[must_use]
375 #[inline]
376 pub const fn len(self) -> usize {
377 self.0.count_ones() as usize
378 }
379
380 #[must_use]
382 #[inline]
383 pub const fn is_empty(self) -> bool {
384 self.0 == 0
385 }
386
387 #[must_use]
389 #[inline]
390 pub const fn contains(self, rank: Rank) -> bool {
391 self.0 & 1 << rank.get() != 0
392 }
393
394 #[inline]
396 pub const fn insert(&mut self, rank: Rank) -> bool {
397 let insertion = 1 << rank.get() & Self::ALL.0;
398 let inserted = insertion & !self.0 != 0;
399 self.0 |= insertion;
400 inserted
401 }
402
403 #[inline]
405 pub const fn remove(&mut self, rank: Rank) -> bool {
406 let removed = self.contains(rank);
407 self.0 &= !(1 << rank.get());
408 removed
409 }
410
411 #[inline]
413 pub const fn toggle(&mut self, rank: Rank) -> bool {
414 self.0 ^= 1 << rank.get() & Self::ALL.0;
415 self.contains(rank)
416 }
417
418 #[inline]
420 pub const fn set(&mut self, rank: Rank, condition: bool) {
421 let flag = 1 << rank.get();
422 let mask = (condition as u16).wrapping_neg();
423 self.0 = (self.0 & !flag) | (mask & flag);
424 }
425
426 #[inline]
428 #[must_use]
429 pub const fn iter(self) -> HoldingIter {
430 HoldingIter {
431 rest: self.0,
432 cursor: 0,
433 }
434 }
435
436 #[must_use]
438 #[inline]
439 pub const fn to_bits(self) -> u16 {
440 self.0
441 }
442
443 #[must_use]
445 #[inline]
446 pub const fn from_bits_retain(bits: u16) -> Self {
447 Self(bits)
448 }
449
450 #[must_use]
452 #[inline]
453 pub const fn contains_unknown_bits(self) -> bool {
454 self.0 & Self::ALL.0 != self.0
455 }
456
457 #[must_use]
459 #[inline]
460 pub const fn from_bits(bits: u16) -> Option<Self> {
461 if bits & Self::ALL.0 == bits {
462 Some(Self(bits))
463 } else {
464 None
465 }
466 }
467
468 #[must_use]
470 #[inline]
471 pub const fn from_bits_truncate(bits: u16) -> Self {
472 Self(bits & Self::ALL.0)
473 }
474
475 #[must_use]
477 #[inline]
478 pub const fn from_rank(rank: Rank) -> Self {
479 Self(1 << rank.get())
480 }
481}
482
483impl IntoIterator for Holding {
484 type Item = Rank;
485 type IntoIter = HoldingIter;
486
487 fn into_iter(self) -> HoldingIter {
488 self.iter()
489 }
490}
491
492impl ops::BitAnd for Holding {
493 type Output = Self;
494
495 #[inline]
496 fn bitand(self, rhs: Self) -> Self {
497 Self(self.0 & rhs.0)
498 }
499}
500
501impl ops::BitOr for Holding {
502 type Output = Self;
503
504 #[inline]
505 fn bitor(self, rhs: Self) -> Self {
506 Self(self.0 | rhs.0)
507 }
508}
509
510impl ops::BitXor for Holding {
511 type Output = Self;
512
513 #[inline]
514 fn bitxor(self, rhs: Self) -> Self {
515 Self(self.0 ^ rhs.0)
516 }
517}
518
519impl ops::Not for Holding {
520 type Output = Self;
521
522 #[inline]
523 fn not(self) -> Self {
524 Self::from_bits_truncate(!self.0)
525 }
526}
527
528impl ops::Sub for Holding {
529 type Output = Self;
530
531 #[inline]
532 fn sub(self, rhs: Self) -> Self {
533 Self(self.0 & !rhs.0)
534 }
535}
536
537impl ops::BitAndAssign for Holding {
538 #[inline]
539 fn bitand_assign(&mut self, rhs: Self) {
540 *self = *self & rhs;
541 }
542}
543
544impl ops::BitOrAssign for Holding {
545 #[inline]
546 fn bitor_assign(&mut self, rhs: Self) {
547 *self = *self | rhs;
548 }
549}
550
551impl ops::BitXorAssign for Holding {
552 #[inline]
553 fn bitxor_assign(&mut self, rhs: Self) {
554 *self = *self ^ rhs;
555 }
556}
557
558impl ops::SubAssign for Holding {
559 #[inline]
560 fn sub_assign(&mut self, rhs: Self) {
561 *self = *self - rhs;
562 }
563}
564
565impl fmt::Display for Holding {
571 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
572 for rank in (2u8..15).rev() {
573 if self.0 & 1 << rank != 0 {
574 f.write_char(b"23456789TJQKA"[rank as usize - 2] as char)?;
575 }
576 }
577 Ok(())
578 }
579}
580
581#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
583#[non_exhaustive]
584pub enum ParseHoldingError {
585 #[error("Ranks are not all valid or in descending order")]
587 InvalidRanks,
588
589 #[error("The same rank appears more than once")]
591 RepeatedRank,
592
593 #[error("A suit contains more than 13 cards")]
595 TooManyCards,
596}
597
598#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
600#[non_exhaustive]
601pub enum ParseHandError {
602 #[error(transparent)]
604 Holding(#[from] ParseHoldingError),
605
606 #[error("The hand does not contain 4 suits")]
608 NotFourSuits,
609}
610
611#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
613#[non_exhaustive]
614pub enum ParseDealError {
615 #[error("Invalid dealer tag for a deal")]
617 InvalidDealer,
618
619 #[error(transparent)]
621 Hand(#[from] ParseHandError),
622
623 #[error("The deal does not contain 4 hands")]
625 NotFourHands,
626}
627
628impl FromStr for Holding {
629 type Err = ParseHoldingError;
630
631 fn from_str(s: &str) -> Result<Self, Self::Err> {
632 if s.len() > 14 {
634 return Err(ParseHoldingError::TooManyCards);
635 }
636
637 let bytes = s.as_bytes();
638 let mut i = 0;
639 let mut prev_rank: u8 = 15;
640 let mut explicit = Self::EMPTY;
641
642 while i < bytes.len() {
643 let c = bytes[i].to_ascii_uppercase();
644 let rank: u8 = match c {
645 b'A' => 14,
646 b'K' => 13,
647 b'Q' => 12,
648 b'J' => 11,
649 b'T' => 10,
650 b'1' => {
651 if bytes.get(i + 1) != Some(&b'0') {
652 return Err(ParseHoldingError::InvalidRanks);
653 }
654 i += 1;
655 10
656 }
657 b'2'..=b'9' => c - b'0',
658 b'X' => break,
659 _ => return Err(ParseHoldingError::InvalidRanks),
660 };
661
662 if rank >= prev_rank {
663 return Err(ParseHoldingError::InvalidRanks);
664 }
665 prev_rank = rank;
666
667 let r = Rank(unsafe { core::num::NonZero::new_unchecked(rank) });
669 explicit.insert(r);
670 i += 1;
671 }
672
673 let spot_count = bytes.len() - i;
674 if bytes[i..].iter().any(|&b| !b.eq_ignore_ascii_case(&b'x')) {
675 return Err(ParseHoldingError::InvalidRanks);
676 }
677 if spot_count > 13 {
678 return Err(ParseHoldingError::TooManyCards);
679 }
680
681 let spots = Self::from_bits_truncate((4u16 << spot_count) - 4);
682
683 if explicit & spots == Self::EMPTY {
684 Ok(explicit | spots)
685 } else {
686 Err(ParseHoldingError::RepeatedRank)
687 }
688 }
689}
690
691#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
693pub struct Hand([Holding; 4]);
694
695#[derive(Debug, Clone, PartialEq, Eq)]
698pub struct HandIter {
699 suits: [HoldingIter; 4],
700 fwd: u8,
701 bwd: u8,
702}
703
704impl Iterator for HandIter {
705 type Item = Card;
706
707 fn next(&mut self) -> Option<Self::Item> {
708 loop {
709 if self.fwd > 3 {
710 return None;
711 }
712 let suit = Suit::ASC[self.fwd as usize];
713 if let Some(rank) = self.suits[self.fwd as usize].next() {
714 return Some(Card { suit, rank });
715 }
716 if self.fwd == self.bwd {
717 self.fwd = 4;
718 return None;
719 }
720 self.fwd -= 1;
721 }
722 }
723
724 fn size_hint(&self) -> (usize, Option<usize>) {
725 let count = self.len();
726 (count, Some(count))
727 }
728
729 fn count(self) -> usize {
730 self.len()
731 }
732}
733
734impl DoubleEndedIterator for HandIter {
735 fn next_back(&mut self) -> Option<Self::Item> {
736 loop {
737 if self.fwd > 3 {
738 return None;
739 }
740 let suit = Suit::ASC[self.bwd as usize];
741 if let Some(rank) = self.suits[self.bwd as usize].next_back() {
742 return Some(Card { suit, rank });
743 }
744 if self.fwd == self.bwd {
745 self.fwd = 4;
746 return None;
747 }
748 self.bwd += 1;
749 }
750 }
751}
752
753impl ExactSizeIterator for HandIter {
754 fn len(&self) -> usize {
755 if self.fwd > 3 {
756 return 0;
757 }
758 (self.bwd as usize..=self.fwd as usize)
759 .map(|i| self.suits[i].len())
760 .sum()
761 }
762}
763
764impl FusedIterator for HandIter {}
765
766impl ops::Index<Suit> for Hand {
767 type Output = Holding;
768
769 #[inline]
770 fn index(&self, suit: Suit) -> &Holding {
771 &self.0[suit as usize]
772 }
773}
774
775impl ops::IndexMut<Suit> for Hand {
776 #[inline]
777 fn index_mut(&mut self, suit: Suit) -> &mut Holding {
778 &mut self.0[suit as usize]
779 }
780}
781
782impl Hand {
783 #[must_use]
785 #[inline]
786 pub const fn to_bits(self) -> u64 {
787 unsafe { core::mem::transmute(self.0) }
788 }
789
790 #[must_use]
792 #[inline]
793 pub const fn from_bits_retain(bits: u64) -> Self {
794 unsafe { core::mem::transmute(bits) }
795 }
796
797 #[must_use]
799 #[inline]
800 pub const fn contains_unknown_bits(self) -> bool {
801 self.to_bits() & Self::ALL.to_bits() != self.to_bits()
802 }
803
804 #[must_use]
806 #[inline]
807 pub const fn from_bits(bits: u64) -> Option<Self> {
808 if bits & Self::ALL.to_bits() == bits {
809 Some(Self::from_bits_retain(bits))
810 } else {
811 None
812 }
813 }
814
815 #[must_use]
817 #[inline]
818 pub const fn from_bits_truncate(bits: u64) -> Self {
819 Self::from_bits_retain(bits & Self::ALL.to_bits())
820 }
821
822 #[must_use]
824 #[inline]
825 pub const fn new(clubs: Holding, diamonds: Holding, hearts: Holding, spades: Holding) -> Self {
826 Self([clubs, diamonds, hearts, spades])
827 }
828
829 pub const EMPTY: Self = Self([Holding::EMPTY; 4]);
831
832 pub const ALL: Self = Self([Holding::ALL; 4]);
834
835 #[must_use]
837 #[inline]
838 pub const fn len(self) -> usize {
839 self.to_bits().count_ones() as usize
840 }
841
842 #[must_use]
844 #[inline]
845 pub const fn is_empty(self) -> bool {
846 self.to_bits() == 0
847 }
848
849 #[must_use]
851 #[inline]
852 pub fn contains(self, card: Card) -> bool {
853 self[card.suit].contains(card.rank)
854 }
855
856 #[inline]
858 pub fn insert(&mut self, card: Card) -> bool {
859 self[card.suit].insert(card.rank)
860 }
861
862 #[inline]
864 pub fn remove(&mut self, card: Card) -> bool {
865 self[card.suit].remove(card.rank)
866 }
867
868 #[inline]
870 pub fn toggle(&mut self, card: Card) -> bool {
871 self[card.suit].toggle(card.rank)
872 }
873
874 #[inline]
876 pub fn set(&mut self, card: Card, condition: bool) {
877 self[card.suit].set(card.rank, condition);
878 }
879
880 #[inline]
882 #[must_use]
883 pub const fn iter(self) -> HandIter {
884 HandIter {
885 suits: [
886 self.0[0].iter(),
887 self.0[1].iter(),
888 self.0[2].iter(),
889 self.0[3].iter(),
890 ],
891 fwd: 3,
892 bwd: 0,
893 }
894 }
895}
896
897impl IntoIterator for Hand {
898 type Item = Card;
899 type IntoIter = HandIter;
900
901 #[inline]
902 fn into_iter(self) -> HandIter {
903 self.iter()
904 }
905}
906
907impl FromIterator<Card> for Hand {
908 fn from_iter<I: IntoIterator<Item = Card>>(iter: I) -> Self {
909 iter.into_iter().fold(Self::EMPTY, |mut hand, card| {
910 hand.insert(card);
911 hand
912 })
913 }
914}
915
916impl fmt::Display for Hand {
920 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
921 if self.is_empty() {
922 return f.write_char('-');
923 }
924
925 self[Suit::Spades].fmt(f)?;
926 f.write_char('.')?;
927
928 self[Suit::Hearts].fmt(f)?;
929 f.write_char('.')?;
930
931 self[Suit::Diamonds].fmt(f)?;
932 f.write_char('.')?;
933
934 self[Suit::Clubs].fmt(f)
935 }
936}
937
938impl FromStr for Hand {
939 type Err = ParseHandError;
940
941 fn from_str(s: &str) -> Result<Self, Self::Err> {
942 if s.len() > 52 + 4 + 3 {
944 return Err(ParseHoldingError::TooManyCards.into());
945 }
946
947 if s == "-" {
948 return Ok(Self::EMPTY);
949 }
950
951 let holdings: Result<Vec<_>, _> = s.split('.').map(Holding::from_str).rev().collect();
952
953 Ok(Self(
954 holdings?
955 .try_into()
956 .map_err(|_| ParseHandError::NotFourSuits)?,
957 ))
958 }
959}
960
961impl ops::BitAnd for Hand {
962 type Output = Self;
963
964 #[inline]
965 fn bitand(self, rhs: Self) -> Self {
966 Self::from_bits_retain(self.to_bits() & rhs.to_bits())
967 }
968}
969
970impl ops::BitOr for Hand {
971 type Output = Self;
972
973 #[inline]
974 fn bitor(self, rhs: Self) -> Self {
975 Self::from_bits_retain(self.to_bits() | rhs.to_bits())
976 }
977}
978
979impl ops::BitXor for Hand {
980 type Output = Self;
981
982 #[inline]
983 fn bitxor(self, rhs: Self) -> Self {
984 Self::from_bits_retain(self.to_bits() ^ rhs.to_bits())
985 }
986}
987
988impl ops::Not for Hand {
989 type Output = Self;
990
991 #[inline]
992 fn not(self) -> Self {
993 Self::from_bits_truncate(!self.to_bits())
994 }
995}
996
997impl ops::Sub for Hand {
998 type Output = Self;
999
1000 #[inline]
1001 fn sub(self, rhs: Self) -> Self {
1002 Self::from_bits_retain(self.to_bits() & !rhs.to_bits())
1003 }
1004}
1005
1006impl ops::BitAndAssign for Hand {
1007 #[inline]
1008 fn bitand_assign(&mut self, rhs: Self) {
1009 *self = *self & rhs;
1010 }
1011}
1012
1013impl ops::BitOrAssign for Hand {
1014 #[inline]
1015 fn bitor_assign(&mut self, rhs: Self) {
1016 *self = *self | rhs;
1017 }
1018}
1019
1020impl ops::BitXorAssign for Hand {
1021 #[inline]
1022 fn bitxor_assign(&mut self, rhs: Self) {
1023 *self = *self ^ rhs;
1024 }
1025}
1026
1027impl ops::SubAssign for Hand {
1028 #[inline]
1029 fn sub_assign(&mut self, rhs: Self) {
1030 *self = *self - rhs;
1031 }
1032}
1033
1034#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
1055pub struct Deal([Hand; 4]);
1056
1057impl IntoIterator for Deal {
1058 type Item = Hand;
1059 type IntoIter = core::array::IntoIter<Hand, 4>;
1060
1061 #[inline]
1062 fn into_iter(self) -> Self::IntoIter {
1063 self.0.into_iter()
1064 }
1065}
1066
1067impl ops::Index<Seat> for Deal {
1068 type Output = Hand;
1069
1070 #[inline]
1071 fn index(&self, seat: Seat) -> &Hand {
1072 &self.0[seat as usize]
1073 }
1074}
1075
1076impl ops::IndexMut<Seat> for Deal {
1077 #[inline]
1078 fn index_mut(&mut self, seat: Seat) -> &mut Hand {
1079 &mut self.0[seat as usize]
1080 }
1081}
1082
1083impl Deal {
1084 pub const EMPTY: Self = Self([Hand::EMPTY; 4]);
1086
1087 #[must_use]
1089 pub const fn new(north: Hand, east: Hand, south: Hand, west: Hand) -> Self {
1090 Self([north, east, south, west])
1091 }
1092
1093 #[must_use]
1103 pub fn validate_and_collect(self) -> Option<Hand> {
1104 let mut seen = Hand::EMPTY;
1105 for hand in self.0 {
1106 if hand.len() > 13 || hand & seen != Hand::EMPTY {
1107 return None;
1108 }
1109 seen |= hand;
1110 }
1111 Some(seen)
1112 }
1113
1114 #[must_use]
1116 pub fn display(self, seat: Seat) -> impl fmt::Display {
1117 struct DisplayAt {
1118 deal: Deal,
1119 seat: Seat,
1120 }
1121 impl fmt::Display for DisplayAt {
1122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1123 f.write_char(self.seat.letter())?;
1124 f.write_char(':')?;
1125
1126 self.deal[self.seat].fmt(f)?;
1127 f.write_char(' ')?;
1128
1129 self.deal[self.seat.lho()].fmt(f)?;
1130 f.write_char(' ')?;
1131
1132 self.deal[self.seat.partner()].fmt(f)?;
1133 f.write_char(' ')?;
1134
1135 self.deal[self.seat.rho()].fmt(f)
1136 }
1137 }
1138 DisplayAt { deal: self, seat }
1139 }
1140}
1141
1142impl FromStr for Deal {
1143 type Err = ParseDealError;
1144
1145 fn from_str(s: &str) -> Result<Self, Self::Err> {
1146 let bytes = s.as_bytes();
1147
1148 let dealer = match bytes.first().map(u8::to_ascii_uppercase) {
1149 Some(b'N') => Seat::North,
1150 Some(b'E') => Seat::East,
1151 Some(b'S') => Seat::South,
1152 Some(b'W') => Seat::West,
1153 _ => return Err(ParseDealError::InvalidDealer),
1154 };
1155
1156 if bytes.get(1) != Some(&b':') {
1157 return Err(ParseDealError::InvalidDealer);
1158 }
1159
1160 let hands: Result<Vec<_>, _> = s[2..].split_whitespace().map(Hand::from_str).collect();
1161
1162 let mut deal = Self(
1163 hands?
1164 .try_into()
1165 .map_err(|_| ParseDealError::NotFourHands)?,
1166 );
1167 deal.0.rotate_right(dealer as usize);
1168 Ok(deal)
1169 }
1170}
1171
1172#[cfg(feature = "serde")]
1173mod serde_string {
1174 use super::{Card, Deal, Hand, Holding, Seat};
1175 use core::fmt::Display;
1176 use core::str::FromStr;
1177 use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
1178
1179 fn serialize<T: Display, S: Serializer>(value: &T, serializer: S) -> Result<S::Ok, S::Error> {
1180 serializer.collect_str(value)
1181 }
1182
1183 fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
1184 where
1185 T: FromStr,
1186 T::Err: Display,
1187 D: Deserializer<'de>,
1188 {
1189 let s = <&str>::deserialize(deserializer)?;
1190 s.parse().map_err(de::Error::custom)
1191 }
1192
1193 impl Serialize for Card {
1194 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1195 serialize(self, s)
1196 }
1197 }
1198 impl<'de> Deserialize<'de> for Card {
1199 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
1200 deserialize(d)
1201 }
1202 }
1203
1204 impl Serialize for Holding {
1205 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1206 serialize(self, s)
1207 }
1208 }
1209 impl<'de> Deserialize<'de> for Holding {
1210 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
1211 deserialize(d)
1212 }
1213 }
1214
1215 impl Serialize for Hand {
1216 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1217 serialize(self, s)
1218 }
1219 }
1220 impl<'de> Deserialize<'de> for Hand {
1221 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
1222 deserialize(d)
1223 }
1224 }
1225
1226 impl Serialize for Deal {
1227 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1228 s.collect_str(&self.display(Seat::North))
1229 }
1230 }
1231 impl<'de> Deserialize<'de> for Deal {
1232 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
1233 deserialize(d)
1234 }
1235 }
1236}