fish_lib/models/item/
attributes_container.rs

1use crate::models::item::attributes::bait::BaitAttributes;
2use crate::models::item::attributes::purchasable::PurchasableAttributes;
3use crate::models::item::attributes::rod::RodAttributes;
4use crate::models::item::attributes::{ItemAttributes, ItemAttributesType};
5use serde::{Deserialize, Serialize};
6use std::collections::{HashMap, HashSet};
7
8pub trait ItemAttributesContainerInterface {
9    fn get_attributes(&self) -> &HashMap<ItemAttributesType, ItemAttributes>;
10
11    fn get_bait_attributes(&self) -> Option<&BaitAttributes> {
12        match self.get_attributes().get(&ItemAttributesType::Bait) {
13            Some(ItemAttributes::Bait(bait)) => Some(bait),
14            Some(_) | None => None,
15        }
16    }
17
18    fn get_purchasable_attributes(&self) -> Option<&PurchasableAttributes> {
19        match self.get_attributes().get(&ItemAttributesType::Purchasable) {
20            Some(ItemAttributes::Purchasable(purchasable)) => Some(purchasable),
21            Some(_) | None => None,
22        }
23    }
24
25    fn get_rod_attributes(&self) -> Option<&RodAttributes> {
26        match self.get_attributes().get(&ItemAttributesType::Rod) {
27            Some(ItemAttributes::Rod(rod)) => Some(rod),
28            Some(_) | None => None,
29        }
30    }
31
32    fn is_bait(&self) -> bool {
33        self.get_bait_attributes().is_some()
34    }
35
36    fn is_purchasable(&self) -> bool {
37        self.get_purchasable_attributes().is_some()
38    }
39
40    fn is_rod(&self) -> bool {
41        self.get_rod_attributes().is_some()
42    }
43
44    // Attribute specific values
45    fn get_bait_level(&self) -> Option<u64> {
46        self.get_bait_attributes().map(|bait| bait.get_level())
47    }
48
49    fn get_cost(&self) -> Option<u32> {
50        self.get_purchasable_attributes()
51            .map(|purchasable| purchasable.get_cost())
52    }
53
54    fn get_rod_level(&self) -> Option<u64> {
55        self.get_rod_attributes().map(|rod| rod.get_level())
56    }
57}
58
59#[derive(Debug, Default, Clone, PartialEq, Serialize)]
60pub struct ItemAttributesContainer {
61    components: HashMap<ItemAttributesType, ItemAttributes>,
62}
63
64impl ItemAttributesContainer {
65    pub fn new() -> Self {
66        Self::default()
67    }
68
69    pub fn get_attributes_types(&self) -> HashSet<ItemAttributesType> {
70        self.components.keys().copied().collect()
71    }
72
73    pub fn add_component(&mut self, component: ItemAttributes) {
74        match component {
75            ItemAttributes::Bait(_) => self.components.insert(ItemAttributesType::Bait, component),
76            ItemAttributes::Purchasable(_) => self
77                .components
78                .insert(ItemAttributesType::Purchasable, component),
79            ItemAttributes::Rod(_) => self.components.insert(ItemAttributesType::Rod, component),
80        };
81    }
82
83    pub fn with_bait(mut self, level: u64) -> Self {
84        let component = ItemAttributes::bait(level);
85        self.add_component(component);
86        self
87    }
88
89    pub fn with_purchasable(mut self, cost: u32) -> Self {
90        let component = ItemAttributes::purchasable(cost);
91        self.add_component(component);
92        self
93    }
94
95    pub fn with_rod(mut self, level: u64) -> Self {
96        let component = ItemAttributes::rod(level);
97        self.add_component(component);
98        self
99    }
100}
101
102impl ItemAttributesContainerInterface for ItemAttributesContainer {
103    fn get_attributes(&self) -> &HashMap<ItemAttributesType, ItemAttributes> {
104        &self.components
105    }
106}
107
108// Serde
109impl<'de> Deserialize<'de> for ItemAttributesContainer {
110    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111    where
112        D: serde::Deserializer<'de>,
113    {
114        #[derive(Deserialize)]
115        struct Helper {
116            components: HashMap<String, serde_json::Value>,
117        }
118
119        let helper = Helper::deserialize(deserializer)?;
120        let mut container = ItemAttributesContainer::new();
121
122        for (type_str, attr_value) in helper.components {
123            let (attr_type, attribute) = match type_str.as_str() {
124                "Bait" => {
125                    let bait =
126                        serde_json::from_value(attr_value).map_err(serde::de::Error::custom)?;
127                    (ItemAttributesType::Bait, ItemAttributes::Bait(bait))
128                }
129                "Purchasable" => {
130                    let purchasable =
131                        serde_json::from_value(attr_value).map_err(serde::de::Error::custom)?;
132                    (
133                        ItemAttributesType::Purchasable,
134                        ItemAttributes::Purchasable(purchasable),
135                    )
136                }
137                "Rod" => {
138                    let rod =
139                        serde_json::from_value(attr_value).map_err(serde::de::Error::custom)?;
140                    (ItemAttributesType::Rod, ItemAttributes::Rod(rod))
141                }
142                _ => continue,
143            };
144
145            container.components.insert(attr_type, attribute);
146        }
147
148        Ok(container)
149    }
150}