steel_registry/data_components/components/
cooking_fuel.rs1use std::io::{Cursor, Result, Write};
4
5use simdnbt::owned::{NbtCompound, NbtTag};
6use simdnbt::{FromNbtTag, ToNbtTag};
7use steel_utils::Identifier;
8use steel_utils::hash::{ComponentHasher, HashComponent, HashEntry, sort_map_entries};
9use steel_utils::serial::{ReadFrom, WriteTo};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct CookingFuel {
15 pub burn_time: Identifier,
16 pub speed_multiplier: Identifier,
17}
18
19impl CookingFuel {
20 #[must_use]
21 pub const fn new(burn_time: Identifier, speed_multiplier: Identifier) -> Self {
22 Self {
23 burn_time,
24 speed_multiplier,
25 }
26 }
27}
28
29impl WriteTo for CookingFuel {
30 fn write(&self, writer: &mut impl Write) -> Result<()> {
31 self.burn_time.write(writer)?;
32 self.speed_multiplier.write(writer)
33 }
34}
35
36impl ReadFrom for CookingFuel {
37 fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
38 Ok(Self {
39 burn_time: Identifier::read(data)?,
40 speed_multiplier: Identifier::read(data)?,
41 })
42 }
43}
44
45impl ToNbtTag for CookingFuel {
46 fn to_nbt_tag(self) -> NbtTag {
47 let mut compound = NbtCompound::new();
48 compound.insert("burn_time", self.burn_time.to_nbt_tag());
49 compound.insert("speed_multiplier", self.speed_multiplier.to_nbt_tag());
50 NbtTag::Compound(compound)
51 }
52}
53
54impl FromNbtTag for CookingFuel {
55 fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
56 let compound = tag.compound()?;
57 let burn_time = Identifier::from_nbt_tag(compound.get("burn_time")?)?;
58 let speed_multiplier = Identifier::from_nbt_tag(compound.get("speed_multiplier")?)?;
59 Some(Self {
60 burn_time,
61 speed_multiplier,
62 })
63 }
64}
65
66impl HashComponent for CookingFuel {
67 fn hash_component(&self, hasher: &mut ComponentHasher) {
68 let mut entries = Vec::with_capacity(2);
69 push_hash_entry(&mut entries, "burn_time", &self.burn_time);
70 push_hash_entry(&mut entries, "speed_multiplier", &self.speed_multiplier);
71 sort_map_entries(&mut entries);
72 hasher.start_map();
73 for entry in entries {
74 hasher.put_raw_bytes(&entry.key_bytes);
75 hasher.put_raw_bytes(&entry.value_bytes);
76 }
77 hasher.end_map();
78 }
79}
80
81fn push_hash_entry<T: HashComponent + ?Sized>(entries: &mut Vec<HashEntry>, key: &str, value: &T) {
82 let mut key_hasher = ComponentHasher::new();
83 key_hasher.put_string(key);
84 let mut value_hasher = ComponentHasher::new();
85 value.hash_component(&mut value_hasher);
86 entries.push(HashEntry::new(key_hasher, value_hasher));
87}
88
89#[cfg(test)]
90mod tests {
91 use std::io::Cursor;
92
93 use simdnbt::FromNbtTag as _;
94 use simdnbt::ToNbtTag as _;
95 use simdnbt::borrow::read_tag;
96 use simdnbt::owned::NbtTag;
97 use steel_utils::Identifier;
98 use steel_utils::serial::{ReadFrom as _, WriteTo as _};
99
100 use super::CookingFuel;
101
102 fn parse(tag: NbtTag) -> Option<CookingFuel> {
103 let mut bytes = Vec::new();
104 tag.write(&mut bytes);
105 let borrowed = read_tag(&mut Cursor::new(bytes.as_slice())).ok()?;
106 CookingFuel::from_nbt_tag(borrowed.as_tag())
107 }
108
109 #[test]
110 fn round_trips_both_codecs() {
111 let value = CookingFuel::new(
112 Identifier::vanilla_static("cooking/time_wood_blocks"),
113 Identifier::vanilla_static("cooking/speed_default"),
114 );
115
116 let nbt = value.clone().to_nbt_tag();
117 assert_eq!(parse(nbt), Some(value.clone()));
118
119 let mut network = Vec::new();
120 value.write(&mut network).expect("fuel should encode");
121 assert_eq!(
122 CookingFuel::read(&mut Cursor::new(network.as_slice())).expect("fuel should decode"),
123 value
124 );
125 }
126}