Skip to main content

steel_registry/data_components/components/
compostable.rs

1//! Vanilla `minecraft:compostable` item component.
2
3use 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};
9use steel_utils::serial::{ReadFrom, WriteTo};
10
11/// Reference to the context int provider giving a compostable item its
12/// chance to add a compost layer.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct Compostable {
15    pub layers: Identifier,
16}
17
18impl Compostable {
19    #[must_use]
20    pub const fn new(layers: Identifier) -> Self {
21        Self { layers }
22    }
23}
24
25impl WriteTo for Compostable {
26    fn write(&self, writer: &mut impl Write) -> Result<()> {
27        self.layers.write(writer)
28    }
29}
30
31impl ReadFrom for Compostable {
32    fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
33        Ok(Self {
34            layers: Identifier::read(data)?,
35        })
36    }
37}
38
39impl ToNbtTag for Compostable {
40    fn to_nbt_tag(self) -> NbtTag {
41        let mut compound = NbtCompound::new();
42        compound.insert("layers", self.layers.to_nbt_tag());
43        NbtTag::Compound(compound)
44    }
45}
46
47impl FromNbtTag for Compostable {
48    fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
49        let compound = tag.compound()?;
50        let layers = Identifier::from_nbt_tag(compound.get("layers")?)?;
51        Some(Self { layers })
52    }
53}
54
55impl HashComponent for Compostable {
56    fn hash_component(&self, hasher: &mut ComponentHasher) {
57        let mut key_hasher = ComponentHasher::new();
58        key_hasher.put_string("layers");
59        let mut value_hasher = ComponentHasher::new();
60        self.layers.hash_component(&mut value_hasher);
61        let entry = HashEntry::new(key_hasher, value_hasher);
62
63        hasher.start_map();
64        hasher.put_raw_bytes(&entry.key_bytes);
65        hasher.put_raw_bytes(&entry.value_bytes);
66        hasher.end_map();
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use std::io::Cursor;
73
74    use simdnbt::FromNbtTag as _;
75    use simdnbt::ToNbtTag as _;
76    use simdnbt::borrow::read_tag;
77    use simdnbt::owned::NbtTag;
78    use steel_utils::Identifier;
79    use steel_utils::serial::{ReadFrom as _, WriteTo as _};
80
81    use super::Compostable;
82
83    fn parse(tag: NbtTag) -> Option<Compostable> {
84        let mut bytes = Vec::new();
85        tag.write(&mut bytes);
86        let borrowed = read_tag(&mut Cursor::new(bytes.as_slice())).ok()?;
87        Compostable::from_nbt_tag(borrowed.as_tag())
88    }
89
90    #[test]
91    fn round_trips_both_codecs() {
92        let value = Compostable::new(Identifier::vanilla_static("compostable/low"));
93
94        let nbt = value.clone().to_nbt_tag();
95        assert_eq!(parse(nbt), Some(value.clone()));
96
97        let mut network = Vec::new();
98        value
99            .write(&mut network)
100            .expect("compostable should encode");
101        assert_eq!(
102            Compostable::read(&mut Cursor::new(network.as_slice()))
103                .expect("compostable should decode"),
104            value
105        );
106    }
107}