diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..b59f5e0 --- /dev/null +++ b/src/data.rs @@ -0,0 +1,165 @@ +use std::collections::HashMap; +use std::io::{Cursor, Read}; +use std::sync::Arc; + +/// NBT 里除了字符串的长度量都是 i32 +pub type NbtLength = i32; + +/// NBT 里的字符串独树一帜的把自己的长度用一个u32表示 +/// 不如说为啥别的不用 u32 呢 +pub type StringLength = u32; + +/// Reader +pub type Reader<'a> = Cursor<&'a [u8]>; + +/// 一个 NBT list 的基本素养 +pub trait NbtListTrait { + /// 内容类型 + type ValueType; + /// 输出类型标识符 + /// 类型标识符 + /// (0x07) Vec + /// (0x09) Vec + /// (0x0A) Compound + /// (0x0B) Vec + /// (0x0C) Vec + fn type_tag() -> u8; + /// 输出自身长度 + fn len(&self) -> usize; + /// 通过索引获取内容 + fn get_index(&self, index: usize) -> Option; + /// 通过名称获取内容 + fn get_name(&self, name: &str) -> Option; +} + +/// 通过范型实现的 NBT List (其实包括了 NbtCompound) +#[derive(Debug, Clone)] +pub struct NbtList { + /// 内容 + pub value: T, +} + +#[allow(unused)] +impl NbtList +where + T: NbtListTrait, +{ + pub fn type_tag() -> u8 { T::type_tag() } + + pub fn len(&self) -> usize { self.value.len() } + + pub fn get_index(&self, index: usize) -> Option { self.value.get_index(index) } + + pub fn get_name(&self, name: &str) -> Option { self.value.get_name(name) } +} + +macro_rules! add_impl { + ($type:ty, $value:ty, $tag:expr, false) => { + impl NbtListTrait for $type { + type ValueType = $value; + + fn type_tag() -> u8 { $tag } + + fn len(&self) -> usize { self.len() } + + fn get_index(&self, _: usize) -> Option { None } + + fn get_name(&self, name: &str) -> Option { self.get(name).copied() } + } + }; + ($type:ty, $value:ty ,$tag:expr, true) => { + impl NbtListTrait for $type { + type ValueType = $value; + + fn type_tag() -> u8 { $tag } + + fn len(&self) -> usize { self.len() } + + fn get_index(&self, index: usize) -> Option { self.get(index).copied() } + + fn get_name(&self, _: &str) -> Option { None } + } + }; +} + +add_impl!(Vec, bool, 0x07, true); +add_impl!(HashMap, i32>, i32, 0x0A, false); +add_impl!(Vec, i32, 0x0B, true); +add_impl!(Vec, i64, 0x0C, true); + +/// 基本 NBT 数据类型 +#[allow(unused)] +#[derive(Debug, Clone)] +pub enum NbtValue { + /// 0x00 + /// 标志着一个 NBT Compound/List 的结束 + NbtEnd, + /// 0x01 + NbtByte(bool), + /// 0x02 + NbtShort(i16), + /// 0x03 + NbtInt(i32), + /// 0x04 + NbtLong(i64), + /// 0x05 + NbtFloat(f32), + /// 0x06 + NbtDouble(f64), + /// 0x08 + /// 一个 UTF-8 编码的定长字符串 + NbtString(Arc), +} + +macro_rules! export_data { + ($name:ident, $nbt_name:ident, $type:ty) => { + pub fn $name(&self) -> Option<$type> { + match self { + Self::$nbt_name(value) => Some(value.to_owned()), + _ => None, + } + } + }; +} + +macro_rules! read_data { + ($name:ident, $nbt_name:ident, bool, 1) => { + pub fn $name(value: &mut Reader) -> Self { + let mut buff = [0_u8]; + _ = value.read(&mut buff).unwrap(); + Self::$nbt_name(buff[0] != 0) + } + }; + ($name:ident, $nbt_name:ident, $type:ty, $len:expr) => { + pub fn $name(value: &mut Reader) -> Self { + let mut buff = [0_u8; $len]; + _ = value.read(&mut buff).unwrap(); + Self::$nbt_name(<$type>::from_be_bytes(buff)) + } + }; +} + +#[allow(unused)] +impl NbtValue { + export_data!(as_bool, NbtByte, bool); + export_data!(as_i16, NbtShort, i16); + export_data!(as_i32, NbtInt, i32); + export_data!(as_i64, NbtLong, i64); + export_data!(as_f32, NbtFloat, f32); + export_data!(as_f64, NbtDouble, f64); + export_data!(as_string, NbtString, Arc); + + read_data!(from_bool, NbtByte, bool, 1); + read_data!(from_i16, NbtShort, i16, 2); + read_data!(from_i32, NbtInt, i32, 4); + read_data!(from_i64, NbtLong, i64, 8); + read_data!(from_f32, NbtFloat, f32, 4); + read_data!(from_f64, NbtDouble, f64, 8); + + pub fn from_string(value: &mut Reader) -> Self { + let len: StringLength = Self::from_i32(value).as_i32().unwrap() as u32; + let mut buff = vec![0_u8; len as usize]; + _ = value.read(&mut buff).unwrap(); + Self::NbtString(Arc::from(String::from_utf8(buff).unwrap())) + } +}