soliterm-model 0.1.0

Shared model types for soliterm
Documentation
use std::cmp::min;

use super::{Cards, Pile, PileMut};
use crate::card::Card;

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Split {
    pile: Cards,
    left_len: usize,
}

#[derive(Debug, Clone, Copy)]
pub struct Segment<'a>(&'a Split);

#[derive(Debug)]
pub struct SegmentMut<'a>(&'a mut Split);

impl Split {
    pub const fn empty() -> Self {
        Self {
            pile: Cards::empty(),
            left_len: 0,
        }
    }

    pub fn from_cards(pile: Cards, left_len: usize) -> Self {
        assert!(left_len <= pile.len());

        Self { pile, left_len }
    }

    pub fn from_left(left_pile: Cards) -> Self {
        let left_len = left_pile.len();

        Self {
            pile: left_pile,
            left_len,
        }
    }

    pub fn from_right(right_pile: Cards) -> Split {
        Self {
            pile: right_pile,
            left_len: 0,
        }
    }

    pub fn left(&self) -> Segment<'_> {
        Segment(self)
    }

    pub fn right(&self) -> Segment<'_> {
        Segment(self)
    }

    pub fn right_mut(&mut self) -> SegmentMut<'_> {
        SegmentMut(self)
    }

    pub fn cards_split(&self) -> (&[Card], &[Card]) {
        self.pile.cards().split_at(self.left_len)
    }

    pub fn set_left_length(&mut self, len: usize) {
        assert!(len <= self.len());

        self.left_len = len;
    }

    pub fn set_right_length(&mut self, len: usize) {
        assert!(len <= self.len());

        self.left_len = self.len() - len;
    }
}

impl IntoIterator for Split {
    type Item = Card;
    type IntoIter = impl Iterator<Item = Self::Item>
        + DoubleEndedIterator<Item = Self::Item>
        + ExactSizeIterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.pile.into_iter()
    }
}

impl<'a> IntoIterator for &'a Split {
    type Item = Card;
    type IntoIter = impl Iterator<Item = Self::Item>
        + DoubleEndedIterator<Item = Self::Item>
        + ExactSizeIterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        (&self.pile).into_iter()
    }
}

impl<'a> IntoIterator for Segment<'a> {
    type Item = Card;
    type IntoIter = impl Iterator<Item = Self::Item>
        + DoubleEndedIterator<Item = Self::Item>
        + ExactSizeIterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<'a> IntoIterator for &'a Segment<'a> {
    type Item = Card;
    type IntoIter = impl Iterator<Item = Self::Item>
        + DoubleEndedIterator<Item = Self::Item>
        + ExactSizeIterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<'a> IntoIterator for SegmentMut<'a> {
    type Item = Card;
    type IntoIter = impl Iterator<Item = Self::Item>
        + DoubleEndedIterator<Item = Self::Item>
        + ExactSizeIterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        (&*self.0).into_iter()
    }
}

impl<'a> IntoIterator for &'a SegmentMut<'a> {
    type Item = Card;
    type IntoIter = impl Iterator<Item = Self::Item>
        + DoubleEndedIterator<Item = Self::Item>
        + ExactSizeIterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        (&*self.0).into_iter()
    }
}

impl Extend<Card> for Split {
    fn extend<I>(&mut self, cards: I)
    where
        I: IntoIterator<Item = Card>,
    {
        self.place(cards);
    }
}

impl<'a> Extend<Card> for SegmentMut<'a> {
    fn extend<I>(&mut self, cards: I)
    where
        I: IntoIterator<Item = Card>,
    {
        self.place(cards);
    }
}

impl Pile for Split {
    fn cards(&self) -> &[Card] {
        self.pile.cards()
    }

    fn len(&self) -> usize {
        self.pile.len()
    }

    fn is_empty(&self) -> bool {
        self.pile.is_empty()
    }
}

impl PileMut for Split {
    fn take_at_most(&mut self, count: usize) -> Cards {
        let pile = self.pile.take_at_most(count);
        self.left_len = min(self.left_len, self.pile.len());

        pile
    }

    fn take_at_most_one(&mut self) -> Option<Card> {
        let card = self.pile.take_at_most_one();
        self.left_len = min(self.left_len, self.pile.len());

        card
    }

    fn take_or_none(&mut self, count: usize) -> Option<Cards> {
        let pile = self.pile.take_or_none(count);
        self.left_len = min(self.left_len, self.pile.len());

        pile
    }

    fn take_exactly(&mut self, count: usize) -> Cards {
        let pile = self.pile.take_exactly(count);
        self.left_len = min(self.left_len, self.pile.len());

        pile
    }

    fn take_exactly_one(&mut self) -> Card {
        let card = self.pile.take_exactly_one();
        self.left_len = min(self.left_len, self.pile.len());

        card
    }

    fn take_all(&mut self) -> Cards {
        self.left_len = 0;
        self.pile.take_all()
    }

    fn place<I>(&mut self, cards: I)
    where
        I: IntoIterator<Item = Card>,
    {
        self.pile.place(cards);
    }

    fn place_one(&mut self, card: Card) {
        self.pile.place_one(card);
    }
}

impl<'a> Pile for Segment<'a> {
    fn cards(&self) -> &[Card] {
        &self.0.pile.cards()[0..self.0.left_len]
    }

    fn len(&self) -> usize {
        self.0.left_len
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<'a> Pile for SegmentMut<'a> {
    fn cards(&self) -> &[Card] {
        &self.0.pile.cards()[self.0.left_len..]
    }

    fn len(&self) -> usize {
        self.0.len() - self.0.left_len
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl<'a> PileMut for SegmentMut<'a> {
    fn take_at_most(&mut self, count: usize) -> Cards {
        let capped_count = min(count, self.len());

        self.0.pile.take_at_most(capped_count)
    }

    fn take_at_most_one(&mut self) -> Option<Card> {
        (!self.is_empty()).then(|| self.0.pile.take_exactly_one())
    }

    fn take_or_none(&mut self, count: usize) -> Option<Cards> {
        (count <= self.len()).then(|| self.0.pile.take_exactly(count))
    }

    fn take_exactly(&mut self, count: usize) -> Cards {
        assert!(count <= self.len());

        self.0.pile.take_exactly(count)
    }

    fn take_exactly_one(&mut self) -> Card {
        assert!(!self.is_empty());

        self.0.pile.take_exactly_one()
    }

    fn take_all(&mut self) -> Cards {
        self.0.pile.take_exactly(self.len())
    }

    fn place<I>(&mut self, cards: I)
    where
        I: IntoIterator<Item = Card>,
    {
        self.0.pile.place(cards);
    }

    fn place_one(&mut self, card: Card) {
        self.0.pile.place_one(card);
    }
}