valence_protocol/
item.rs
1use std::io::Write;
2
3pub use valence_generated::item::ItemKind;
4use valence_nbt::Compound;
5
6use crate::{Decode, Encode};
7
8#[derive(Clone, PartialEq, Debug, Default)]
10pub struct ItemStack {
11 pub item: ItemKind,
12 pub count: i8,
13 pub nbt: Option<Compound>,
14}
15
16impl ItemStack {
17 pub const EMPTY: ItemStack = ItemStack {
18 item: ItemKind::Air,
19 count: 0,
20 nbt: None,
21 };
22
23 #[must_use]
24 pub const fn new(item: ItemKind, count: i8, nbt: Option<Compound>) -> Self {
25 Self { item, count, nbt }
26 }
27
28 #[must_use]
29 pub const fn with_count(mut self, count: i8) -> Self {
30 self.count = count;
31 self
32 }
33
34 #[must_use]
35 pub const fn with_item(mut self, item: ItemKind) -> Self {
36 self.item = item;
37 self
38 }
39
40 #[must_use]
41 pub fn with_nbt<C: Into<Option<Compound>>>(mut self, nbt: C) -> Self {
42 self.nbt = nbt.into();
43 self
44 }
45
46 pub const fn is_empty(&self) -> bool {
47 matches!(self.item, ItemKind::Air) || self.count <= 0
48 }
49}
50
51impl Encode for ItemStack {
52 fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
53 if self.is_empty() {
54 false.encode(w)
55 } else {
56 true.encode(&mut w)?;
57 self.item.encode(&mut w)?;
58 self.count.encode(&mut w)?;
59 match &self.nbt {
60 Some(n) => n.encode(w),
61 None => 0_u8.encode(w),
62 }
63 }
64 }
65}
66
67impl Decode<'_> for ItemStack {
68 fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
69 let present = bool::decode(r)?;
70 if !present {
71 return Ok(ItemStack::EMPTY);
72 };
73
74 let item = ItemKind::decode(r)?;
75 let count = i8::decode(r)?;
76
77 let nbt = if let [0, rest @ ..] = *r {
78 *r = rest;
79 None
80 } else {
81 Some(Compound::decode(r)?)
82 };
83
84 let stack = ItemStack { item, count, nbt };
85
86 if stack.is_empty() {
88 Ok(ItemStack::EMPTY)
89 } else {
90 Ok(stack)
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn empty_item_stack_is_empty() {
101 let air_stack = ItemStack::new(ItemKind::Air, 10, None);
102 let less_then_one_stack = ItemStack::new(ItemKind::Stone, 0, None);
103
104 assert!(air_stack.is_empty());
105 assert!(less_then_one_stack.is_empty());
106
107 assert!(ItemStack::EMPTY.is_empty());
108
109 let not_empty_stack = ItemStack::new(ItemKind::Stone, 10, None);
110
111 assert!(!not_empty_stack.is_empty());
112 }
113}