msla_format 0.2.0

Library for encoding and decoding various MSLA file formats: Elegoo (.goo), Chitu Encrypted (.ctb), NanoDLP (.nanodlp).
Documentation
use anyhow::Result;
use nalgebra::Vector4;

use crate::serde::{Deserializer, Serializer, SliceDeserializer};

use crate::ctb::{Section, read_string};

/// Describes the resin used for this job.
#[derive(Debug)]
pub struct ResinParameters {
    pub resin_color: Vector4<u8>,
    pub machine_name: String,
    pub resin_type: String,
    pub resin_name: String,
    pub resin_density: f32,
}

impl ResinParameters {
    pub fn deserialize(des: &mut SliceDeserializer) -> Result<Self> {
        des.advance_by(4);

        let color_b = des.read_u8();
        let color_g = des.read_u8();
        let color_r = des.read_u8();
        let color_a = des.read_u8();

        let machine_name_address = des.read_u32_le();
        let resin_type = Section::deserialize_rev(des)?;
        let resin_name = Section::deserialize_rev(des)?;
        let machine_name = Section {
            size: des.read_u32_le(),
            offset: machine_name_address,
        };
        let resin_density = des.read_f32_le();

        Ok(Self {
            resin_color: Vector4::new(color_r, color_g, color_b, color_a),
            machine_name: read_string(des, machine_name),
            resin_type: read_string(des, resin_type),
            resin_name: read_string(des, resin_name),
            resin_density,
        })
    }

    pub fn serialize<T: Serializer>(&self, ser: &mut T) {
        ser.write_u32_be(0);
        ser.write_u8(self.resin_color.z);
        ser.write_u8(self.resin_color.y);
        ser.write_u8(self.resin_color.x);
        ser.write_u8(self.resin_color.w);
        let machine_name_address = ser.reserve(4);
        let resin_type = ser.reserve(8);
        let resin_name = ser.reserve(8);
        let machine_name_size = ser.reserve(4);
        ser.write_f32_le(self.resin_density);
        ser.write_u32_le(0);

        let machine_name_bytes = self.machine_name.as_bytes();
        let machine_name_offset = ser.pos();
        ser.write_bytes(machine_name_bytes);
        ser.execute_at(machine_name_address, |ser| {
            ser.write_u32_le(machine_name_offset as u32);
        });
        ser.execute_at(machine_name_size, |ser| {
            ser.write_u32_le(machine_name_bytes.len() as u32)
        });

        serialize_string(ser, resin_type, &self.resin_type);
        serialize_string(ser, resin_name, &self.resin_name);
    }
}

fn serialize_string<T: Serializer>(ser: &mut T, offset: usize, string: &str) {
    let string_bytes = string.as_bytes();
    let string_offset = ser.pos();
    ser.write_bytes(string_bytes);
    ser.execute_at(offset, |ser| {
        Section::new(string_offset, string_bytes.len()).serialize_rev(ser);
    });
}