use crate::prelude::*;
use crate::util::fmt::typename;
use crate::util::init::vec_with_capacity;
use crate::wad::elem::GMElement;
use crate::wad::parse::reader::DataReader;
impl DataReader<'_> {
pub fn read_simple_list<T: GMElement>(&mut self) -> Result<Vec<T>> {
let count = self.read_u32()?;
let mut elements: Vec<T> = vec_with_capacity(count)
.ctx(|| format!("reading simple list of {}", typename::<T>()))?;
for _ in 0..count {
let element = T::deserialize(self).ctx(|| {
format!(
"deserializing element {}/{} of {} simple list",
elements.len(),
count,
typename::<T>(),
)
})?;
elements.push(element);
}
Ok(elements)
}
pub fn read_simple_list_short<T: GMElement>(&mut self) -> Result<Vec<T>> {
let count = u32::from(self.read_u16()?);
let mut elements: Vec<T> = vec_with_capacity(count)
.ctx(|| format!("reading short simple list of {}", typename::<T>()))?;
for _ in 0..count {
let element = T::deserialize(self).ctx(|| {
format!(
"deserializing element {}/{} of {} short simple list",
elements.len(),
count,
typename::<T>(),
)
})?;
elements.push(element);
}
Ok(elements)
}
pub fn read_pointer_list<T: GMElement>(&mut self) -> Result<Vec<T>> {
let pointers: Vec<u32> = self.read_simple_list()?;
let count = pointers.len();
let mut elements: Vec<T> = Vec::with_capacity(count);
for (i, pointer) in pointers.into_iter().enumerate() {
let element_opt: Option<T> =
self.read_pointer_element(pointer, i == count - 1).ctx(|| {
format!(
"deserializing element {}/{} of {} pointer list",
i,
count,
typename::<T>(),
)
})?;
let Some(element) = element_opt else {
bail!(
"Element {}/{} of {} pointer list is null",
i,
count,
typename::<T>(),
)
};
elements.push(element);
}
Ok(elements)
}
pub fn read_pointer_list_opt<T: GMElement>(&mut self) -> Result<Vec<Option<T>>> {
let pointers: Vec<u32> = self.read_simple_list()?;
let count = pointers.len();
let mut elements: Vec<Option<T>> = Vec::with_capacity(count);
for (i, pointer) in pointers.into_iter().enumerate() {
let element_opt: Option<T> =
self.read_pointer_element(pointer, i == count - 1).ctx(|| {
format!(
"deserializing element {}/{} of nullable {} pointer list",
i,
count,
typename::<T>(),
)
})?;
elements.push(element_opt);
}
Ok(elements)
}
fn read_pointer_element<T: GMElement>(
&mut self,
pointer: u32,
is_last: bool,
) -> Result<Option<T>> {
T::deserialize_pre_padding(self).ctx("reading pre-padding")?;
if self.cur_pos != pointer {
let name = typename::<T>();
let pos = i64::from(self.cur_pos);
if pointer == 0 {
return Ok(None);
}
let diff = i64::from(pointer) - pos;
self.handle_invalid_align(format!(
"{name} pointer is misaligned: expected position {pointer} but reader is actually \
at {pos} (diff: {diff})",
))?;
}
let element = T::deserialize(self)?;
T::deserialize_post_padding(self, is_last).ctx("reading post-padding")?;
Ok(Some(element))
}
}