use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Stage {
GroupStage,
RoundOf32,
RoundOf16,
QuarterFinal,
SemiFinal,
ThirdPlace,
Final,
}
impl Stage {
#[must_use]
pub fn knockout_order() -> [Stage; 6] {
[
Stage::RoundOf32,
Stage::RoundOf16,
Stage::QuarterFinal,
Stage::SemiFinal,
Stage::ThirdPlace,
Stage::Final,
]
}
#[must_use]
pub fn is_knockout(self) -> bool {
!matches!(self, Stage::GroupStage)
}
#[must_use]
pub fn label(self) -> &'static str {
match self {
Stage::GroupStage => "Group Stage",
Stage::RoundOf32 => "Round of 32",
Stage::RoundOf16 => "Round of 16",
Stage::QuarterFinal => "Quarter-final",
Stage::SemiFinal => "Semi-final",
Stage::ThirdPlace => "Third place",
Stage::Final => "Final",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Team {
pub id: String,
pub name: String,
pub abbreviation: String,
pub country_code: Option<String>,
pub crest_url: Option<String>,
}
impl Team {
#[must_use]
pub fn placeholder(label: impl Into<String>) -> Self {
let name = label.into();
Self {
id: String::new(),
abbreviation: name.chars().take(3).collect::<String>().to_uppercase(),
name,
country_code: None,
crest_url: None,
}
}
#[must_use]
pub fn is_placeholder(&self) -> bool {
self.id.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum MatchStatus {
Scheduled,
Live {
minute: Option<u16>,
detail: Option<String>,
},
HalfTime,
FullTime,
AfterExtraTime,
Penalties,
Postponed,
Canceled,
Unknown,
}
impl MatchStatus {
#[must_use]
pub fn is_live(&self) -> bool {
matches!(self, MatchStatus::Live { .. } | MatchStatus::HalfTime)
}
#[must_use]
pub fn is_finished(&self) -> bool {
matches!(
self,
MatchStatus::FullTime | MatchStatus::AfterExtraTime | MatchStatus::Penalties
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Score {
pub home: u8,
pub away: u8,
pub home_pens: Option<u8>,
pub away_pens: Option<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Match {
pub id: String,
pub stage: Stage,
pub group: Option<String>,
pub home: Team,
pub away: Team,
pub score: Option<Score>,
pub status: MatchStatus,
#[serde(with = "time::serde::rfc3339")]
pub kickoff: OffsetDateTime,
pub venue: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct GroupStanding {
pub team: Team,
pub rank: u8,
pub played: u8,
pub won: u8,
pub drawn: u8,
pub lost: u8,
pub goals_for: u16,
pub goals_against: u16,
pub goal_diff: i16,
pub points: u16,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Group {
pub name: String,
pub standings: Vec<GroupStanding>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MatchEventKind {
Goal,
OwnGoal,
PenaltyGoal,
PenaltyMiss,
YellowCard,
SecondYellow,
RedCard,
Substitution,
Var,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MatchEvent {
pub minute: Option<u16>,
pub stoppage: Option<u16>,
pub kind: MatchEventKind,
pub team_id: Option<String>,
pub player: Option<String>,
pub detail: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Player {
pub name: String,
pub number: Option<u8>,
pub position: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Lineup {
pub team_id: String,
pub formation: Option<String>,
pub starters: Vec<Player>,
pub substitutes: Vec<Player>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TeamStat {
pub label: String,
pub home: String,
pub away: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MatchDetail {
pub summary: Match,
pub events: Vec<MatchEvent>,
pub lineups: Vec<Lineup>,
pub stats: Vec<TeamStat>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BracketRound {
pub stage: Stage,
pub matches: Vec<Match>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Bracket {
pub rounds: Vec<BracketRound>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StageWindow {
pub stage: Stage,
pub label: String,
#[serde(with = "time::serde::rfc3339")]
pub start: OffsetDateTime,
#[serde(with = "time::serde::rfc3339")]
pub end: OffsetDateTime,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Calendar {
pub stages: Vec<StageWindow>,
}