use std::{io, ops::Range};
use ltk_hash::BinHash;
use crate::{
stream::{BinStream, ObjectEntry, ObjectView},
BinObject, Error,
};
#[must_use = "cursors are lazy and read nothing until advanced"]
#[derive(Debug)]
pub struct Objects<'a, R: io::Read + io::Seek> {
stream: &'a mut BinStream<R>,
index: usize,
}
impl<'a, R: io::Read + io::Seek> Objects<'a, R> {
pub(crate) fn new(stream: &'a mut BinStream<R>) -> Self {
Self { stream, index: 0 }
}
#[expect(
clippy::should_implement_trait,
reason = "a lending cursor: the yielded item borrows the reader, which `Iterator` cannot express"
)]
pub fn next(&mut self) -> Result<Option<ObjectStream<'_, R>>, Error> {
if self.index == self.stream.class_hashes().len() {
return Ok(None);
}
let entry = match self.stream.toc_row(self.index) {
Some(&entry) => entry,
None => match self.stream.harvest(self.index) {
Ok(entry) => entry,
Err(error) => {
self.index = self.stream.class_hashes().len();
return Err(error);
}
},
};
self.index += 1;
Ok(Some(ObjectStream::new(self.stream, entry)))
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct Entries<'a, R: io::Read + io::Seek> {
objects: Objects<'a, R>,
}
impl<'a, R: io::Read + io::Seek> Entries<'a, R> {
pub(crate) fn new(stream: &'a mut BinStream<R>) -> Self {
Self {
objects: Objects::new(stream),
}
}
}
impl<R: io::Read + io::Seek> Iterator for Entries<'_, R> {
type Item = Result<ObjectEntry, Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.objects.next() {
Ok(Some(object)) => Some(Ok(object.entry())),
Ok(None) => None,
Err(error) => Some(Err(error)),
}
}
}
#[derive(Debug)]
pub struct ObjectStream<'a, R: io::Read + io::Seek> {
stream: &'a mut BinStream<R>,
entry: ObjectEntry,
property_count: Option<u16>,
}
impl<'a, R: io::Read + io::Seek> ObjectStream<'a, R> {
pub(crate) fn new(stream: &'a mut BinStream<R>, entry: ObjectEntry) -> Self {
Self {
stream,
entry,
property_count: None,
}
}
#[must_use]
pub fn path_hash(&self) -> BinHash {
self.entry.path_hash
}
#[must_use]
pub fn class_hash(&self) -> BinHash {
self.entry.class_hash
}
#[must_use]
pub fn entry(&self) -> ObjectEntry {
self.entry
}
#[must_use]
pub fn byte_range(&self) -> Range<u64> {
self.entry.byte_range()
}
pub fn property_count(&mut self) -> Result<u16, Error> {
if let Some(count) = self.property_count {
return Ok(count);
}
let count = self.stream.read_property_count(self.entry.offset + 8)?;
self.property_count = Some(count);
Ok(count)
}
pub fn view(&mut self) -> Result<ObjectView<'_>, Error> {
let entry = self.entry;
ObjectView::new(entry, self.stream.view_object(entry)?)
}
pub fn read(&mut self) -> Result<BinObject, Error> {
self.stream.read_object(self.entry)
}
}