arma_rs/value/loadout/
inventory_item.rs

1use crate::{FromArma, FromArmaError, IntoArma, Value};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4/// An item stored in a uniform, vest, or backpack
5pub enum InventoryItem {
6    /// An item that is not a magazine
7    Item(String, u32),
8    /// A magazine
9    Magazine(String, u32, u32),
10}
11impl InventoryItem {
12    /// Create a new item
13    #[must_use]
14    pub const fn new_item(class: String, count: u32) -> Self {
15        Self::Item(class, count)
16    }
17
18    /// Create a new magazine
19    #[must_use]
20    pub const fn new_magazine(class: String, count: u32, ammo: u32) -> Self {
21        Self::Magazine(class, count, ammo)
22    }
23
24    /// The item is a magazine
25    #[must_use]
26    pub const fn is_magazine(&self) -> bool {
27        matches!(self, Self::Magazine(_, _, _))
28    }
29
30    /// The class name of the item
31    #[must_use]
32    pub fn class(&self) -> &str {
33        match self {
34            Self::Item(c, _) | Self::Magazine(c, _, _) => c.as_str(),
35        }
36    }
37
38    /// Set the class name of the item
39    pub fn set_class(&mut self, class: String) {
40        match self {
41            Self::Item(c, _) | Self::Magazine(c, _, _) => *c = class,
42        }
43    }
44
45    /// The amount of the item
46    #[must_use]
47    pub fn count(&self) -> u32 {
48        match self {
49            Self::Item(_, c) | Self::Magazine(_, c, _) => c.to_owned(),
50        }
51    }
52
53    /// Set the amount of the item
54    pub fn set_count(&mut self, count: u32) {
55        match self {
56            Self::Item(_, c) | Self::Magazine(_, c, _) => *c = count,
57        }
58    }
59
60    /// The amount of ammo in the magazine
61    #[must_use]
62    pub fn ammo(&self) -> Option<u32> {
63        match self {
64            Self::Item(..) => None,
65            Self::Magazine(_, _, a) => Some(a.to_owned()),
66        }
67    }
68
69    /// Set the amount of ammo in the magazine
70    /// Returns true if the ammo was set, false if the item is not a magazine
71    pub fn set_ammo(&mut self, ammo: u32) -> bool {
72        match self {
73            Self::Magazine(_, _, a) => {
74                *a = ammo;
75                true
76            }
77            Self::Item(..) => false,
78        }
79    }
80}
81impl FromArma for InventoryItem {
82    fn from_arma(s: String) -> Result<Self, FromArmaError> {
83        let commas = s.matches(',').count();
84        match commas {
85            1 => <(String, u32)>::from_arma(s).map(|(name, count)| Self::Item(name, count)),
86            2 => <(String, u32, u32)>::from_arma(s)
87                .map(|(name, count, ammo)| Self::Magazine(name, count, ammo)),
88            _ => Err(FromArmaError::custom(format!(
89                "Invalid inventory item: {s}"
90            ))),
91        }
92    }
93}
94impl IntoArma for InventoryItem {
95    fn to_arma(&self) -> Value {
96        match self {
97            Self::Item(name, count) => Value::Array(vec![
98                Value::String(name.clone()),
99                Value::Number(f64::from(*count)),
100            ]),
101            Self::Magazine(name, count, ammo) => Value::Array(vec![
102                Value::String(name.clone()),
103                Value::Number(f64::from(*count)),
104                Value::Number(f64::from(*ammo)),
105            ]),
106        }
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use crate::{FromArma, IntoArma, Value};
113
114    use super::InventoryItem;
115
116    #[test]
117    fn is() {
118        let item = InventoryItem::new_item("test".to_owned(), 1);
119        assert_eq!(item.class(), "test");
120        assert_eq!(item.count(), 1);
121        assert_eq!(item.ammo(), None);
122        assert!(!item.is_magazine());
123        let item = InventoryItem::new_magazine("test".to_owned(), 1, 1);
124        assert_eq!(item.class(), "test");
125        assert_eq!(item.count(), 1);
126        assert_eq!(item.ammo(), Some(1));
127        assert!(item.is_magazine());
128    }
129
130    #[test]
131    fn class() {
132        let mut item = InventoryItem::new_item("test".to_owned(), 1);
133        assert_eq!(item.class(), "test");
134        item.set_class("test2".to_owned());
135        assert_eq!(item.class(), "test2");
136    }
137
138    #[test]
139    fn count() {
140        let mut item = InventoryItem::new_item("test".to_owned(), 1);
141        assert_eq!(item.count(), 1);
142        item.set_count(2);
143        assert_eq!(item.count(), 2);
144    }
145
146    #[test]
147    fn ammo() {
148        let item = InventoryItem::new_magazine("test".to_owned(), 1, 1);
149        assert_eq!(item.ammo(), Some(1));
150        assert!(item.is_magazine());
151        let item = InventoryItem::new_item("test".to_owned(), 1);
152        assert_eq!(item.ammo(), None);
153        assert!(!item.is_magazine());
154    }
155
156    #[test]
157    fn from_arma() {
158        let item = InventoryItem::from_arma("[\"test\",1]".to_owned()).unwrap();
159        assert_eq!(item.class(), "test");
160        assert_eq!(item.count(), 1);
161        assert_eq!(item.ammo(), None);
162        assert!(!item.is_magazine());
163        let item = InventoryItem::from_arma("[\"test\",1,1]".to_owned()).unwrap();
164        assert_eq!(item.class(), "test");
165        assert_eq!(item.count(), 1);
166        assert_eq!(item.ammo(), Some(1));
167        assert!(item.is_magazine());
168    }
169
170    #[test]
171    fn to_arma() {
172        let item = InventoryItem::new_item("test".to_owned(), 1);
173        assert_eq!(
174            item.to_arma(),
175            Value::Array(vec![Value::String("test".to_owned()), Value::Number(1.0),])
176        );
177        let item = InventoryItem::new_magazine("test".to_owned(), 1, 1);
178        assert_eq!(
179            item.to_arma(),
180            Value::Array(vec![
181                Value::String("test".to_owned()),
182                Value::Number(1.0),
183                Value::Number(1.0),
184            ])
185        );
186    }
187}