basalt_types/nbt/
encode.rs1use crate::nbt::tag::{NbtCompound, NbtTag, tag_id};
2use crate::{Encode, EncodedSize, Result};
3
4fn encode_nbt_string(s: &str, buf: &mut Vec<u8>) -> Result<()> {
10 let bytes = s.as_bytes();
11 (bytes.len() as u16).encode(buf)?;
12 buf.extend_from_slice(bytes);
13 Ok(())
14}
15
16fn nbt_string_size(s: &str) -> usize {
18 2 + s.len()
19}
20
21fn encode_tag_payload(tag: &NbtTag, buf: &mut Vec<u8>) -> Result<()> {
27 match tag {
28 NbtTag::Byte(v) => v.encode(buf),
29 NbtTag::Short(v) => v.encode(buf),
30 NbtTag::Int(v) => v.encode(buf),
31 NbtTag::Long(v) => v.encode(buf),
32 NbtTag::Float(v) => v.encode(buf),
33 NbtTag::Double(v) => v.encode(buf),
34 NbtTag::ByteArray(v) => {
35 (v.len() as i32).encode(buf)?;
36 for &b in v {
37 b.encode(buf)?;
38 }
39 Ok(())
40 }
41 NbtTag::String(v) => encode_nbt_string(v, buf),
42 NbtTag::List(list) => {
43 list.element_type.encode(buf)?;
44 (list.elements.len() as i32).encode(buf)?;
45 for elem in &list.elements {
46 encode_tag_payload(elem, buf)?;
47 }
48 Ok(())
49 }
50 NbtTag::Compound(compound) => {
51 encode_compound_payload(compound, buf)?;
52 Ok(())
53 }
54 NbtTag::IntArray(v) => {
55 (v.len() as i32).encode(buf)?;
56 for &val in v {
57 val.encode(buf)?;
58 }
59 Ok(())
60 }
61 NbtTag::LongArray(v) => {
62 (v.len() as i32).encode(buf)?;
63 for &val in v {
64 val.encode(buf)?;
65 }
66 Ok(())
67 }
68 }
69}
70
71fn encode_compound_payload(compound: &NbtCompound, buf: &mut Vec<u8>) -> Result<()> {
76 for (name, tag) in compound.iter() {
77 tag.tag_id().encode(buf)?;
78 encode_nbt_string(name, buf)?;
79 encode_tag_payload(tag, buf)?;
80 }
81 tag_id::END.encode(buf)?;
82 Ok(())
83}
84
85fn tag_payload_size(tag: &NbtTag) -> usize {
87 match tag {
88 NbtTag::Byte(_) => 1,
89 NbtTag::Short(_) => 2,
90 NbtTag::Int(_) => 4,
91 NbtTag::Long(_) => 8,
92 NbtTag::Float(_) => 4,
93 NbtTag::Double(_) => 8,
94 NbtTag::ByteArray(v) => 4 + v.len(),
95 NbtTag::String(v) => nbt_string_size(v),
96 NbtTag::List(list) => {
97 1 + 4 + list.elements.iter().map(tag_payload_size).sum::<usize>()
99 }
100 NbtTag::Compound(compound) => compound_payload_size(compound),
101 NbtTag::IntArray(v) => 4 + v.len() * 4,
102 NbtTag::LongArray(v) => 4 + v.len() * 8,
103 }
104}
105
106fn compound_payload_size(compound: &NbtCompound) -> usize {
108 let entries_size: usize = compound
109 .iter()
110 .map(|(name, tag)| {
111 1 + nbt_string_size(name) + tag_payload_size(tag)
113 })
114 .sum();
115 entries_size + 1 }
117
118impl Encode for NbtCompound {
128 fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
130 tag_id::COMPOUND.encode(buf)?;
131 encode_compound_payload(self, buf)
132 }
133}
134
135impl EncodedSize for NbtCompound {
140 fn encoded_size(&self) -> usize {
142 1 + compound_payload_size(self)
143 }
144}
145
146impl Encode for NbtTag {
153 fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
155 match self {
156 NbtTag::Compound(compound) => compound.encode(buf),
157 _ => {
158 let mut wrapper = NbtCompound::new();
160 wrapper.insert("", self.clone());
161 wrapper.encode(buf)
162 }
163 }
164 }
165}
166
167impl EncodedSize for NbtTag {
169 fn encoded_size(&self) -> usize {
170 match self {
171 NbtTag::Compound(compound) => compound.encoded_size(),
172 _ => {
173 let mut wrapper = NbtCompound::new();
174 wrapper.insert("", self.clone());
175 wrapper.encoded_size()
176 }
177 }
178 }
179}