use std::collections::HashMap;
use bytemuck::cast_slice;
use crate::tags::{Array, List, String, Tag, TagId};
fn serialize_byte(data: &i8, buffer: &mut Vec<u8>) {
buffer.push(*data as u8);
}
fn serialize_short(data: &i16, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(&data.to_be_bytes());
}
fn serialize_int(data: &i32, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(&data.to_be_bytes());
}
fn serialize_long(data: &i64, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(&data.to_be_bytes());
}
fn serialize_float(data: &f32, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(&data.to_be_bytes());
}
fn serialize_double(data: &f64, buffer: &mut Vec<u8>) {
buffer.extend_from_slice(&data.to_be_bytes());
}
fn serialize_byte_array(data: &Array<i8>, buffer: &mut Vec<u8>) {
serialize_int(&(data.len() as i32), buffer);
buffer.extend_from_slice(cast_slice(&data.items));
}
fn serialize_string(data: &String, buffer: &mut Vec<u8>) {
serialize_short(&(data.len() as u16 as i16), buffer);
buffer.extend_from_slice(data.as_bytes());
}
fn serialize_int_array(data: &Array<i32>, buffer: &mut Vec<u8>) {
serialize_int(&(data.len() as i32), buffer);
for v in data.iter() {
buffer.extend_from_slice(&v.to_be_bytes());
}
}
fn serialize_long_array(data: &Array<i64>, buffer: &mut Vec<u8>) {
serialize_int(&(data.len() as i32), buffer);
for v in data.iter() {
buffer.extend_from_slice(&v.to_be_bytes());
}
}
fn serialize_list(list: &List, buffer: &mut Vec<u8>) {
macro_rules! serialize {
($data:ident, $serializer:ident, $variant:ident) => {{
buffer.push(TagId::$variant as u8);
serialize_int(&($data.len() as i32), buffer);
for value in $data.iter() {
$serializer(value, buffer);
}
}};
}
match list {
List::End => {
buffer.extend_from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00]);
}
List::Byte(data) => serialize!(data, serialize_byte, Byte),
List::Short(data) => serialize!(data, serialize_short, Short),
List::Int(data) => serialize!(data, serialize_int, Int),
List::Long(data) => serialize!(data, serialize_long, Long),
List::Float(data) => serialize!(data, serialize_float, Float),
List::Double(data) => serialize!(data, serialize_double, Double),
List::ByteArray(data) => serialize!(data, serialize_byte_array, ByteArray),
List::String(data) => serialize!(data, serialize_string, String),
List::List(data) => serialize!(data, serialize_list, List),
List::Compound(data) => serialize!(data, serialize_compound, Compound),
List::IntArray(data) => serialize!(data, serialize_int_array, IntArray),
List::LongArray(data) => serialize!(data, serialize_long_array, LongArray),
}
}
fn serialize_compound(data: &HashMap<String, Tag>, buffer: &mut Vec<u8>) {
for (key, tag) in data {
serialize_named_tag(key, tag, buffer);
}
buffer.push(0x00);
}
fn serialize_payload(data: &Tag, buffer: &mut Vec<u8>) {
match data {
Tag::End => {}
Tag::Byte(data) => serialize_byte(data, buffer),
Tag::Short(data) => serialize_short(data, buffer),
Tag::Int(data) => serialize_int(data, buffer),
Tag::Long(data) => serialize_long(data, buffer),
Tag::Float(data) => serialize_float(data, buffer),
Tag::Double(data) => serialize_double(data, buffer),
Tag::ByteArray(data) => serialize_byte_array(data, buffer),
Tag::String(data) => serialize_string(data, buffer),
Tag::List(data) => serialize_list(data, buffer),
Tag::Compound(data) => serialize_compound(data, buffer),
Tag::IntArray(data) => serialize_int_array(data, buffer),
Tag::LongArray(data) => serialize_long_array(data, buffer),
}
}
fn serialize_named_tag(name: &String, tag: &Tag, buffer: &mut Vec<u8>) {
buffer.push(tag.tag_id() as u8);
serialize_string(name, buffer);
serialize_payload(tag, buffer);
}
pub fn serialize_nbt(name: &String, data: &HashMap<String, Tag>) -> Box<[u8]> {
let mut buffer = Vec::new();
buffer.push(TagId::Compound as u8);
serialize_string(name, &mut buffer);
serialize_compound(data, &mut buffer);
buffer.into_boxed_slice()
}