1use std::fmt;
2
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum GridError {
6 ParseError(String),
7}
8
9#[derive(serde::Deserialize, serde::Serialize)]
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct Grid {
12 value: u32,
13}
14
15impl Grid {
16 pub fn value_of(s: &str) -> Result<Self, GridError> {
17 s.parse::<u32>()
18 .map_err(|_| {
19 GridError::ParseError(s.to_owned())
20 })
21 .and_then(|i| {
22 Self::from_u32(i)
23 })
24 }
25
26 #[inline]
27 pub fn from_u32(i: u32) -> Result<Self, GridError> {
28 if i == 0 {
29 Err(GridError::ParseError("0".to_owned()))
30 } else {
31 Ok(Self { value: i })
32 }
33 }
34
35 #[inline]
36 pub fn as_u32(self) -> u32 {
37 self.value
38 }
39
40 #[inline]
41 pub fn snap(self, tick: i64) -> i64 {
42 let i = self.value as i64;
43 if tick < 0 {
44 i * ((tick - i / 2) / i)
45 } else {
46 i * ((tick + i / 2) / i)
47 }
48 }
49}
50
51impl Default for Grid {
52 fn default() -> Self {
53 Self { value: 60 }
54 }
55}
56
57impl fmt::Display for Grid {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(f, "{}", self.value)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::grid::{Grid, GridError};
66
67 #[test]
68 fn empty_str() {
69 assert_eq!(Grid::value_of(""), Err(GridError::ParseError("".to_owned())));
70 }
71
72
73 #[test]
74 fn non_numerical_str() {
75 assert_eq!(Grid::value_of("1a"), Err(GridError::ParseError("1a".to_owned())));
76 }
77
78 #[test]
79 fn zero() {
80 assert_eq!(Grid::value_of("0"), Err(GridError::ParseError("0".to_owned())));
81 }
82
83 #[test]
84 fn ok() {
85 assert_eq!(Grid::value_of("120"), Ok(Grid { value: 120 }));
86 }
87
88 #[test]
89 fn snap() {
90 assert_eq!(Grid::from_u32(100).unwrap().snap(49), 0);
91 assert_eq!(Grid::from_u32(100).unwrap().snap(50), 100);
92 assert_eq!(Grid::from_u32(100).unwrap().snap(99), 100);
93 assert_eq!(Grid::from_u32(100).unwrap().snap(149), 100);
94 assert_eq!(Grid::from_u32(100).unwrap().snap(150), 200);
95 assert_eq!(Grid::from_u32(100).unwrap().snap(199), 200);
96 assert_eq!(Grid::from_u32(100).unwrap().snap(249), 200);
97
98 assert_eq!(Grid::from_u32(100).unwrap().snap(-49), 0);
99 assert_eq!(Grid::from_u32(100).unwrap().snap(-50), -100);
100 }
101}