Skip to main content

steel_core/inventory/slots/
normal_slot.rs

1use steel_registry::item_stack::ItemStack;
2use steel_utils::{DowncastType, DowncastTypeKey};
3
4use crate::inventory::{
5    lock::{ContainerLockGuard, ContainerRef},
6    slots::slot::{Slot, SlotStorage},
7};
8
9/// A normal slot that references a container and index.
10pub struct NormalSlot {
11    storage: SlotStorage,
12}
13
14// SAFETY: This key uniquely identifies Steel's `NormalSlot`.
15unsafe impl DowncastType for NormalSlot {
16    const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:slot/normal");
17}
18
19impl NormalSlot {
20    /// Creates a new normal slot from a `ContainerRef`.
21    pub fn new(container: impl Into<ContainerRef>, index: usize) -> Self {
22        Self {
23            storage: SlotStorage::physical(container, index),
24        }
25    }
26
27    /// Returns a reference to the container.
28    #[must_use]
29    pub fn container_ref(&self) -> ContainerRef {
30        self.backing().0.clone()
31    }
32
33    fn backing(&self) -> (&ContainerRef, usize) {
34        let Some(backing) = self.storage.physical_backing() else {
35            unreachable!("NormalSlot always has physical storage");
36        };
37        backing
38    }
39}
40
41impl Slot for NormalSlot {
42    fn storage(&self) -> &SlotStorage {
43        &self.storage
44    }
45
46    fn get_item<'a>(&self, guard: &'a ContainerLockGuard) -> &'a ItemStack {
47        let (container, index) = self.backing();
48        guard
49            .get(container.container_id())
50            .expect("container not locked")
51            .get_item(index)
52    }
53
54    fn get_item_mut<'a>(&self, guard: &'a mut ContainerLockGuard) -> &'a mut ItemStack {
55        let (container, index) = self.backing();
56        guard
57            .get_mut(container.container_id())
58            .expect("container not locked")
59            .get_item_mut(index)
60    }
61
62    fn set_item(&self, guard: &mut ContainerLockGuard, stack: ItemStack) {
63        let (container, index) = self.backing();
64        assert!(
65            guard.set_item(container.container_id(), index, stack),
66            "container not locked"
67        );
68        self.set_changed(guard);
69    }
70
71    fn remove(&self, guard: &mut ContainerLockGuard, amount: i32) -> ItemStack {
72        if amount <= 0 || self.get_item(guard).is_empty() {
73            return ItemStack::empty();
74        }
75        let (container, index) = self.backing();
76        guard
77            .remove_item(container.container_id(), index, amount)
78            .expect("container not locked")
79    }
80
81    fn set_changed(&self, guard: &mut ContainerLockGuard) {
82        let (container, _) = self.backing();
83        assert!(
84            guard.set_changed(container.container_id()),
85            "container not locked"
86        );
87    }
88
89    fn get_container_slot(&self) -> usize {
90        self.backing().1
91    }
92
93    fn get_max_stack_size(&self, guard: &ContainerLockGuard) -> i32 {
94        let (container, _) = self.backing();
95        guard
96            .get(container.container_id())
97            .expect("container not locked")
98            .get_max_stack_size()
99    }
100}