NbtReader都实现好了
是时候开始实现read了
This commit is contained in:
parent
ec0166a3c4
commit
0a170b7269
@ -28,7 +28,8 @@ macro_rules! read_uncheck {
|
||||
#[inline]
|
||||
pub unsafe fn $name(&mut self) -> $ty {
|
||||
// 使用 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>();
|
||||
value.to_be()
|
||||
}
|
||||
@ -43,6 +44,12 @@ impl NbtReader<'_> {
|
||||
// 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 类型的数据
|
||||
#[inline]
|
||||
pub fn read_u8(&mut self) -> u8 {
|
||||
@ -99,7 +106,16 @@ impl NbtReader<'_> {
|
||||
///
|
||||
/// 会在超出长度时 panic
|
||||
#[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 类型的数据
|
||||
///
|
||||
/// 转换大小端(大端)
|
||||
@ -126,7 +142,20 @@ impl NbtReader<'_> {
|
||||
///
|
||||
/// 会在超出长度时 panic
|
||||
#[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 类型的数据
|
||||
///
|
||||
/// 转换大小端
|
||||
@ -148,10 +177,10 @@ impl NbtReader<'_> {
|
||||
/// # 安全性
|
||||
/// 允许未对齐的地址
|
||||
/// 长度溢出会导致 UB
|
||||
#[inline]
|
||||
pub unsafe fn read_f32_unchecked(&mut self) -> f32 {
|
||||
let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const u32);
|
||||
self.cursor += 4;
|
||||
std::mem::transmute::<u32, f32>(value.to_be())
|
||||
let value = self.read_u32_unchecked();
|
||||
std::mem::transmute::<u32, f32>(value)
|
||||
}
|
||||
/// 读取一个 f64 类型的数据
|
||||
/// 转换大小端
|
||||
@ -159,10 +188,10 @@ impl NbtReader<'_> {
|
||||
/// # 安全性
|
||||
/// 允许未对齐的地址
|
||||
/// 长度溢出会导致 UB
|
||||
#[inline]
|
||||
pub unsafe fn read_f64_unchecked(&mut self) -> f64 {
|
||||
let value = std::ptr::read_unaligned(self.data[self.cursor..].as_ptr() as *const u64);
|
||||
self.cursor += 8;
|
||||
std::mem::transmute::<u64, f64>(value.to_be())
|
||||
let value = self.read_u64_unchecked();
|
||||
std::mem::transmute::<u64, f64>(value)
|
||||
}
|
||||
/// 读取指定长度的 u8 数组
|
||||
///
|
||||
@ -180,10 +209,20 @@ impl NbtReader<'_> {
|
||||
/// # 安全性
|
||||
///
|
||||
/// 长度溢出会导致 UB
|
||||
pub fn read_i8_array_unchecked(&mut self, len: usize) -> &[i8] {
|
||||
let value = unsafe {
|
||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i8, len)
|
||||
};
|
||||
#[inline]
|
||||
pub unsafe fn read_i8_array_unchecked(&mut self, len: usize) -> Vec<i8> {
|
||||
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;
|
||||
value
|
||||
}
|
||||
@ -203,34 +242,60 @@ impl NbtReader<'_> {
|
||||
/// # 安全性
|
||||
///
|
||||
/// 长度溢出会导致 UB
|
||||
pub fn read_i32_array_unchecked(&mut self, len: usize) -> Vec<i32> {
|
||||
unsafe {
|
||||
let value =
|
||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i32, len);
|
||||
let mut value = value.to_vec();
|
||||
for n in &mut value {
|
||||
*n = n.to_be();
|
||||
}
|
||||
self.cursor += len * 4;
|
||||
value
|
||||
#[inline]
|
||||
pub unsafe fn read_i32_array_unchecked(&mut self, len: usize) -> Vec<i32> {
|
||||
let value =
|
||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i32, len);
|
||||
let mut value = value.to_vec();
|
||||
for n in &mut value {
|
||||
*n = n.to_be();
|
||||
}
|
||||
self.cursor += len * 4;
|
||||
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 数组
|
||||
///
|
||||
/// # 安全性
|
||||
///
|
||||
/// 长度溢出会导致 UB
|
||||
pub fn read_i64_array_unchecked(&mut self, len: usize) -> Vec<i64> {
|
||||
unsafe {
|
||||
let value =
|
||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i64, len);
|
||||
let mut value = value.to_vec();
|
||||
for n in &mut value {
|
||||
*n = n.to_be();
|
||||
}
|
||||
self.cursor += len * 8;
|
||||
value
|
||||
#[inline]
|
||||
pub unsafe fn read_i64_array_unchecked(&mut self, len: usize) -> Vec<i64> {
|
||||
let value =
|
||||
std::slice::from_raw_parts(self.data[self.cursor..].as_ptr() as *const i64, len);
|
||||
let mut value = value.to_vec();
|
||||
for n in &mut value {
|
||||
*n = n.to_be();
|
||||
}
|
||||
self.cursor += len * 8;
|
||||
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
|
||||
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]
|
||||
fn read_x8() {
|
||||
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
||||
let mut reader = NbtReader::new(&mut data);
|
||||
let mut data: Vec<u8> = vec![0x01, 0x02, i8::MIN as u8, u8::MAX];
|
||||
let mut reader = NbtReader::new(data.as_mut_slice());
|
||||
assert_eq!(reader.read_i8(), 0x01);
|
||||
assert_eq!(reader.cursor, 1);
|
||||
assert_eq!(reader.read_u8(), 0x02);
|
||||
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]
|
||||
fn read_x16() {
|
||||
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);
|
||||
assert_eq!(reader.read_i16(), 0x0102);
|
||||
assert_eq!(reader.cursor, 2);
|
||||
assert_eq!(reader.read_u16(), 0x0304);
|
||||
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]
|
||||
@ -89,32 +98,130 @@ mod safe_test {
|
||||
}
|
||||
}
|
||||
|
||||
/// unsafe 测试
|
||||
///
|
||||
/// 实际内容与 safe_test 一致
|
||||
///
|
||||
/// 测试方法就是 safe 读一遍,然后 unsafe 读一遍,然后比较结果
|
||||
///
|
||||
/// 反正只要 safe 测试过了,unsafe 直接参考 safe 的测试结果就行
|
||||
mod unsafe_test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_array() {
|
||||
fn read_x16() {
|
||||
let mut data = vec![0x01, 0x02, 0x03, 0x04];
|
||||
let mut reader = NbtReader::new(&mut data);
|
||||
assert_eq!(reader.read_u8_array(2), &[0x01, 0x02]);
|
||||
assert_eq!(reader.cursor, 2);
|
||||
assert_eq!(reader.read_i8_array_unchecked(2), &[0x03, 0x04]);
|
||||
assert_eq!(reader.cursor, 4);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[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]
|
||||
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);
|
||||
assert_eq!(reader.read_i32_array_unchecked(1), &[1234567890_i32]);
|
||||
assert_eq!(reader.cursor, 4);
|
||||
unsafe {
|
||||
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]
|
||||
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);
|
||||
assert_eq!(reader.read_i64_array_unchecked(1), &[1234567890_i64]);
|
||||
assert_eq!(reader.cursor, 8);
|
||||
unsafe {
|
||||
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