rsn 0.2.0

A Rust-inspired, human-readable object notation.
Documentation
use core::iter::Peekable;
use core::ops::Range;
use core::str::CharIndices;

#[derive(Debug, Clone)]
pub struct CharIterator<'a> {
    pub source: &'a str,
    chars: Peekable<CharIndices<'a>>,
    last: Option<(usize, char)>,
    marked_start: usize,
}

impl<'a> CharIterator<'a> {
    #[inline]
    pub fn new(source: &'a str) -> Self {
        Self {
            source,
            chars: source.char_indices().peekable(),
            last: None,
            marked_start: 0,
        }
    }

    #[inline]
    pub const fn last_offset(&self) -> usize {
        if let Some((offset, _)) = self.last {
            offset
        } else {
            0
        }
    }

    #[inline]
    pub const fn current_offset(&self) -> usize {
        if let Some((offset, ch)) = self.last {
            offset + ch.len_utf8()
        } else {
            0
        }
    }

    #[inline]
    pub fn mark_start(&mut self) {
        self.marked_start = self.current_offset();
    }

    #[inline]
    pub const fn marked_range(&self) -> Range<usize> {
        self.marked_start..self.current_offset()
    }

    pub fn marked_str(&self) -> &'a str {
        &self.source[self.marked_range()]
    }

    #[inline]
    pub const fn last_char_range(&self) -> Range<usize> {
        if let Some((offset, ch)) = self.last {
            offset..(offset + ch.len_utf8())
        } else {
            0..0
        }
    }

    #[inline]
    pub fn next_char_and_index(&mut self) -> Option<(usize, char)> {
        let current = self.chars.next()?;
        self.last = Some(current);
        Some(current)
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.peek_full().map(|(_, ch)| ch)
    }

    #[inline]
    pub fn peek_full(&mut self) -> Option<(usize, char)> {
        self.chars.peek().copied()
    }
}

impl<'a> Iterator for CharIterator<'a> {
    type Item = char;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.next_char_and_index().map(|(_, ch)| ch)
    }
}