tournaments 0.1.0-alpha2

Rust library for running tournaments
Documentation
mod factory;

pub use factory::Factory;
use std::cell::RefCell;

use crate::contestant;
use crate::contestant::Contestant;
use crate::match_contender::MatchContender;
use std::rc::Rc;

pub type Id = u32;
pub type Contenders = [Box<dyn MatchContender>; 2];
pub type RcMatch = Rc<RefCell<Match>>;

#[derive(Clone)]
pub enum MatchState {
    NotReady,
    Ready,
    Won(Rc<Contestant>),
}

#[allow(dead_code)]
pub struct Match {
    id: Id,
    contenders: Contenders,
    winner: Option<Rc<Contestant>>,
}

#[allow(dead_code)]
impl Match {
    pub fn new(id: Id, contestants: Contenders) -> Self {
        Self {
            id,
            contenders: contestants,
            winner: None,
        }
    }

    pub fn id(&self) -> &Id {
        &self.id
    }
    pub fn contestants(&self) -> &Contenders {
        &self.contenders
    }

    pub fn state(&self) -> MatchState {
        match &self.winner {
            None => {
                let not_ready_contender = self.contenders.iter().find(|c| c.contestant().is_none());
                match not_ready_contender {
                    None => MatchState::Ready,
                    Some(_) => MatchState::NotReady,
                }
            }
            Some(winner) => MatchState::Won(winner.clone()),
        }
    }

    pub fn set_winner(&mut self, id: &contestant::Id) -> Result<(), SetWinnerError> {
        if !matches!(self.state(), MatchState::Ready) {
            return Err(SetWinnerError::InvalidState);
        }

        let maybe_winner = self
            .contenders
            .iter()
            .find(|c| c.contestant().unwrap().id() == id);

        match maybe_winner {
            None => Err(SetWinnerError::InvalidId),
            Some(winner) => {
                self.winner = winner.contestant();
                Ok(())
            }
        }
    }
}

#[derive(Debug)]
pub enum SetWinnerError {
    InvalidId,
    InvalidState,
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::match_contender::tests::dummy_contenders;
    use std::rc::Rc;

    struct NoContender;
    impl MatchContender for NoContender {
        fn contestant(&self) -> Option<Rc<Contestant>> {
            None
        }
    }

    #[test]
    fn not_ready() {
        let contestants: Contenders = [Box::new(NoContender), Box::new(NoContender)];

        let match_ = Match::new(0, contestants);

        assert!(matches!(match_.state(), MatchState::NotReady));
    }

    #[test]
    fn ready() {
        let contestants = dummy_contenders();
        let match_ = Match::new(0, contestants);

        assert!(matches!(match_.state(), MatchState::Ready));
    }

    #[test]
    fn set_winner() {
        let contestants = dummy_contenders();
        let mut match_ = Match::new(0, contestants);
        let winner = match_.contestants().first().unwrap().contestant().unwrap();

        match_.set_winner(winner.id()).unwrap();

        assert!(matches!(match_.state(), MatchState::Won(_)));
    }
}