msla_format 0.2.0

Library for encoding and decoding various MSLA file formats: Elegoo (.goo), Chitu Encrypted (.ctb), NanoDLP (.nanodlp).
Documentation
use std::{
    borrow::Cow,
    io::{ErrorKind, Read, Seek, SeekFrom},
    mem::{self, MaybeUninit},
    slice,
};

#[rustfmt::skip]
pub trait Deserializer {
    fn pos(&mut self) -> usize;
    fn size(&mut self) -> usize;
    fn advance_by(&mut self, amount: usize);
    fn jump_to(&mut self, pos: usize);
    fn execute_at<T>(&mut self, pos: usize, func: impl FnOnce(&mut Self) -> T) -> T;
    fn read_bytes(&mut self, length: usize) -> Cow<'_, [u8]>;
    fn is_eof(&mut self) -> bool;

    fn read_array<const LENGTH: usize>(&mut self) -> [u8; LENGTH] {
        as_array::<_, LENGTH>(&self.read_bytes(LENGTH))
            .copied()
            .unwrap_or([0; LENGTH])
    }

    fn read_bool(&mut self) -> bool { self.read_u8() != 0 }
    fn read_u8(&mut self) -> u8 { self.read_array::<1>()[0] }
    fn read_u16_be(&mut self) -> u16 { u16::from_be_bytes(self.read_array()) }
    fn read_u16_le(&mut self) -> u16 { u16::from_le_bytes(self.read_array()) }
    fn read_u32_be(&mut self) -> u32 { u32::from_be_bytes(self.read_array()) }
    fn read_u32_le(&mut self) -> u32 { u32::from_le_bytes(self.read_array()) }
    fn read_u64_be(&mut self) -> u64 { u64::from_be_bytes(self.read_array()) }
    fn read_u64_le(&mut self) -> u64 { u64::from_le_bytes(self.read_array()) }
    fn read_f32_be(&mut self) -> f32 { f32::from_be_bytes(self.read_array()) }
    fn read_f32_le(&mut self) -> f32 { f32::from_le_bytes(self.read_array()) }
    fn read_f64_be(&mut self) -> f64 { f64::from_be_bytes(self.read_array()) }
    fn read_f64_le(&mut self) -> f64 { f64::from_le_bytes(self.read_array()) }
}

pub struct SliceDeserializer<'a> {
    buffer: &'a [u8],
    offset: usize,
}

pub struct ReaderDeserializer<T: Read> {
    reader: T,
}

impl<'a> SliceDeserializer<'a> {
    pub fn new(data: &'a [u8]) -> Self {
        Self {
            buffer: data,
            offset: 0,
        }
    }

    pub fn read_slice(&mut self, length: usize) -> &'a [u8] {
        let value = &self.buffer[self.offset..self.offset + length];
        self.offset += length;
        value
    }
}

impl<T: Read> ReaderDeserializer<T> {
    pub fn new(reader: T) -> Self {
        Self { reader }
    }

    fn read_vec(&mut self, length: usize) -> Vec<u8> {
        let mut buf = Vec::<MaybeUninit<u8>>::with_capacity(length);
        let slice = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, length) };

        let mut written = 0;
        while written < length {
            match self.reader.read(&mut slice[written..]) {
                Ok(0) => break,
                Ok(n) => written += n,
                Err(e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => panic!("failed to read from reader: {}", e),
            }
        }

        unsafe {
            buf.set_len(written);
            mem::transmute(buf)
        }
    }
}

impl<'a> Deserializer for SliceDeserializer<'a> {
    fn pos(&mut self) -> usize {
        self.offset
    }

    fn size(&mut self) -> usize {
        self.buffer.len()
    }

    fn advance_by(&mut self, amount: usize) {
        self.offset += amount;
    }

    fn jump_to(&mut self, pos: usize) {
        self.offset = pos;
    }

    fn execute_at<T>(&mut self, pos: usize, func: impl FnOnce(&mut Self) -> T) -> T {
        let offset = self.offset;
        self.jump_to(pos);
        let result = func(self);
        self.offset = offset;
        result
    }

    fn read_bytes(&mut self, length: usize) -> Cow<'_, [u8]> {
        let value = &self.buffer[self.offset..self.offset + length];
        self.offset += length;
        Cow::Borrowed(value)
    }

    fn is_eof(&mut self) -> bool {
        self.offset >= self.buffer.len()
    }
}

impl<T: Read + Seek> Deserializer for ReaderDeserializer<T> {
    fn pos(&mut self) -> usize {
        self.reader.stream_position().unwrap() as usize
    }

    fn size(&mut self) -> usize {
        let pos = self.reader.stream_position().unwrap();
        let len = self.reader.seek(SeekFrom::End(0)).unwrap();
        (pos != len).then(|| self.reader.seek(SeekFrom::Start(pos)).unwrap());
        len as usize
    }

    fn advance_by(&mut self, amount: usize) {
        self.reader.seek_relative(amount as i64).unwrap();
    }

    fn jump_to(&mut self, pos: usize) {
        self.reader.seek(SeekFrom::Start(pos as u64)).unwrap();
    }

    fn execute_at<K>(&mut self, pos: usize, func: impl FnOnce(&mut Self) -> K) -> K {
        let offset = self.reader.stream_position().unwrap();
        self.jump_to(pos);
        let result = func(self);
        self.jump_to(offset as usize);
        result
    }

    fn read_bytes(&mut self, length: usize) -> Cow<'_, [u8]> {
        Cow::Owned(self.read_vec(length))
    }

    fn is_eof(&mut self) -> bool {
        self.pos() >= self.size()
    }
}

const fn as_array<T, const N: usize>(this: &[T]) -> Option<&[T; N]> {
    if this.len() == N {
        let ptr = this.as_ptr() as *const [T; N];
        Some(unsafe { &*ptr })
    } else {
        None
    }
}