steel_core/inventory/slots/
result_slot.rs1use std::{mem, sync::Arc};
2
3use steel_registry::item_stack::ItemStack;
4use steel_utils::{DowncastType, DowncastTypeKey};
5
6use crate::{
7 inventory::{
8 lock::{ContainerLockGuard, ContainerRef},
9 slots::{ResultHandler, Slot, SlotStorage},
10 },
11 player::Player,
12};
13
14pub struct ResultSlot {
16 handler: Arc<dyn ResultHandler + Send + Sync>,
17 storage: SlotStorage,
18}
19
20unsafe impl DowncastType for ResultSlot {
22 const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:slot/result");
23}
24
25impl ResultSlot {
26 pub fn new(handler: impl ResultHandler + 'static) -> Self {
28 let result_container = handler.result_container();
29 let storage =
30 SlotStorage::physical(result_container, 0).with_dependencies(handler.dependencies());
31 Self {
32 handler: Arc::new(handler),
33 storage,
34 }
35 }
36
37 pub(crate) fn result_container(&self) -> &ContainerRef {
39 let Some((container, _)) = self.storage.physical_backing() else {
40 unreachable!("ResultSlot always has physical storage");
41 };
42 container
43 }
44}
45
46impl Slot for ResultSlot {
47 fn storage(&self) -> &SlotStorage {
48 &self.storage
49 }
50
51 fn get_item<'a>(&self, guard: &'a ContainerLockGuard) -> &'a ItemStack {
52 guard
53 .get(self.result_container().container_id())
54 .expect("failed to get item from result container")
55 .get_item(0)
56 }
57
58 fn get_item_mut<'a>(&self, guard: &'a mut ContainerLockGuard) -> &'a mut ItemStack {
59 guard
60 .get_mut(self.result_container().container_id())
61 .expect("failed to get item mutabily from result container")
62 .get_item_mut(0)
63 }
64
65 fn set_item(&self, guard: &mut ContainerLockGuard, stack: ItemStack) {
66 guard
67 .get_mut(self.result_container().container_id())
68 .expect("failed to get item mutabily from result container")
69 .set_item(0, stack);
70 }
71
72 fn get_max_stack_size(&self, guard: &ContainerLockGuard) -> i32 {
73 guard
74 .get(self.result_container().container_id())
75 .expect("result container not locked")
76 .get_max_stack_size()
77 }
78
79 fn set_changed(&self, guard: &mut ContainerLockGuard) {
80 guard
81 .get_mut(self.result_container().container_id())
82 .expect("result container not locked")
83 .set_changed();
84 }
85
86 fn get_container_slot(&self) -> usize {
87 0
88 }
89
90 fn on_take(
91 &self,
92 guard: &mut ContainerLockGuard,
93 _stack: &ItemStack,
94 player: &Player,
95 ) -> Option<ItemStack> {
96 self.handler.on_result_taken(guard, player)
97 }
98
99 fn remove(&self, guard: &mut ContainerLockGuard, _amount: i32) -> ItemStack {
100 mem::take(self.get_item_mut(guard))
101 }
102
103 fn is_fake(&self) -> bool {
104 true
105 }
106
107 fn allow_modification(&self, _guard: &ContainerLockGuard, _player: &Player) -> bool {
108 false
109 }
110
111 fn may_place(&self, _stack: &ItemStack) -> bool {
112 false
113 }
114
115 fn may_pickup(&self, guard: &ContainerLockGuard, player: &Player) -> bool {
116 self.handler.is_result_valid(guard, player)
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use steel_utils::locks::IntoShared;
123
124 use super::*;
125 use crate::inventory::container::SimpleContainer;
126
127 struct NoopResultHandler(ContainerRef);
128
129 impl ResultHandler for NoopResultHandler {
130 fn result_container(&self) -> ContainerRef {
131 self.0.clone()
132 }
133
134 fn dependencies(&self) -> Vec<ContainerRef> {
135 Vec::new()
136 }
137
138 fn update_result(&self, _guard: &mut ContainerLockGuard) {}
139
140 fn on_result_taken(
141 &self,
142 _guard: &mut ContainerLockGuard,
143 _player: &Player,
144 ) -> Option<ItemStack> {
145 None
146 }
147
148 fn is_result_valid(&self, _guard: &ContainerLockGuard, _player: &Player) -> bool {
149 true
150 }
151 }
152
153 #[test]
154 fn constructor_uses_the_handlers_result_container() {
155 let container = ContainerRef::from(SimpleContainer::new(1).into_shared());
156 let expected = container.container_id();
157
158 let slot = ResultSlot::new(NoopResultHandler(container));
159
160 assert_eq!(slot.storage().physical_key(), Some((expected, 0)));
161 }
162}