wow-alchemy-data 0.2.0

Base data types used in parsing WoW binary formats.
Documentation
use crate::types::MagicStr;

#[macro_export]
macro_rules! wow_collection {
    ($reader:ident, $header:expr, |$local_reader:ident, $item_header:ident| $constructor:expr) => {{
        let mut iter = $header.new_iterator($local_reader)?;
        let mut vec = Vec::with_capacity($header.count as usize);
        loop {
            match iter.next(|$local_reader, temp_header| {
                let $item_header = match temp_header {
                    Some(item) => item,
                    None => $local_reader.wow_read()?,
                };
                vec.push($constructor);
                Ok(())
            }) {
                Ok(is_active) => {
                    if !is_active {
                        break;
                    }
                }
                Err(err) => return Err(err.into()),
            }
        }
        vec
    }};
}

#[macro_export]
macro_rules! v_wow_collection {
    ($reader:ident, $version:expr, $header:expr, |$local_reader:ident, $item_header:ident| $constructor:expr) => {{
        let mut iter = $header.new_iterator($local_reader, $version)?;
        let mut vec = Vec::with_capacity($header.count as usize);
        loop {
            match iter.next(|$local_reader, temp_header| {
                let $item_header = match temp_header {
                    Some(item) => item,
                    None => $local_reader.wow_read_versioned($version)?,
                };
                vec.push($constructor);
                Ok(())
            }) {
                Ok(is_active) => {
                    if !is_active {
                        break;
                    }
                }
                Err(err) => return Err(err.into()),
            }
        }
        vec
    }};
}

#[macro_export]
macro_rules! read_chunk_items {
    ($reader:ident, $chunk_header:ident, $type:ty) => {{
        let first: $type = $reader.wow_read()?;
        let item_size = first.wow_size();
        let items = $chunk_header.bytes as usize / item_size;

        let rest = $chunk_header.bytes as usize % item_size;
        if rest > 0 {
            dbg!(format!(
                "chunk items size mismatch: chunk={} item_size={}, items={}, rest={}",
                String::from_utf8_lossy(&$chunk_header.magic),
                item_size,
                items,
                rest
            ));
        }

        let mut vec = Vec::<$type>::with_capacity(items);
        vec.push(first);

        for _ in 1..items {
            vec.push($reader.wow_read()?);
        }

        $reader.seek_relative(rest as i64)?;

        vec
    }};
}

#[macro_export]
macro_rules! v_read_chunk_items {
    ($reader:ident, $version:ident, $chunk_header:ident, $type:ty) => {{
        let first: $type = $reader.wow_read_versioned($version)?;
        let item_size = first.wow_size();
        let items = $chunk_header.bytes as usize / item_size;

        let rest = $chunk_header.bytes as usize % item_size;
        if rest > 0 {
            dbg!(format!(
                "chunk items size mismatch: chunk={} item_size={}, items={}, rest={}",
                String::from_utf8_lossy(&$chunk_header.magic),
                item_size,
                items,
                rest
            ));
        }

        let mut vec = Vec::<$type>::with_capacity(items);
        vec.push(first);

        for _ in 1..items {
            vec.push($reader.wow_read_versioned($version)?);
        }

        $reader.seek_relative(rest as i64)?;

        vec
    }};
}

pub fn magic_to_string(magic: &MagicStr) -> String {
    String::from_utf8_lossy(magic).into()
}

pub fn magic_to_inverted_string(magic: &MagicStr) -> String {
    String::from_utf8_lossy(magic).chars().rev().collect()
}

pub const fn string_to_magic(bytes_vec: &str) -> MagicStr {
    if bytes_vec.len() != 4 {
        panic!("magic must have len() == 4")
    }
    let ptr = bytes_vec.as_ptr();
    unsafe { [*ptr, *(ptr.add(1)), *(ptr.add(2)), *(ptr.add(3))] }
}

pub const fn string_to_inverted_magic(bytes_vec: &str) -> MagicStr {
    let res = string_to_magic(bytes_vec);
    [res[3], res[2], res[1], res[0]]
}