fish_lib/models/item/
properties_container.rs1use crate::models::item::properties::stackable::StackableComponent;
2use crate::models::item::properties::usage_count::UsageComponent;
3use crate::models::item::properties::{ItemProperties, ItemPropertiesType};
4use diesel::deserialize::FromSql;
5use diesel::pg::Pg;
6use diesel::serialize::{Output, ToSql};
7use diesel::sql_types::Jsonb;
8use diesel::{deserialize, serialize, AsExpression, FromSqlRow};
9use serde::{Deserialize, Serialize};
10use std::collections::{HashMap, HashSet};
11
12#[derive(Debug, Default, Clone, PartialEq, Serialize, FromSqlRow, AsExpression)]
13#[diesel(sql_type = diesel::sql_types::Jsonb)]
14pub struct ItemPropertiesContainer {
15 components: HashMap<ItemPropertiesType, ItemProperties>,
16}
17
18impl ItemPropertiesContainer {
19 pub fn new() -> Self {
20 Self {
21 components: HashMap::new(),
22 }
23 }
24
25 pub fn get_properties_types(&self) -> HashSet<ItemPropertiesType> {
26 self.components.keys().copied().collect()
27 }
28
29 pub fn add_properties(&mut self, properties: ItemProperties) {
30 match properties {
31 ItemProperties::Stackable(_) => self
32 .components
33 .insert(ItemPropertiesType::Stackable, properties),
34 ItemProperties::Usage(_) => self
35 .components
36 .insert(ItemPropertiesType::Usage, properties),
37 };
38 }
39
40 pub fn remove_properties(&mut self, properties_type: ItemPropertiesType) {
41 self.components.remove(&properties_type);
42 }
43
44 pub fn with_stackable(mut self, count: u64) -> Self {
45 let component = ItemProperties::stackable(count);
46 self.add_properties(component);
47 self
48 }
49
50 pub fn with_usage(mut self, count: u64) -> Self {
51 let component = ItemProperties::usage(count);
52 self.add_properties(component);
53 self
54 }
55}
56
57impl ItemPropertiesContainerInterface for ItemPropertiesContainer {
58 fn get_properties(&self) -> &HashMap<ItemPropertiesType, ItemProperties> {
59 &self.components
60 }
61
62 fn get_properties_mut(&mut self) -> &mut HashMap<ItemPropertiesType, ItemProperties> {
63 &mut self.components
64 }
65}
66
67pub trait ItemPropertiesContainerInterface {
68 fn get_properties(&self) -> &HashMap<ItemPropertiesType, ItemProperties>;
69 fn get_properties_mut(&mut self) -> &mut HashMap<ItemPropertiesType, ItemProperties>;
70
71 fn get_stackable_properties(&self) -> Option<&StackableComponent> {
72 match self.get_properties().get(&ItemPropertiesType::Stackable) {
73 Some(ItemProperties::Stackable(stackable)) => Some(stackable),
74 Some(_) | None => None,
75 }
76 }
77
78 fn get_stackable_properties_mut(&mut self) -> Option<&mut StackableComponent> {
79 match self
80 .get_properties_mut()
81 .get_mut(&ItemPropertiesType::Stackable)
82 {
83 Some(ItemProperties::Stackable(stackable)) => Some(stackable),
84 Some(_) | None => None,
85 }
86 }
87
88 fn get_usage_properties(&self) -> Option<&UsageComponent> {
89 match self.get_properties().get(&ItemPropertiesType::Usage) {
90 Some(ItemProperties::Usage(usage)) => Some(usage),
91 Some(_) | None => None,
92 }
93 }
94 fn get_usage_properties_mut(&mut self) -> Option<&mut UsageComponent> {
95 match self
96 .get_properties_mut()
97 .get_mut(&ItemPropertiesType::Usage)
98 {
99 Some(ItemProperties::Usage(usage)) => Some(usage),
100 Some(_) | None => None,
101 }
102 }
103
104 fn set_count(&mut self, count: u64) {
106 self.get_stackable_properties_mut().map(|stackable| {
107 stackable.set_count(count);
108 });
109 }
110
111 fn is_stackable(&self) -> bool {
113 self.get_stackable_properties().is_some()
114 }
115
116 fn has_usage(&self) -> bool {
117 self.get_usage_properties().is_some()
118 }
119
120 fn get_count(&self) -> Option<u64> {
122 self.get_stackable_properties()
123 .map(|stackable| stackable.get_count())
124 }
125
126 fn get_times_used(&self) -> Option<u64> {
127 self.get_usage_properties()
128 .map(|usage| usage.get_times_used())
129 }
130
131 fn on_use(&mut self, times: u64) {
133 self.get_properties_mut()
134 .values_mut()
135 .for_each(|component| component.on_use(times))
136 }
137
138 fn on_add(&mut self, amount: u64) {
139 self.get_properties_mut()
140 .values_mut()
141 .for_each(|component| component.on_add(amount));
142 }
143
144 fn on_remove(&mut self, amount: u64) {
145 self.get_properties_mut()
146 .values_mut()
147 .for_each(|component| component.on_remove(amount));
148 }
149
150 fn should_consume(&self) -> bool {
151 self.get_properties()
152 .values()
153 .any(|component| component.should_consume())
154 }
155}
156
157impl ToSql<Jsonb, Pg> for ItemPropertiesContainer {
158 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
159 let value = serde_json::to_value(self)?;
160 ToSql::<Jsonb, Pg>::to_sql(&value, &mut out.reborrow())
161 }
162}
163
164impl FromSql<Jsonb, Pg> for ItemPropertiesContainer {
165 fn from_sql(
166 bytes: <Pg as diesel::backend::Backend>::RawValue<'_>,
167 ) -> deserialize::Result<Self> {
168 let value = <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
169 Ok(serde_json::from_value(value)?)
170 }
171}
172
173impl<'de> Deserialize<'de> for ItemPropertiesContainer {
175 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
176 where
177 D: serde::Deserializer<'de>,
178 {
179 #[derive(Deserialize)]
180 struct Helper {
181 components: HashMap<String, serde_json::Value>,
182 }
183
184 let helper = Helper::deserialize(deserializer)?;
185 let mut container = ItemPropertiesContainer::new();
186
187 for (type_str, component_value) in helper.components {
188 let (component_type, component) = match type_str.as_str() {
189 "Usage" => {
190 let usage = serde_json::from_value(component_value)
191 .map_err(serde::de::Error::custom)?;
192 (ItemPropertiesType::Usage, ItemProperties::Usage(usage))
193 }
194 "Stackable" => {
195 let stackable = serde_json::from_value(component_value)
196 .map_err(serde::de::Error::custom)?;
197 (
198 ItemPropertiesType::Stackable,
199 ItemProperties::Stackable(stackable),
200 )
201 }
202 _ => continue,
203 };
204
205 container.components.insert(component_type, component);
206 }
207
208 Ok(container)
209 }
210}