1use std::io;
2
3use super::{reader::Reader, writer::Writer};
4use crate::{endian::RawSlice, mutf8::mstr, num::Num, NbtReadError};
5
6#[inline]
7pub(super) fn read_str<'a>(reader: &mut impl Reader<'a>) -> Result<&'a mstr, NbtReadError> {
8 let len: u16 = reader.read_u16()?;
9 let buf: &[u8] = reader.read_slice(len as usize)?;
10 Ok(mstr::from_mutf8(buf))
11}
12
13#[inline]
14pub(super) fn read_slice_with_len<'a, T: Num>(
15 reader: &mut impl Reader<'a>,
16) -> Result<RawSlice<'a, T>, NbtReadError> {
17 let len: i32 = reader.read_i32()?;
18
19 if len <= 0 {
20 return Ok(RawSlice::new());
21 }
22
23 read_slice(reader, len as usize)
24}
25
26#[inline]
27pub(super) fn read_byte_slice_with_len<'a>(reader: &mut impl Reader<'a>) -> io::Result<&'a [u8]> {
28 let len: i32 = reader.read_i32()?;
29
30 if len <= 0 {
31 return Ok(&[]);
32 }
33
34 reader.read_slice(len as usize)
35}
36
37#[inline]
38pub(super) fn read_slice<'a, T: Num>(
39 reader: &mut impl Reader<'a>,
40 len: usize,
41) -> Result<RawSlice<'a, T>, NbtReadError> {
42 let buf: &[u8] = reader.read_slice(len * size_of::<T>())?;
43 Ok(RawSlice::from_bytes(buf))
44}
45
46#[inline]
47pub(super) fn write_str(writer: &mut impl Writer, str: &mstr) {
48 let len: u16 = str.len().min(u16::MAX as usize) as u16;
49 writer.write_u16(len);
50 writer.write_slice(&str.as_bytes()[..len as usize]);
51}
52
53#[inline]
54pub(super) fn write_slice<'a, T: Num>(writer: &mut impl Writer, slice: RawSlice<'a, T>) {
55 let len: i32 = (slice.len() as i32).min(i32::MAX);
56 writer.write_i32(len);
57 writer.write_slice(&slice.to_bytes()[..len as usize * size_of::<T>()]);
58}
59
60macro_rules! impl_tag {
61 ($name:ident, $( $(@$deref:tt)? + )? $type:ty) => {
62 paste! {
63 #[inline]
64 pub fn $name(&self) -> Option<$type> {
65 match self {
66 Tag::[< $name:camel >](val) => Some(impl_tag!(@internal { $( $($deref)? + )? } { val } { *val })),
67 _ => None,
68 }
69 }
70
71 impl_tag!(@internal { $( $($deref)? + )? } {} {
72 #[inline]
73 pub fn [< $name _mut >](&mut self) -> Option<&mut $type> {
74 match self {
75 Tag::[< $name:camel >](val) => Some(val),
76 _ => None,
77 }
78 }
79
80 #[inline]
81 pub fn [< into_ $name >](self) -> Option<$type> {
82 match self {
83 Tag::[< $name:camel >](val) => Some(val),
84 _ => None,
85 }
86 }
87 });
88
89 }
90 };
91 ( @internal { } { $($then:tt)* } { $($else:tt)* } ) => { $($then)* };
92 ( @internal { + } { $($then:tt)* } { $($else:tt)* } ) => { $($else)* };
93}
94pub(super) use impl_tag;
95
96macro_rules! impl_list {
97 ($name:ident, $( $(@$deref:tt)? + )? $type:ty, $new:expr) => {
98 paste! {
99 #[inline]
100 pub fn [< $name s >](&self) -> Option<$type> {
101 match self {
102 List::[< $name:camel >](val) => Some(impl_list!(@internal { $( $($deref)? + )? } { val } { *val })),
103 List::Empty => Some(const { $new }),
104 _ => None,
105 }
106 }
107 }
108 };
109 ( @internal { } { $($then:tt)* } { $($else:tt)* } ) => { $($then)* };
110 ( @internal { + } { $($then:tt)* } { $($else:tt)* } ) => { $($else)* };
111}
112pub(super) use impl_list;