cpp_rs 0.1.0

[Not currently ready] A C Preprocessor library and associated binary.
Documentation
use super::char_source::CharSource;
use log::trace;
use std::borrow::Cow;
use std::collections::VecDeque;

#[derive(Debug)]
pub struct PeekAdapter<S> {
    source: S,

    peek_index: usize,
    peek_buffer: VecDeque<(usize, char)>,

    consumed_start_byte: Option<usize>,
    consumed_end_byte: usize,
    consumed: String,
}

impl<'s, S: CharSource<'s>> PeekAdapter<S> {
    pub fn new(source: S) -> PeekAdapter<S> {
        PeekAdapter {
            source,

            peek_index: 0,
            peek_buffer: VecDeque::new(),

            consumed_start_byte: None,
            consumed_end_byte: 0,
            consumed: String::new(),
        }
    }

    pub fn get_len(&self) -> usize {
        self.source.get_len()
    }

    pub fn peek(&mut self) -> Option<(usize, char)> {
        match self.inner_peek() {
            Some(x @ (_, '\\')) => match self.inner_peek() {
                Some((_, '\n')) => self.peek(),
                Some((_, _)) => {
                    self.return_peek();
                    Some(x)
                }
                None => Some(x),
            },

            out @ Some(_) | out @ None => out,
        }
    }

    pub fn return_peek(&mut self) {
        assert!(self.peek_index > 0);
        self.peek_index -= 1;
    }

    pub fn reset_peek(&mut self) {
        self.peek_index = 0;
    }

    pub fn consume(&mut self) -> Result<(), ()> {
        match self.inner_consume()? {
            (b, c @ '\\') => match self.inner_peek() {
                Some((_, '\n')) => {
                    trace!("Consume: Skipping escaped newline ({})", b);
                    self.inner_consume()?;
                    self.consume()
                }

                Some((_, _)) => {
                    self.reset_peek();
                    self.consumed_start_byte.get_or_insert(b);
                    self.consumed_end_byte = b + c.len_utf8() - 1;
                    self.consumed.push(c);
                    trace!(
                        "Consumed: {:?} ({}, {})",
                        c,
                        self.consumed_start_byte.unwrap_or(0),
                        self.consumed_end_byte
                    );
                    Ok(())
                }

                None => {
                    self.reset_peek();
                    self.consumed_start_byte.get_or_insert(b);
                    self.consumed_end_byte = b + c.len_utf8() - 1;
                    self.consumed.push(c);
                    trace!(
                        "Consumed: {:?} ({}, {})",
                        c,
                        self.consumed_start_byte.unwrap_or(0),
                        self.consumed_end_byte
                    );
                    Ok(())
                }
            },

            (b, c) => {
                trace!("{:?} {}", self.consumed_start_byte, b);
                self.consumed_start_byte.get_or_insert(b);
                self.consumed_end_byte = b + c.len_utf8() - 1;
                self.consumed.push(c);
                trace!(
                    "Consumed: {:?} ({}, {})",
                    c,
                    self.consumed_start_byte.unwrap_or(0),
                    self.consumed_end_byte
                );
                Ok(())
            }
        }
    }

    fn inner_consume(&mut self) -> Result<(usize, char), ()> {
        self.reset_peek();

        self.peek_buffer
            .pop_front()
            .or_else(|| self.source.next())
            .map_or_else(|| Err(()), Ok)
    }

    pub fn get_consumed_range(&self) -> (usize, usize) {
        (
            self.consumed_start_byte.unwrap_or(0),
            self.consumed_end_byte,
        )
    }

    pub fn get_consumed(&mut self) -> Cow<'s, str> {
        let consume_len = self.consumed_end_byte - self.consumed_start_byte.unwrap_or(0) + 1;

        let out = if dbg!(self.consumed.len()) == dbg!(consume_len) {
            self.source
                .get_slice(self.consumed_start_byte.unwrap_or(0)..=self.consumed_end_byte)
        } else {
            Cow::Owned(self.consumed.clone())
        };

        self.consumed_start_byte = None;
        self.consumed_end_byte += 1;
        self.consumed.truncate(0);

        out
    }

    fn inner_peek(&mut self) -> Option<(usize, char)> {
        let out = if self.peek_index < self.peek_buffer.len() {
            Some(self.peek_buffer[self.peek_index])
        } else {
            match self.source.next() {
                Some(x) => {
                    self.peek_buffer.push_back(x);
                    Some(self.peek_buffer[self.peek_index])
                }

                None => return None,
            }
        };

        self.peek_index += 1;
        out
    }
}