NbtReader都实现好了
是时候开始实现read了
This commit is contained in:
parent
ec0166a3c4
commit
0a170b7269
@ -28,7 +28,8 @@ macro_rules! read_uncheck {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn $name(&mut self) -> $ty {
|
pub unsafe fn $name(&mut self) -> $ty {
|
||||||
// 使用 std::ptr::read_unaligned 解决未对齐地址问题
|
// 使用 std::ptr::read_unaligned 解决未对齐地址问题
|
||||||
let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const $ty);
|
let ptr = self.data.as_ptr().add(self.cursor) as *const $ty;
|
||||||
|
let value = std::ptr::read_unaligned(ptr);
|
||||||
self.cursor += std::mem::size_of::<$ty>();
|
self.cursor += std::mem::size_of::<$ty>();
|
||||||
value.to_be()
|
value.to_be()
|
||||||
}
|
}
|
||||||
@ -43,6 +44,12 @@ impl NbtReader<'_> {
|
|||||||
// endian: Endian::Big,
|
// endian: Endian::Big,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// 向后滚动
|
||||||
|
#[inline]
|
||||||
|
pub fn roll_back(&mut self, len: usize) { self.cursor -= len; }
|
||||||
|
/// 向前滚动
|
||||||
|
#[inline]
|
||||||
|
pub fn roll_down(&mut self, len: usize) { self.cursor += len; }
|
||||||
/// 读取一个 u8 类型的数据
|
/// 读取一个 u8 类型的数据
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_u8(&mut self) -> u8 {
|
pub fn read_u8(&mut self) -> u8 {
|
||||||
@ -99,7 +106,16 @@ impl NbtReader<'_> {
|
|||||||
///
|
///
|
||||||
/// 会在超出长度时 panic
|
/// 会在超出长度时 panic
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_u32(&mut self) -> u32 { self.read_i32() as u32 }
|
pub fn read_u32(&mut self) -> u32 {
|
||||||
|
let value = u32::from_be_bytes([
|
||||||
|
self.data[self.cursor],
|
||||||
|
self.data[self.cursor + 1],
|
||||||
|
self.data[self.cursor + 2],
|
||||||
|
self.data[self.cursor + 3],
|
||||||
|
]);
|
||||||
|
self.cursor += 4;
|
||||||
|
value
|
||||||
|
}
|
||||||
/// 安全的读取 i64 类型的数据
|
/// 安全的读取 i64 类型的数据
|
||||||
///
|
///
|
||||||
/// 转换大小端(大端)
|
/// 转换大小端(大端)
|
||||||
@ -126,7 +142,20 @@ impl NbtReader<'_> {
|
|||||||
///
|
///
|
||||||
/// 会在超出长度时 panic
|
/// 会在超出长度时 panic
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_u64(&mut self) -> u64 { self.read_i64() as u64 }
|
pub fn read_u64(&mut self) -> u64 {
|
||||||
|
let value = u64::from_be_bytes([
|
||||||
|
self.data[self.cursor],
|
||||||
|
self.data[self.cursor + 1],
|
||||||
|
self.data[self.cursor + 2],
|
||||||
|
self.data[self.cursor + 3],
|
||||||
|
self.data[self.cursor + 4],
|
||||||
|
self.data[self.cursor + 5],
|
||||||
|
self.data[self.cursor + 6],
|
||||||
|
self.data[self.cursor + 7],
|
||||||
|
]);
|
||||||
|
self.cursor += 8;
|
||||||
|
value
|
||||||
|
}
|
||||||
/// 读取一个 f32 类型的数据
|
/// 读取一个 f32 类型的数据
|
||||||
///
|
///
|
||||||
/// 转换大小端
|
/// 转换大小端
|
||||||
@ -148,10 +177,10 @@ impl NbtReader<'_> {
|
|||||||
/// # 安全性
|
/// # 安全性
|
||||||
/// 允许未对齐的地址
|
/// 允许未对齐的地址
|
||||||
/// 长度溢出会导致 UB
|
/// 长度溢出会导致 UB
|
||||||
|
#[inline]
|
||||||
pub unsafe fn read_f32_unchecked(&mut self) -> f32 {
|
pub unsafe fn read_f32_unchecked(&mut self) -> f32 {
|
||||||
let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const u32);
|
let value = self.read_u32_unchecked();
|
||||||
self.cursor += 4;
|
std::mem::transmute::<u32, f32>(value)
|
||||||
std::mem::transmute::<u32, f32>(value.to_be())
|
|
||||||
}
|
}
|
||||||
/// 读取一个 f64 类型的数据
|
/// 读取一个 f64 类型的数据
|
||||||
/// 转换大小端
|
/// 转换大小端
|
||||||
@ -159,10 +188,10 @@ impl NbtReader<'_> {
|
|||||||
/// # 安全性
|
/// # 安全性
|
||||||
/// 允许未对齐的地址
|
/// 允许未对齐的地址
|
||||||
/// 长度溢出会导致 UB
|
/// 长度溢出会导致 UB
|
||||||
|
#[inline]
|
||||||
pub unsafe fn read_f64_unchecked(&mut self) -> f64 {
|
pub unsafe fn read_f64_unchecked(&mut self) -> f64 {
|
||||||
let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const u64);
|
let value = self.read_u64_unchecked();
|
||||||
self.cursor += 8;
|
std::mem::transmute::<u64, f64>(value)
|
||||||
std::mem::transmute::<u64, f64>(value.to_be())
|
|
||||||
}
|
}
|
||||||
/// 读取指定长度的 u8 数组
|
/// 读取指定长度的 u8 数组
|
||||||
///
|
///
|
||||||
@ -180,10 +209,20 @@ impl NbtReader<'_> {
|
|||||||
/// # 安全性
|
/// # 安全性
|
||||||
///
|
///
|
||||||
/// 长度溢出会导致 UB
|
/// 长度溢出会导致 UB
|
||||||
pub fn read_i8_array_unchecked(&mut self, len: usize) -> &[i8] {
|
#[inline]
|
||||||
let value = unsafe {
|
pub unsafe fn read_i8_array_unchecked(&mut self, len: usize) -> Vec<i8> {
|
||||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i8, len)
|
let value = std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i8, len);
|
||||||
};
|
self.cursor += len;
|
||||||
|
value.to_vec()
|
||||||
|
}
|
||||||
|
/// 读取指定长度的 i8 数组
|
||||||
|
///
|
||||||
|
/// # 安全性
|
||||||
|
///
|
||||||
|
/// 长度溢出会导致 panic
|
||||||
|
#[inline]
|
||||||
|
pub fn read_i8_array(&mut self, len: usize) -> Vec<i8> {
|
||||||
|
let value = self.data[self.cursor..self.cursor + len].iter().map(|&n| n as i8).collect();
|
||||||
self.cursor += len;
|
self.cursor += len;
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
@ -203,8 +242,8 @@ impl NbtReader<'_> {
|
|||||||
/// # 安全性
|
/// # 安全性
|
||||||
///
|
///
|
||||||
/// 长度溢出会导致 UB
|
/// 长度溢出会导致 UB
|
||||||
pub fn read_i32_array_unchecked(&mut self, len: usize) -> Vec<i32> {
|
#[inline]
|
||||||
unsafe {
|
pub unsafe fn read_i32_array_unchecked(&mut self, len: usize) -> Vec<i32> {
|
||||||
let value =
|
let value =
|
||||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i32, len);
|
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i32, len);
|
||||||
let mut value = value.to_vec();
|
let mut value = value.to_vec();
|
||||||
@ -214,14 +253,27 @@ impl NbtReader<'_> {
|
|||||||
self.cursor += len * 4;
|
self.cursor += len * 4;
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
/// 读取指定长度的 i32 数组
|
||||||
|
///
|
||||||
|
/// # 安全性
|
||||||
|
///
|
||||||
|
/// 长度溢出会导致 panic
|
||||||
|
#[inline]
|
||||||
|
pub fn read_i32_array(&mut self, len: usize) -> Vec<i32> {
|
||||||
|
let value = self.data[self.cursor..self.cursor + len * 4]
|
||||||
|
.chunks_exact(4)
|
||||||
|
.map(|n| i32::from_be_bytes(n[0..4].try_into().unwrap()))
|
||||||
|
.collect();
|
||||||
|
self.cursor += len * 4;
|
||||||
|
value
|
||||||
}
|
}
|
||||||
/// 读取指定长度的 i64 数组
|
/// 读取指定长度的 i64 数组
|
||||||
///
|
///
|
||||||
/// # 安全性
|
/// # 安全性
|
||||||
///
|
///
|
||||||
/// 长度溢出会导致 UB
|
/// 长度溢出会导致 UB
|
||||||
pub fn read_i64_array_unchecked(&mut self, len: usize) -> Vec<i64> {
|
#[inline]
|
||||||
unsafe {
|
pub unsafe fn read_i64_array_unchecked(&mut self, len: usize) -> Vec<i64> {
|
||||||
let value =
|
let value =
|
||||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i64, len);
|
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i64, len);
|
||||||
let mut value = value.to_vec();
|
let mut value = value.to_vec();
|
||||||
@ -231,6 +283,19 @@ impl NbtReader<'_> {
|
|||||||
self.cursor += len * 8;
|
self.cursor += len * 8;
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
/// 读取指定长度的 i64 数组
|
||||||
|
///
|
||||||
|
/// # 安全性
|
||||||
|
///
|
||||||
|
/// 长度溢出会导致 panic
|
||||||
|
#[inline]
|
||||||
|
pub fn read_i64_array(&mut self, len: usize) -> Vec<i64> {
|
||||||
|
let value = self.data[self.cursor..self.cursor + len * 8]
|
||||||
|
.chunks_exact(8)
|
||||||
|
.map(|n| i64::from_be_bytes(n[0..8].try_into().unwrap()))
|
||||||
|
.collect();
|
||||||
|
self.cursor += len * 8;
|
||||||
|
value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,3 +328,12 @@ pub enum NbtValue {
|
|||||||
/// 12
|
/// 12
|
||||||
LongArray(Vec<i64>),
|
LongArray(Vec<i64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NbtValue {
|
||||||
|
pub fn from_binary(data: &mut [u8]) -> NbtValue {
|
||||||
|
let reader = NbtReader::new(data);
|
||||||
|
NbtValue::from_reader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_reader(reader: NbtReader) -> NbtValue { todo!() }
|
||||||
|
}
|
||||||
|
@ -23,22 +23,31 @@ mod safe_test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_x8() {
|
fn read_x8() {
|
||||||
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
let mut data: Vec<u8> = vec![0x01, 0x02, i8::MIN as u8, u8::MAX];
|
||||||
let mut reader = NbtReader::new(&mut data);
|
let mut reader = NbtReader::new(data.as_mut_slice());
|
||||||
assert_eq!(reader.read_i8(), 0x01);
|
assert_eq!(reader.read_i8(), 0x01);
|
||||||
assert_eq!(reader.cursor, 1);
|
assert_eq!(reader.cursor, 1);
|
||||||
assert_eq!(reader.read_u8(), 0x02);
|
assert_eq!(reader.read_u8(), 0x02);
|
||||||
assert_eq!(reader.cursor, 2);
|
assert_eq!(reader.cursor, 2);
|
||||||
|
assert_eq!(reader.read_i8(), i8::MIN);
|
||||||
|
assert_eq!(reader.cursor, 3);
|
||||||
|
assert_eq!(reader.read_u8(), u8::MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_x16() {
|
fn read_x16() {
|
||||||
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
||||||
|
data.extend(i16::MIN.to_be_bytes());
|
||||||
|
data.extend(i16::MAX.to_be_bytes());
|
||||||
let mut reader = NbtReader::new(&mut data);
|
let mut reader = NbtReader::new(&mut data);
|
||||||
assert_eq!(reader.read_i16(), 0x0102);
|
assert_eq!(reader.read_i16(), 0x0102);
|
||||||
assert_eq!(reader.cursor, 2);
|
assert_eq!(reader.cursor, 2);
|
||||||
assert_eq!(reader.read_u16(), 0x0304);
|
assert_eq!(reader.read_u16(), 0x0304);
|
||||||
assert_eq!(reader.cursor, 4);
|
assert_eq!(reader.cursor, 4);
|
||||||
|
assert_eq!(reader.read_i16(), i16::MIN);
|
||||||
|
assert_eq!(reader.cursor, 6);
|
||||||
|
assert_eq!(reader.read_i16(), i16::MAX);
|
||||||
|
assert_eq!(reader.cursor, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -89,32 +98,130 @@ mod safe_test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// unsafe 测试
|
||||||
|
///
|
||||||
|
/// 实际内容与 safe_test 一致
|
||||||
|
///
|
||||||
|
/// 测试方法就是 safe 读一遍,然后 unsafe 读一遍,然后比较结果
|
||||||
|
///
|
||||||
|
/// 反正只要 safe 测试过了,unsafe 直接参考 safe 的测试结果就行
|
||||||
mod unsafe_test {
|
mod unsafe_test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_array() {
|
fn read_x16() {
|
||||||
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
||||||
let mut reader = NbtReader::new(&mut data);
|
let mut reader = NbtReader::new(&mut data);
|
||||||
assert_eq!(reader.read_u8_array(2), &[0x01, 0x02]);
|
unsafe {
|
||||||
|
let value = reader.read_i16_unchecked();
|
||||||
|
reader.roll_back(2);
|
||||||
|
let safe_value = reader.read_i16();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
assert_eq!(reader.cursor, 2);
|
assert_eq!(reader.cursor, 2);
|
||||||
assert_eq!(reader.read_i8_array_unchecked(2), &[0x03, 0x04]);
|
let value = reader.read_u16_unchecked();
|
||||||
|
reader.roll_back(2);
|
||||||
|
let safe_value = reader.read_u16();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
assert_eq!(reader.cursor, 4);
|
assert_eq!(reader.cursor, 4);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_x32() {
|
||||||
|
let mut data = vec![0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04];
|
||||||
|
let mut reader = NbtReader::new(&mut data);
|
||||||
|
unsafe {
|
||||||
|
let value = reader.read_i32_unchecked();
|
||||||
|
reader.roll_back(4);
|
||||||
|
let safe_value = reader.read_i32();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 4);
|
||||||
|
let value = reader.read_u32_unchecked();
|
||||||
|
reader.roll_back(4);
|
||||||
|
let safe_value = reader.read_u32();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_x64() {
|
||||||
|
let mut data = vec![
|
||||||
|
0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
|
||||||
|
0x03, 0x04,
|
||||||
|
];
|
||||||
|
let mut reader = NbtReader::new(&mut data);
|
||||||
|
unsafe {
|
||||||
|
let value = reader.read_i64_unchecked();
|
||||||
|
reader.roll_back(8);
|
||||||
|
let safe_value = reader.read_i64();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 8);
|
||||||
|
let value = reader.read_u64_unchecked();
|
||||||
|
reader.roll_back(8);
|
||||||
|
let safe_value = reader.read_u64();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_fxx() {
|
||||||
|
let mut data = Vec::with_capacity(12);
|
||||||
|
data.extend_from_slice(&std::f32::consts::PI.to_be_bytes());
|
||||||
|
data.extend_from_slice(&std::f64::consts::PI.to_be_bytes());
|
||||||
|
println!("{:?}", data);
|
||||||
|
let mut reader = NbtReader::new(&mut data);
|
||||||
|
unsafe {
|
||||||
|
let value = reader.read_f32_unchecked();
|
||||||
|
reader.roll_back(4);
|
||||||
|
let safe_value = reader.read_f32();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 4);
|
||||||
|
let value = reader.read_f64_unchecked();
|
||||||
|
reader.roll_back(8);
|
||||||
|
let safe_value = reader.read_f64();
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_array() {
|
||||||
|
let mut data = gen_datas(100);
|
||||||
|
let mut reader = NbtReader::new(&mut data);
|
||||||
|
unsafe {
|
||||||
|
let value = reader.read_i8_array_unchecked(100);
|
||||||
|
reader.roll_back(100);
|
||||||
|
let safe_value = reader.read_i8_array(100);
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_i32_array() {
|
fn read_i32_array() {
|
||||||
let mut value = 1234567890_i32.to_be_bytes();
|
let mut value = gen_datas(4 * 100);
|
||||||
let mut reader = NbtReader::new(&mut value);
|
let mut reader = NbtReader::new(&mut value);
|
||||||
assert_eq!(reader.read_i32_array_unchecked(1), &[1234567890_i32]);
|
unsafe {
|
||||||
assert_eq!(reader.cursor, 4);
|
let value = reader.read_i32_array_unchecked(100);
|
||||||
|
reader.roll_back(100 * 4);
|
||||||
|
let safe_value = reader.read_i32_array(100);
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 100 * 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_i64_array() {
|
fn read_i64_array() {
|
||||||
let mut value = 1234567890_i64.to_be_bytes();
|
let mut value = gen_datas(8 * 100);
|
||||||
let mut reader = NbtReader::new(&mut value);
|
let mut reader = NbtReader::new(&mut value);
|
||||||
assert_eq!(reader.read_i64_array_unchecked(1), &[1234567890_i64]);
|
unsafe {
|
||||||
assert_eq!(reader.cursor, 8);
|
let value = reader.read_i64_array_unchecked(100);
|
||||||
|
reader.roll_back(100 * 8);
|
||||||
|
let safe_value = reader.read_i64_array(100);
|
||||||
|
assert_eq!(value, safe_value);
|
||||||
|
assert_eq!(reader.cursor, 100 * 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user