firefly_types/
boards.rs

1use crate::encode::Encode;
2use alloc::borrow::Cow;
3use core::fmt::Display;
4use serde::{Deserialize, Serialize};
5
6pub enum BoardValidationError {
7    EmptyName,
8    NameTooLong,
9    MinGtMax,
10}
11
12impl BoardValidationError {
13    #[must_use]
14    pub const fn as_str(&self) -> &'static str {
15        match self {
16            Self::EmptyName => "name must not be empty",
17            Self::NameTooLong => "name is too long",
18            Self::MinGtMax => "min must be less than or equal to max",
19        }
20    }
21}
22
23impl Display for BoardValidationError {
24    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
25        write!(f, "{}", self.as_str())
26    }
27}
28
29#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
30pub struct Boards<'a> {
31    #[serde(borrow)]
32    pub boards: Cow<'a, [Board<'a>]>,
33}
34
35impl<'a> Boards<'a> {
36    #[must_use]
37    pub const fn new(boards: Cow<'a, [Board<'a>]>) -> Self {
38        Self { boards }
39    }
40}
41
42impl<'a> Encode<'a> for Boards<'a> {}
43
44#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
45pub struct Board<'a> {
46    /// The order in which the board should be displayed, ascending.
47    pub position: u16,
48
49    /// The minimum value for a score to be added to the board.
50    ///
51    /// It's possible to have negative scores when the app needs scores on the board
52    /// to be ordered in ascending order rather than descending.
53    /// So the default minimum is [`i16::MIN`] rather than 0.
54    pub min: i16,
55
56    /// The maximum value for a score to be added to the board.
57    ///
58    /// Useful for filtering out obvious cheating.
59    pub max: i16,
60
61    /// If the score should be formatted as time.
62    pub time: bool,
63
64    /// Digits after decimal point.
65    pub decimals: u8,
66
67    /// Human-readable board name.
68    pub name: &'a str,
69}
70
71impl Board<'_> {
72    /// Validate board attributes.
73    ///
74    /// # Errors
75    ///
76    /// Returns [`BoardValidationError`] if any of the attributes are not valid.
77    pub const fn validate(&self) -> Result<(), BoardValidationError> {
78        if self.name.is_empty() {
79            return Err(BoardValidationError::EmptyName);
80        }
81        if self.name.len() > 64 {
82            return Err(BoardValidationError::NameTooLong);
83        }
84        if self.min > self.max {
85            return Err(BoardValidationError::MinGtMax);
86        }
87        Ok(())
88    }
89}