planter_core/
resources.rs

1use crate::person::Person;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4/// Represents a resource that can be used in a project. A resource can be either a material or personnel.
5pub enum Resource {
6    /// Represents a material resource that can be used in a project.
7    Material(Material),
8    /// Represents a personnel resource. Personnel is usually a resource that can complete tasks
9    Personnel {
10        /// Information about the person.
11        person: Person,
12        /// Hourly rate of the person.
13        hourly_rate: Option<u16>,
14    },
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18/// Represents a material resource that can be used in a project.
19/// It can be either consumable or non-consumable.
20pub enum Material {
21    /// A consumable resource is a material that needs to be resupplied after use.
22    Consumable(Consumable),
23    /// A non-consumable resource is a material that does not need to be resupplied after use.
24    NonConsumable(NonConsumable),
25}
26
27impl Default for Material {
28    fn default() -> Self {
29        Material::new("")
30    }
31}
32
33#[derive(Debug, Clone, Default, PartialEq, Eq)]
34/// Represents a consumable material resource that can be used in a project.
35pub struct Consumable {
36    /// Name of the consumable material.
37    name: String,
38    /// Available quantity of the consumable material.
39    quantity: Option<u16>,
40    /// Cost to buy this material.
41    cost_per_unit: Option<u16>,
42}
43
44#[derive(Debug, Clone, Default, PartialEq, Eq)]
45/// Represents a non-consumable material resource that can be used in a project.
46pub struct NonConsumable {
47    /// Name of the non-consumable material.
48    name: String,
49    /// Available quantity of the non-consumable material.
50    quantity: Option<u16>,
51    /// Cost to buy this material.
52    cost_per_unit: Option<u16>,
53    /// Some non consumable materials can have a hourly rate. For example, due to energy consumption.
54    hourly_rate: Option<u16>,
55}
56
57impl From<NonConsumable> for Consumable {
58    fn from(value: NonConsumable) -> Self {
59        Consumable {
60            name: value.name,
61            quantity: value.quantity,
62            cost_per_unit: value.quantity,
63        }
64    }
65}
66
67impl From<Consumable> for NonConsumable {
68    fn from(value: Consumable) -> Self {
69        NonConsumable {
70            name: value.name,
71            quantity: value.quantity,
72            cost_per_unit: value.cost_per_unit,
73            hourly_rate: None,
74        }
75    }
76}
77
78impl Material {
79    /// Returns a consumable material by default, with the given name.
80    pub fn new(name: impl Into<String>) -> Self {
81        Material::Consumable(Consumable::new(name))
82    }
83
84    /// Returns the name of the material.
85    /// # Example
86    /// ```
87    /// use planter_core::resources::Material;
88    ///
89    /// let material = Material::new("Steel".to_owned());
90    /// assert_eq!(material.name(), "Steel");
91    /// ```
92    pub fn name(&self) -> &str {
93        match self {
94            Material::Consumable(consumable) => &consumable.name,
95            Material::NonConsumable(non_consumable) => &non_consumable.name,
96        }
97    }
98
99    /// Updates the name of the material.
100    /// # Example
101    /// ```
102    /// use planter_core::resources::Material;
103    ///
104    /// let mut material = Material::new("Steel".to_owned());
105    /// material.update_name("Iron".to_owned());
106    /// assert_eq!(material.name(), "Iron");
107    /// ```
108    pub fn update_name(&mut self, name: impl Into<String>) {
109        match self {
110            Material::Consumable(consumable) => consumable.name = name.into(),
111            Material::NonConsumable(non_consumable) => non_consumable.name = name.into(),
112        }
113    }
114
115    /// Returns the quantity of materials.
116    /// # Example
117    /// ```
118    /// use planter_core::resources::Material;
119    ///
120    /// let material = Material::new("Steel".to_owned());
121    /// assert_eq!(material.quantity(), None);
122    /// ```
123    pub fn quantity(&self) -> Option<u16> {
124        match self {
125            Material::Consumable(consumable) => consumable.quantity,
126            Material::NonConsumable(non_consumable) => non_consumable.quantity,
127        }
128    }
129
130    /// Updates the quantity of materials.
131    /// # Example
132    /// ```
133    /// use planter_core::resources::Material;
134    ///
135    /// let mut material = Material::new("Steel".to_owned());
136    /// material.update_quantity(3);
137    /// assert_eq!(material.quantity(), Some(3));
138    /// ```
139    pub fn update_quantity(&mut self, quantity: u16) {
140        match self {
141            Material::Consumable(consumable) => consumable.quantity = Some(quantity),
142            Material::NonConsumable(non_consumable) => non_consumable.quantity = Some(quantity),
143        }
144    }
145
146    /// Remove the quantity of materials.
147    /// # Example
148    /// ```
149    /// use planter_core::resources::Material;
150    ///
151    /// let mut material = Material::new("Steel".to_owned());
152    /// material.update_quantity(3);
153    /// assert_eq!(material.quantity(), Some(3));
154    /// material.remove_quantity();
155    /// assert_eq!(material.quantity(), None);
156    /// ```
157    pub fn remove_quantity(&mut self) {
158        match self {
159            Material::Consumable(consumable) => consumable.quantity = None,
160            Material::NonConsumable(non_consumable) => non_consumable.quantity = None,
161        }
162    }
163    /// Returns the cost per unit of the material.
164    /// # Example
165    /// ```
166    /// use planter_core::resources::Material;
167    ///
168    /// let material = Material::new("Steel".to_owned());
169    /// assert_eq!(material.cost_per_unit(), None);
170    /// ```
171    pub fn cost_per_unit(&self) -> Option<u16> {
172        match self {
173            Material::Consumable(consumable) => consumable.cost_per_unit,
174            Material::NonConsumable(non_consumable) => non_consumable.cost_per_unit,
175        }
176    }
177
178    /// Updates the cost per unit of the material.
179    /// # Example
180    /// ```
181    /// use planter_core::resources::Material;
182    ///
183    /// let mut material = Material::new("Steel".to_owned());
184    /// material.update_cost_per_unit(3);
185    /// assert_eq!(material.cost_per_unit(), Some(3));
186    /// ```
187    pub fn update_cost_per_unit(&mut self, cost_per_unit: u16) {
188        match self {
189            Material::Consumable(consumable) => consumable.cost_per_unit = Some(cost_per_unit),
190            Material::NonConsumable(non_consumable) => {
191                non_consumable.cost_per_unit = Some(cost_per_unit)
192            }
193        }
194    }
195
196    /// Remove the cost per unit of the material.
197    /// # Example
198    /// ```
199    /// use planter_core::resources::Material;
200    ///
201    /// let mut material = Material::new("Steel".to_owned());
202    /// material.update_cost_per_unit(3);
203    /// assert_eq!(material.cost_per_unit(), Some(3));
204    /// material.remove_cost_per_unit();
205    /// assert_eq!(material.cost_per_unit(), None);
206    /// ```
207    pub fn remove_cost_per_unit(&mut self) {
208        match self {
209            Material::Consumable(consumable) => consumable.cost_per_unit = None,
210            Material::NonConsumable(non_consumable) => non_consumable.cost_per_unit = None,
211        }
212    }
213}
214
215impl Consumable {
216    /// Creates a new consumable material resource.
217    pub fn new(name: impl Into<String>) -> Self {
218        Consumable {
219            name: name.into(),
220            quantity: None,
221            cost_per_unit: None,
222        }
223    }
224}
225
226impl NonConsumable {
227    /// Creates a new non-consumable material resource.
228    pub fn new(name: impl Into<String>) -> Self {
229        NonConsumable {
230            name: name.into(),
231            quantity: None,
232            hourly_rate: None,
233            cost_per_unit: None,
234        }
235    }
236
237    /// Returns the hourly rate of the non-consumable material.
238    /// # Example
239    /// ```
240    /// use planter_core::resources::NonConsumable;
241    ///
242    /// let non_consumable = NonConsumable::new("Steel".to_owned());
243    /// assert_eq!(non_consumable.hourly_rate(), None);
244    /// ```
245    pub fn hourly_rate(&self) -> Option<u16> {
246        self.hourly_rate
247    }
248
249    /// Updates the hourly_rate of the non consumable material.
250    /// # Example
251    /// ```
252    /// use planter_core::resources::NonConsumable;
253    ///
254    /// let mut non_consumable = NonConsumable::new("Steel".to_owned());
255    /// non_consumable.update_hourly_rate(3);
256    /// assert_eq!(non_consumable.hourly_rate(), Some(3));
257    /// ```
258    pub fn update_hourly_rate(&mut self, hourly_rate: u16) {
259        self.hourly_rate = Some(hourly_rate);
260    }
261
262    /// Remove the cost per unit of the non consumable material.
263    /// # Example
264    /// ```
265    /// use planter_core::resources::NonConsumable;
266    ///
267    /// let mut non_consumable = NonConsumable::new("Steel".to_owned());
268    /// non_consumable.update_hourly_rate(3);
269    /// assert_eq!(non_consumable.hourly_rate(), Some(3));
270    /// non_consumable.remove_hourly_rate();
271    /// assert_eq!(non_consumable.hourly_rate(), None);
272    /// ```
273    pub fn remove_hourly_rate(&mut self) {
274        self.hourly_rate = None;
275    }
276}