1#![doc(html_root_url = "https://docs.rs/inv-sys/1.4.1")]
2
3use std::fmt::Debug;
4
5pub trait Stacksize {
6 fn get_max_stacksize(&self) -> usize;
7}
8
9#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
10pub struct Inv<T> {
11 slots: Vec<Slot<T>>
12}
13
14impl<T> IntoIterator for Inv<T> {
15 type Item = Slot<T>;
16 type IntoIter = std::vec::IntoIter<Self::Item>;
17
18 fn into_iter(self) -> Self::IntoIter {
19 self.slots.into_iter()
20 }
21}
22
23#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
24pub struct Slot<T> {
25 inner: Option<ItemStack<T>>
26}
27
28impl<T> Slot<T>
29where T: Stacksize + Eq + Clone + Ord {
30 pub fn new_empty() -> Self {
32 Self {
33 inner: None
34 }
35 }
36
37 pub fn new(items: ItemStack<T>) -> Self {
39 Self {
40 inner: Some(items)
41 }
42 }
43
44 pub fn is_empty(&self) -> bool {
46 self.inner.is_none()
47 }
48
49 pub fn stack(&mut self, to_place: ItemStack<T>) -> Result<(), StackErr<T>> {
51 if let Some(inner) = &mut self.inner {
52 match inner.stack(to_place) {
53 Ok(()) => Ok(()),
54 Err(rest) => Err(rest),
55 }
56 } else {
57 if to_place.get_amount() > 0 {
59 match ItemStack::new_from_stack(to_place) {
60 Ok(new) => {
61 self.inner = Some(new);
62 Ok(())
63 },
64 Err((new, rest)) => {
65 self.inner = Some(new);
66 Err(rest)
67 },
68 }
69 } else {
70 Ok(())
71 }
72 }
73 }
74
75 pub fn inner(&self) -> &Option<ItemStack<T>> {
77 &self.inner
78 }
79
80 pub fn get_item(&self) -> Result<&T, InvAccessErr> {
82 if let Some(inner) = &self.inner {
83 Ok(inner.get_item())
84 } else {
85 Err(InvAccessErr::SlotEmpty)
86 }
87 }
88
89 pub fn get_amount(&self) -> Result<usize, InvAccessErr> {
91 if let Some(inner) = &self.inner {
92 Ok(inner.get_amount())
93 } else {
94 Err(InvAccessErr::SlotEmpty)
95 }
96 }
97
98 pub fn decrease_amount(&mut self) -> Result<(), InvAccessErr> {
100 if let Some(inner) = &mut self.inner {
101 if inner.get_amount() > 0 {
102 inner.amount -= 1;
103 if inner.amount == 0 {
104 self.inner = None;
105 }
106 Ok(())
107 } else {
108 unreachable!();
109 }
111 } else {
112 Err(InvAccessErr::SlotEmpty)
113 }
114 }
115
116 pub fn decrease_amount_by(&mut self, amount: usize) -> Result<(), InvAccessErr> {
118 if let Some(inner) = &mut self.inner {
119 if inner.get_amount() >= amount {
120 inner.amount -= amount;
121 if inner.amount == 0 {
122 self.inner = None;
123 }
124 Ok(())
125 } else {
126 Err(InvAccessErr::AmountInsufficient)
127 }
128 } else {
129 Err(InvAccessErr::SlotEmpty)
130 }
131 }
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
135pub struct ItemStack<T> {
136 item: T,
137 amount: usize
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
141pub enum StackErr<T>
142where T: Stacksize + Eq + Clone {
143 ItemTypeDoesNotMatch(ItemStack<T>),
144 StackSizeOverflow(ItemStack<T>)
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
148pub enum InvAccessErr {
149 SlotOutOfBounds,
150 SlotEmpty,
151 ItemNotFound,
152 AmountInsufficient
153}
154
155pub type InvOverflow<T> = ItemStack<T>;
156
157impl<T> From<StackErr<T>> for ItemStack<T>
158where T: Stacksize + Eq + Clone {
159 fn from(item: StackErr<T>) -> Self {
160 match item {
161 StackErr::ItemTypeDoesNotMatch(x) => x,
162 StackErr::StackSizeOverflow(x) => x,
163 }
164 }
165}
166
167impl<T> ItemStack<T>
168where T: Stacksize + Eq + Clone + Ord {
169 pub fn new(item: T, amount: usize) -> Self {
170 Self {
171 item,
172 amount
173 }
174 }
175
176 pub fn new_from_stack(mut new: ItemStack<T>) -> Result<Self, (Self, StackErr<T>)> {
177 match new.stacksize_split() {
178 Ok(()) => Ok(new),
179 Err(rest) => Err((new, StackErr::StackSizeOverflow(rest)))
180 }
181 }
182
183 fn stacksize_split(&mut self) -> Result<(), ItemStack<T>> {
184 let max = self.item.get_max_stacksize();
185 if self.amount > max {
186 let rest = self.amount - max;
187 self.amount = max;
188 Err(
189 ItemStack::<T>::new(
190 self.item.clone(),
191 rest
192 ))
193 } else {
194 Ok(())
195 }
196 }
197
198 pub fn stack(&mut self, other: ItemStack<T>) -> Result<(), StackErr<T>> {
199 if other.item == self.item {
200 self.amount += other.amount;
201 self.stacksize_split().map_err(|err| StackErr::StackSizeOverflow(err))
202 } else {
203 Err(StackErr::ItemTypeDoesNotMatch(other))
204 }
205 }
206
207 pub fn get_item(&self) -> &T {
208 &self.item
209 }
210
211 pub fn get_amount(&self) -> usize {
212 self.amount
213 }
214}
215
216impl<T> Inv<T>
217where T: Stacksize + Eq + Clone + Ord {
218 pub fn new(slot_amount: usize) -> Self {
219 Inv {
220 slots: vec![Slot::new_empty(); slot_amount]
221 }
222 }
223
224 fn auto_stack_inner_filled(&mut self, to_place: ItemStack<T>) -> Result<(), StackErr<T>> {
226 let mut state = to_place.clone();
227 for slot in self.slots.iter_mut() {
228 if !slot.is_empty() {
229 match slot.stack(state) {
230 Ok(()) => return Ok(()),
231 Err(rest) => {
232 state = rest.into();
233 }
234 }
235 } else {
236 continue
237 }
238 }
239 Err(StackErr::StackSizeOverflow(state))
240 }
241
242 fn auto_stack_inner_empty(&mut self, to_place: ItemStack<T>) -> Result<(), StackErr<T>> {
244 let mut state = to_place.clone();
245 for slot in self.slots.iter_mut() {
246 if slot.is_empty() {
247 match slot.stack(state) {
248 Ok(()) => return Ok(()),
249 Err(rest) => {
250 state = rest.into();
251 }
252 }
253 }
254 }
255 Err(StackErr::StackSizeOverflow(state))
256 }
257
258 pub fn auto_stack(&mut self, to_place: ItemStack<T>) -> Result<(), InvOverflow<T>> {
261 match self.auto_stack_inner_filled(to_place) {
262 Ok(()) => return Ok(()),
263 Err(rest) => {
264 match self.auto_stack_inner_empty(rest.into()) {
265 Ok(()) => return Ok(()),
266 Err(rest) => Err(rest.into()),
267 }
268 }
269 }
270 }
271
272 pub fn stack_at(&mut self, index: usize, to_place: ItemStack<T>) -> Result<Result<(), StackErr<T>>, InvAccessErr> {
274 match self.slots.get_mut(index) {
275 Some(slot) => {
276 Ok(
277 match slot.stack(to_place) {
278 Ok(()) => Ok(()),
279 Err(rest) => Err(rest),
280 }
281 )
282 },
283 None => Err(InvAccessErr::SlotOutOfBounds)
284 }
285 }
286
287 pub fn take_stack(&mut self, index: usize) -> Result<ItemStack<T>, InvAccessErr> {
290 match self.slots.get_mut(index) {
291 Some(slot) => {
292 if let Some(filled) = &slot.inner {
293 let take = filled.clone();
294 slot.inner = None;
295 Ok(take)
296 } else {
297 Err(InvAccessErr::SlotEmpty)
298 }
299 },
300 None => Err(InvAccessErr::SlotOutOfBounds)
301 }
302 }
303
304 pub fn get_slot(&self, index: usize) -> Result<&Slot<T>, InvAccessErr> {
306 match self.slots.get(index) {
307 Some(slot) => Ok(slot),
308 None => Err(InvAccessErr::SlotOutOfBounds)
309 }
310 }
311
312 pub fn get_slot_mut(&mut self, index: usize) -> Result<&mut Slot<T>, InvAccessErr> {
314 match self.slots.get_mut(index) {
315 Some(slot) => Ok(slot),
316 None => Err(InvAccessErr::SlotOutOfBounds)
317 }
318 }
319
320 pub fn find_slot(&self, item: T) -> Result<&Slot<T>, InvAccessErr> {
322 for slot in self.slots.iter() {
323 if let Some(inner) = &slot.inner {
324 if *inner.get_item() == item {
325 return Ok(slot);
326 }
327 }
328 }
329 Err(InvAccessErr::ItemNotFound)
330 }
331
332 pub fn find_slot_mut(&mut self, item: T) -> Result<&mut Slot<T>, InvAccessErr> {
334 for slot in self.slots.iter_mut() {
335 if let Some(inner) = &slot.inner {
336 if *inner.get_item() == item {
337 return Ok(slot);
338 }
339 }
340 }
341 Err(InvAccessErr::ItemNotFound)
342 }
343
344 pub fn sort(&mut self) {
346 self.slots.sort_unstable();
347 }
348}
349
350#[cfg(test)]
351mod test;