mmd 0.0.6

Miku Miku Dance format parser for rust programming language
use crate::{
  reader::{helpers::ReadHelpers, SurfaceReader},
  DefaultConfig, Result, Settings,
};
use byteorder::{ReadBytesExt, LE};
use std::io::Read;

pub struct TextureReader<R> {
  pub settings: Settings,
  pub count: i32,
  pub remaining: i32,
  pub(crate) read: R,
  pub(crate) poison: bool,
}

impl<R: Read> TextureReader<R> {
  pub fn new(mut s: SurfaceReader<R>) -> Result<TextureReader<R>> {
    assert!(!s.poison);
    while s.remaining > 0 {
      s.next::<DefaultConfig>()?;
    }
    let count = s.read.read_i32::<LE>()?;

    Ok(TextureReader {
      settings: s.settings,
      count,
      remaining: count,
      read: s.read,
      poison: false,
    })
  }

  pub fn next(&mut self) -> Result<Option<String>> {
    assert!(!self.poison);
    let result = self.next_impl();
    if result.is_err() {
      self.poison = true;
    }
    result
  }

  fn next_impl(&mut self) -> Result<Option<String>> {
    if self.remaining <= 0 {
      return Ok(None);
    }

    self.remaining -= 1;

    self.read.read_text(self.settings.text_encoding).map(Some)
  }

  pub fn iter(&mut self) -> TextureIterator<R> {
    TextureIterator { reader: self }
  }
}

pub struct TextureIterator<'a, R> {
  reader: &'a mut TextureReader<R>,
}

impl<R: Read> Iterator for TextureIterator<'_, R> {
  type Item = Result<String>;

  fn next(&mut self) -> Option<Self::Item> {
    self
      .reader
      .next()
      .map_or_else(|e| Some(Err(e)), |v| v.map(Ok))
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    (
      self.reader.remaining as usize,
      Some(self.reader.remaining as usize),
    )
  }
}

impl<R: Read> ExactSizeIterator for TextureIterator<'_, R> {
  fn len(&self) -> usize {
    self.reader.remaining as usize
  }
}