refeff-io 0.2.0

FEFF file-format readers and writers (feff.inp, .dat/.bin handoffs, PAD encoding) for the refeff FEFF10 port
Documentation
use std::str::FromStr;

use crate::error::{IoError, Result};

#[derive(Debug, Clone, Copy)]
struct DymToken<'a> {
    line: usize,
    text: &'a str,
}

#[derive(Debug)]
pub(super) struct DymTokenCursor<'a> {
    tokens: Vec<DymToken<'a>>,
    index: usize,
}

impl<'a> DymTokenCursor<'a> {
    pub(super) fn new(text: &'a str) -> Self {
        let tokens = text
            .lines()
            .enumerate()
            .flat_map(|(line, text)| {
                text.split_whitespace().map(move |token| DymToken {
                    line: line + 1,
                    text: token,
                })
            })
            .collect();
        Self { tokens, index: 0 }
    }

    pub(super) fn parse<T>(&mut self, field: &'static str) -> Result<T>
    where
        T: FromStr,
    {
        let token = self.next_token(field)?;
        token.text.parse::<T>().map_err(|_| IoError::DymParse {
            field,
            line: token.line,
            token: token.text.to_string(),
        })
    }

    fn next_token(&mut self, field: &'static str) -> Result<DymToken<'a>> {
        let Some(token) = self.tokens.get(self.index).copied() else {
            return Err(IoError::DymMissing { field });
        };
        self.index += 1;
        Ok(token)
    }

    pub(super) fn remaining_count(&self) -> usize {
        self.tokens.len().saturating_sub(self.index)
    }
}