initiative_core/world/npc/
size.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
5#[serde(tag = "type")]
6pub enum Size {
7    Tiny { height: u16, weight: u16 },
8    Small { height: u16, weight: u16 },
9    Medium { height: u16, weight: u16 },
10    // Large { height: u16, weight: u16 },
11    // Huge { height: u16, weight: u16 },
12    // Gargantuan { height: u16, weight: u16 },
13}
14
15impl Size {
16    pub fn height_weight(&self) -> (u16, u16) {
17        match self {
18            Self::Tiny { height, weight } => (*height, *weight),
19            Self::Small { height, weight } => (*height, *weight),
20            Self::Medium { height, weight } => (*height, *weight),
21        }
22    }
23
24    pub fn height(&self) -> u16 {
25        self.height_weight().0
26    }
27
28    pub fn height_ft_in(&self) -> (u8, u8) {
29        let height = self.height();
30        ((height / 12) as u8, (height % 12) as u8)
31    }
32
33    pub fn weight(&self) -> u16 {
34        self.height_weight().1
35    }
36
37    pub fn name(&self) -> &'static str {
38        match self {
39            Self::Tiny { .. } => "tiny",
40            Self::Small { .. } => "small",
41            Self::Medium { .. } => "medium",
42        }
43    }
44}
45
46impl fmt::Display for Size {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        let (height_ft, height_in) = self.height_ft_in();
49        write!(
50            f,
51            "{}'{}\", {} lbs ({})",
52            height_ft,
53            height_in,
54            self.weight(),
55            self.name(),
56        )
57    }
58}
59
60#[cfg(test)]
61mod test {
62    use super::*;
63
64    #[test]
65    fn height_weight_test() {
66        assert_eq!(
67            (71, 140),
68            Size::Small {
69                height: 71,
70                weight: 140
71            }
72            .height_weight()
73        );
74
75        assert_eq!(
76            (71, 140),
77            Size::Medium {
78                height: 71,
79                weight: 140
80            }
81            .height_weight()
82        );
83    }
84
85    #[test]
86    fn height_test() {
87        assert_eq!(71, size().height());
88    }
89
90    #[test]
91    fn height_ft_in_test() {
92        assert_eq!((5, 11), size().height_ft_in());
93    }
94
95    #[test]
96    fn weight_test() {
97        assert_eq!(140, size().weight());
98    }
99
100    #[test]
101    fn name_test() {
102        assert_eq!(
103            "small",
104            Size::Small {
105                height: 0,
106                weight: 0
107            }
108            .name()
109        );
110        assert_eq!(
111            "medium",
112            Size::Medium {
113                height: 0,
114                weight: 0
115            }
116            .name()
117        );
118    }
119
120    #[test]
121    fn fmt_test() {
122        assert_eq!("5'11\", 140 lbs (medium)", format!("{}", size()));
123    }
124
125    #[test]
126    fn serialize_deserialize_test() {
127        assert_eq!(
128            r#"{"type":"Medium","height":71,"weight":140}"#,
129            serde_json::to_string(&size()).unwrap(),
130        );
131
132        let value: Size =
133            serde_json::from_str(r#"{"type":"Medium","height":71,"weight":140}"#).unwrap();
134        assert_eq!(size(), value);
135    }
136
137    fn size() -> Size {
138        Size::Medium {
139            height: 71,
140            weight: 140,
141        }
142    }
143}