na_nbt 0.2.1

High-performance NBT (Named Binary Tag) library with zero-copy parsing and serde support
Documentation
use std::{marker::PhantomData, ptr};

use zerocopy::byteorder;

use crate::{
    ByteOrder, ConfigMut, ConfigRef, GenericNBT, IntoNBT, ListOwn, MUTF8Str, NBT, StringOwn,
    VecOwn, TagID, ValueOwn, cold_path,
    mutable::{
        config::MutableConfig, size::mutable_tag_size, value_mut::MutValue, value_ref::RefValue,
    },
};

#[repr(transparent)]
pub struct CompoundOwn<O: ByteOrder> {
    pub(crate) data: VecOwn<u8>,
    pub(crate) _marker: PhantomData<O>,
}

impl<O: ByteOrder> Default for CompoundOwn<O> {
    fn default() -> Self {
        Self {
            data: vec![0].into(),
            _marker: PhantomData,
        }
    }
}

impl<O: ByteOrder> CompoundOwn<O> {
    #[inline]
    fn _to_read_params<'a>(&'a self) -> <MutableConfig<O> as ConfigRef>::ReadParams<'a> {
        self.data.as_ptr()
    }

    #[inline]
    fn _to_write_params<'a>(&'a mut self) -> <MutableConfig<O> as ConfigMut>::WriteParams<'a> {
        self.data.to_mut()
    }

    #[inline]
    pub fn get<'a>(&'a self, key: &str) -> Option<RefValue<'a, O>> {
        unsafe {
            let key = simd_cesu8::mutf8::encode(key);
            let key = MUTF8Str::from_mutf8_unchecked(&key);
            let (tag_id, params) = MutableConfig::<O>::compound_get(self._to_read_params(), key)?;
            Some(MutableConfig::<O>::read_value(tag_id, params))
        }
    }

    #[inline]
    pub fn get_<'a, T: GenericNBT>(
        &'a self,
        key: &str,
    ) -> Option<T::TypeRef<'a, MutableConfig<O>>> {
        unsafe {
            let key = simd_cesu8::mutf8::encode(key);
            let key = MUTF8Str::from_mutf8_unchecked(&key);
            let (tag_id, params) = MutableConfig::<O>::compound_get(self._to_read_params(), key)?;
            if tag_id != T::TAG_ID {
                cold_path();
                return None;
            }
            MutableConfig::<O>::read::<T>(params)
        }
    }

    #[inline]
    pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<MutValue<'a, O>> {
        unsafe {
            let key = simd_cesu8::mutf8::encode(key);
            let key = MUTF8Str::from_mutf8_unchecked(&key);
            let (tag_id, params) = MutableConfig::<O>::compound_get(self._to_read_params(), key)?;
            Some(MutableConfig::<O>::read_value_mut(tag_id, params))
        }
    }

    #[inline]
    pub fn get_mut_<'a, T: GenericNBT>(
        &'a mut self,
        key: &str,
    ) -> Option<T::TypeMut<'a, MutableConfig<O>>> {
        unsafe {
            let key = simd_cesu8::mutf8::encode(key);
            let key = MUTF8Str::from_mutf8_unchecked(&key);
            let (tag_id, params) = MutableConfig::<O>::compound_get(self._to_read_params(), key)?;
            if tag_id != T::TAG_ID {
                cold_path();
                return None;
            }
            MutableConfig::<O>::read_mut::<T>(params)
        }
    }

    #[inline]
    pub fn insert<T: NBT>(
        &mut self,
        key: &str,
        value: impl IntoNBT<O, Tag = T>,
    ) -> Option<ValueOwn<O>> {
        unsafe {
            let key = simd_cesu8::mutf8::encode(key);
            let key = MUTF8Str::from_mutf8_unchecked(&key);
            let old = MutableConfig::<O>::compound_remove(self._to_write_params(), key);
            MutableConfig::<O>::compound_insert::<T>(
                self._to_write_params(),
                key,
                value.into_nbt(),
            );
            old
        }
    }

    #[inline]
    pub fn remove(&mut self, key: &str) -> Option<ValueOwn<O>> {
        unsafe {
            let key = simd_cesu8::mutf8::encode(key);
            let key = MUTF8Str::from_mutf8_unchecked(&key);
            MutableConfig::<O>::compound_remove(self._to_write_params(), key)
        }
    }
}

impl<O: ByteOrder> Drop for CompoundOwn<O> {
    fn drop(&mut self) {
        unsafe {
            let mut ptr = self.data.as_mut_ptr();

            loop {
                let tag_id = *ptr.cast();
                ptr = ptr.add(1);

                if tag_id == TagID::End {
                    cold_path();
                    debug_assert!(
                        ptr.byte_offset_from_unsigned(self.data.as_mut_ptr()) == self.data.len()
                    );
                    return;
                }

                let name_len = byteorder::U16::<O>::from_bytes(*ptr.cast()).get();
                ptr = ptr.add(2);

                ptr = ptr.add(name_len as usize);

                match tag_id {
                    TagID::ByteArray => {
                        ptr::read(ptr.cast::<VecOwn<i8>>());
                    }
                    TagID::String => {
                        ptr::read(ptr.cast::<StringOwn>());
                    }
                    TagID::List => {
                        ptr::read(ptr.cast::<ListOwn<O>>());
                    }
                    TagID::Compound => {
                        ptr::read(ptr.cast::<CompoundOwn<O>>());
                    }
                    TagID::IntArray => {
                        ptr::read(ptr.cast::<VecOwn<byteorder::I32<O>>>());
                    }
                    TagID::LongArray => {
                        ptr::read(ptr.cast::<VecOwn<byteorder::I64<O>>>());
                    }
                    _ => (),
                }

                ptr = ptr.add(mutable_tag_size(tag_id));
            }
        }
    }
}