yam-core 0.1.0

Pure Rust YAML reader and writer (to be added)
Documentation
#![allow(clippy::match_like_matches_macro)]

use core::ops::Range;
use alloc::vec::Vec;

use super::ErrorType;

pub struct LookAroundBytes<'a> {
    iter: &'a [u8],
    pos: usize,
    end: usize,
}

impl<'a> LookAroundBytes<'a> {
    pub(crate) fn new(iter: &'a [u8], range: Range<usize>) -> LookAroundBytes<'a> {
        let (pos, end) = (range.start, range.end);

        LookAroundBytes { iter, pos, end }
    }
}

impl<'a> Iterator for LookAroundBytes<'a> {
    type Item = (u8, u8, u8, usize);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.pos <= self.end {
            let prev = if self.pos < 1 {
                b'\0'
            } else {
                unsafe { *self.iter.get_unchecked(self.pos - 1) }
            };
            let curr = unsafe { *self.iter.get_unchecked(self.pos) };
            let next = unsafe {
                if self.pos + 1 < self.iter.len() {
                    *self.iter.get_unchecked(self.pos + 1)
                } else {
                    b'\0'
                }
            };
            let x = Some((prev, curr, next, self.pos));
            self.pos += 1;
            x
        } else {
            None
        }
    }
}

pub trait Reader<B> {
    fn eof(&self) -> bool;
    fn col(&self) -> u32;
    fn line(&self) -> u32;
    fn offset(&self) -> usize;
    fn peek_chars(&self) -> &[u8];
    fn peek_two_chars(&self) -> &[u8];
    fn peek_byte_at(&self, offset: usize) -> Option<u8>;
    #[inline]
    fn peek_byte(&self) -> Option<u8> {
        self.peek_byte_at(0)
    }
    #[inline]
    fn peek_byte_is(&self, needle: u8) -> bool {
        match self.peek_byte_at(0) {
            Some(x) if x == needle => true,
            _ => false,
        }
    }
    #[inline]
    fn peek_byte_is_off(&self, needle: u8, offset: usize) -> bool {
        match self.peek_byte_at(offset) {
            Some(x) if x == needle => true,
            _ => false,
        }
    }
    fn peek_stream_ending(&self) -> bool {
        let chars = self.peek_chars();
        (chars == b"..." || chars == b"---")
            && self.peek_byte_at(3).map_or(true, |c| {
                c == b'\t' || c == b' ' || c == b'\r' || c == b'\n' || c == b'[' || c == b'{'
            })
            && self.col() == 0
    }
    fn skip_space_tab(&mut self) -> usize;
    fn skip_space_and_tab_detect(&mut self, has_tab: &mut bool) -> usize;
    fn consume_bytes(&mut self, amount: usize) -> usize;
    fn try_read_slice_exact(&mut self, needle: &str) -> bool;
    fn get_read_line(&self) -> (usize, usize, usize);
    fn read_line(&mut self) -> (usize, usize);
    fn count_spaces(&self) -> u32;
    fn count_whitespace(&self) -> usize {
        self.count_whitespace_from(0)
    }
    fn count_whitespace_from(&self, offset: usize) -> usize;
    fn count_spaces_till(&self, indent: u32) -> usize;
    fn is_empty_newline(&self) -> bool;
    fn get_double_quote(&self) -> Option<usize>;
    fn get_double_quote_trim(&self, start_str: usize) -> Option<(usize, usize)>;
    fn get_single_quote(&self) -> Option<usize>;
    fn get_single_quote_trim(&self, start_str: usize) -> Option<(usize, usize)>;
    fn count_space_then_tab(&mut self) -> (u32, u32);
    fn consume_anchor_alias(&mut self) -> (usize, usize);
    fn read_tag(&mut self) -> (Option<ErrorType>, usize, usize, usize);
    fn read_tag_handle(&mut self) -> Result<Vec<u8>, ErrorType>;
    fn read_tag_uri(&mut self) -> Option<(usize, usize)>;
    fn read_break(&mut self) -> Option<(usize, usize)>;
    fn read_plain_one_line(
        &mut self,
        offset_start: Option<usize>,
        had_comment: &mut bool,
        in_flow_collection: bool,
    ) -> (usize, usize, usize);
}

#[inline]
pub(crate) const fn is_white_tab_or_break(chr: u8) -> bool {
    match chr {
        b' ' | b'\t' | b'\r' | b'\n' => true,
        _ => false,
    }
}

#[inline]
pub(crate) const fn is_valid_skip_char(chr: u8) -> bool {
    match chr {
        b' ' | b'\t' | b'\r' | b'\n' | b'#' => true,
        _ => false,
    }
}

#[inline]
pub(crate) const fn is_white_tab(chr: u8) -> bool {
    match chr {
        b' ' | b'\t' => true,
        _ => false,
    }
}

#[inline]
pub(crate) const fn is_plain_unsafe(chr: u8) -> bool {
    match chr {
        b'\0' | b' ' | b'\t' | b'\r' | b'\n' | b',' | b'[' | b']' | b'{' | b'}' => true,
        _ => false,
    }
}

#[inline]
pub(crate) const fn is_newline(chr: u8) -> bool {
    match chr {
        b'\r' | b'\n' => true,
        _ => false,
    }
}

#[inline]
pub(crate) const fn is_flow_indicator(chr: u8) -> bool {
    match chr {
        b',' | b'[' | b']' | b'{' | b'}' => true,
        _ => false,
    }
}

#[inline]
pub(crate) fn is_uri_char(chr: u8) -> bool {
    chr == b'!'
        || (b'#'..=b',').contains(&chr)
        || (b'-'..=b';').contains(&chr)
        || (b'?'..=b'[').contains(&chr)
        || chr == b'_'
        || chr == b']'
        || chr.is_ascii_lowercase()
}

#[inline]
pub(crate) fn is_tag_char_short(chr: u8) -> bool {
    // can't contain `!`, `,` `[`, `]` , `{` , `}`
    (b'#'..=b'+').contains(&chr)
        || (b'-'..=b';').contains(&chr)
        || (b'?'..=b'Z').contains(&chr)
        || chr == b'_'
        || chr.is_ascii_lowercase()
}


#[inline]
pub(crate) fn is_tag_char(chr: u8) -> bool {
    matches!(chr, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9')
}

#[inline]
pub(crate) fn is_valid_escape(x: u8) -> bool {
    x == b'0'
        || x == b'r'
        || x == b'n'
        || x == b'b'
        || x == b'\\'
        || x == b'/'
        || x == b'"'
        || x == b'N'
        || x == b'_'
        || x == b'L'
        || x == b'P'
}