1use crate::hand::{Hand, ParseHandError};
28use crate::seat::Seat;
29use core::fmt::{self, Write as _};
30use core::ops;
31use core::str::FromStr;
32use thiserror::Error;
33
34#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
36#[non_exhaustive]
37pub enum ParseDealError {
38 #[error("Invalid dealer tag for a deal")]
40 InvalidDealer,
41
42 #[error(transparent)]
44 Hand(#[from] ParseHandError),
45
46 #[error("The deal does not contain 4 hands")]
48 NotFourHands,
49
50 #[error("The deal is not a valid subset (>13 cards per hand or overlapping hands)")]
53 InvalidPartialDeal,
54
55 #[error("The deal is not a full deal (each hand must have exactly 13 cards)")]
57 NotFullDeal,
58}
59
60#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
71pub struct Builder([Hand; 4]);
72
73impl IntoIterator for Builder {
74 type Item = Hand;
75 type IntoIter = core::array::IntoIter<Hand, 4>;
76
77 #[inline]
78 fn into_iter(self) -> Self::IntoIter {
79 self.0.into_iter()
80 }
81}
82
83impl ops::Index<Seat> for Builder {
84 type Output = Hand;
85
86 #[inline]
87 fn index(&self, seat: Seat) -> &Hand {
88 &self.0[seat as usize]
89 }
90}
91
92impl ops::IndexMut<Seat> for Builder {
93 #[inline]
94 fn index_mut(&mut self, seat: Seat) -> &mut Hand {
95 &mut self.0[seat as usize]
96 }
97}
98
99impl Builder {
100 #[must_use]
102 pub const fn new() -> Self {
103 Self([Hand::EMPTY; 4])
104 }
105
106 #[must_use]
108 pub const fn north(mut self, hand: Hand) -> Self {
109 self.0[Seat::North as usize] = hand;
110 self
111 }
112
113 #[must_use]
115 pub const fn east(mut self, hand: Hand) -> Self {
116 self.0[Seat::East as usize] = hand;
117 self
118 }
119
120 #[must_use]
122 pub const fn south(mut self, hand: Hand) -> Self {
123 self.0[Seat::South as usize] = hand;
124 self
125 }
126
127 #[must_use]
129 pub const fn west(mut self, hand: Hand) -> Self {
130 self.0[Seat::West as usize] = hand;
131 self
132 }
133
134 pub fn build_partial(self) -> Result<PartialDeal, Self> {
142 let mut seen = Hand::EMPTY;
143 for hand in self.0 {
144 if hand.len() > 13 || hand & seen != Hand::EMPTY {
145 return Err(self);
146 }
147 seen |= hand;
148 }
149 Ok(PartialDeal(self))
150 }
151
152 pub fn build_full(self) -> Result<FullDeal, Self> {
160 match self.build_partial() {
161 Ok(subset) if subset.len() == 52 => Ok(FullDeal(subset.0)),
162 Ok(subset) => Err(subset.0),
163 Err(builder) => Err(builder),
164 }
165 }
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
186#[cfg_attr(
187 feature = "serde",
188 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
189)]
190pub struct PartialDeal(Builder);
191
192impl ops::Index<Seat> for PartialDeal {
193 type Output = Hand;
194
195 #[inline]
196 fn index(&self, seat: Seat) -> &Hand {
197 &self.0[seat]
198 }
199}
200
201impl PartialDeal {
202 pub const EMPTY: Self = Self(Builder::new());
204
205 #[must_use]
207 pub fn collected(&self) -> Hand {
208 self.0.into_iter().fold(Hand::EMPTY, |a, h| a | h)
209 }
210
211 #[must_use]
213 pub fn len(&self) -> usize {
214 self.collected().len()
215 }
216
217 #[must_use]
219 pub fn is_empty(&self) -> bool {
220 self.collected().is_empty()
221 }
222
223 #[must_use]
225 pub fn display(&self, seat: Seat) -> impl fmt::Display + use<> {
226 DisplayAt {
227 builder: self.0,
228 seat,
229 }
230 }
231}
232
233impl From<PartialDeal> for Builder {
234 #[inline]
235 fn from(subset: PartialDeal) -> Self {
236 subset.0
237 }
238}
239
240impl TryFrom<Builder> for PartialDeal {
241 type Error = Builder;
242
243 #[inline]
244 fn try_from(builder: Builder) -> Result<Self, Self::Error> {
245 builder.build_partial()
246 }
247}
248
249impl FromStr for PartialDeal {
250 type Err = ParseDealError;
251
252 fn from_str(s: &str) -> Result<Self, Self::Err> {
253 parse_pbn(s)?
254 .build_partial()
255 .map_err(|_| ParseDealError::InvalidPartialDeal)
256 }
257}
258
259impl fmt::Display for PartialDeal {
260 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
261 self.display(Seat::North).fmt(f)
262 }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
292#[cfg_attr(
293 feature = "serde",
294 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
295)]
296pub struct FullDeal(Builder);
297
298impl ops::Index<Seat> for FullDeal {
299 type Output = Hand;
300
301 #[inline]
302 fn index(&self, seat: Seat) -> &Hand {
303 &self.0[seat]
304 }
305}
306
307impl IntoIterator for FullDeal {
308 type Item = Hand;
309 type IntoIter = core::array::IntoIter<Hand, 4>;
310
311 #[inline]
312 fn into_iter(self) -> Self::IntoIter {
313 self.0.into_iter()
314 }
315}
316
317impl FullDeal {
318 #[must_use]
320 pub fn display(&self, seat: Seat) -> impl fmt::Display + use<> {
321 DisplayAt {
322 builder: self.0,
323 seat,
324 }
325 }
326}
327
328impl From<FullDeal> for Builder {
329 #[inline]
330 fn from(deal: FullDeal) -> Self {
331 deal.0
332 }
333}
334
335impl From<FullDeal> for PartialDeal {
336 #[inline]
337 fn from(deal: FullDeal) -> Self {
338 Self(deal.0)
339 }
340}
341
342impl TryFrom<Builder> for FullDeal {
343 type Error = Builder;
344
345 #[inline]
346 fn try_from(builder: Builder) -> Result<Self, Self::Error> {
347 builder.build_full()
348 }
349}
350
351impl TryFrom<PartialDeal> for FullDeal {
352 type Error = PartialDeal;
353
354 #[inline]
355 fn try_from(subset: PartialDeal) -> Result<Self, Self::Error> {
356 match subset.0.build_full() {
357 Ok(full) => Ok(full),
358 Err(builder) => Err(PartialDeal(builder)),
359 }
360 }
361}
362
363impl FromStr for FullDeal {
364 type Err = ParseDealError;
365
366 fn from_str(s: &str) -> Result<Self, Self::Err> {
367 parse_pbn(s)?
368 .build_full()
369 .map_err(|_| ParseDealError::NotFullDeal)
370 }
371}
372
373impl fmt::Display for FullDeal {
374 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
375 self.display(Seat::North).fmt(f)
376 }
377}
378
379fn parse_pbn(s: &str) -> Result<Builder, ParseDealError> {
382 let bytes = s.as_bytes();
383
384 let dealer = match bytes.first().map(u8::to_ascii_uppercase) {
385 Some(b'N') => Seat::North,
386 Some(b'E') => Seat::East,
387 Some(b'S') => Seat::South,
388 Some(b'W') => Seat::West,
389 _ => return Err(ParseDealError::InvalidDealer),
390 };
391
392 if bytes.get(1) != Some(&b':') {
393 return Err(ParseDealError::InvalidDealer);
394 }
395
396 let hands: Result<Vec<_>, _> = s[2..].split_whitespace().map(Hand::from_str).collect();
397
398 let mut builder = Builder(
399 hands?
400 .try_into()
401 .map_err(|_| ParseDealError::NotFourHands)?,
402 );
403 builder.0.rotate_right(dealer as usize);
404 Ok(builder)
405}
406
407struct DisplayAt {
409 builder: Builder,
410 seat: Seat,
411}
412
413impl fmt::Display for DisplayAt {
414 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415 f.write_char(self.seat.letter())?;
416 f.write_char(':')?;
417
418 self.builder[self.seat].fmt(f)?;
419 f.write_char(' ')?;
420
421 self.builder[self.seat.lho()].fmt(f)?;
422 f.write_char(' ')?;
423
424 self.builder[self.seat.partner()].fmt(f)?;
425 f.write_char(' ')?;
426
427 self.builder[self.seat.rho()].fmt(f)
428 }
429}