rsonpath-lib 0.2.1

Blazing fast JSONPath query engine powered by SIMD. Core library of `rsonpath`.
Documentation
use super::*;
use crate::debug;
use crate::quotes::{QuoteClassifiedBlock, ResumeClassifierBlockState};
use std::marker::PhantomData;

pub(crate) struct VectorIterator<'a, I: QuoteClassifiedIterator<'a>> {
    iter: I,
    opening: u8,
    phantom: PhantomData<&'a I>,
}

impl<'a, I: QuoteClassifiedIterator<'a>> VectorIterator<'a, I> {
    pub(crate) fn new(iter: I, opening: u8) -> Self {
        Self {
            iter,
            opening,
            phantom: PhantomData,
        }
    }
}

impl<'a, I: QuoteClassifiedIterator<'a>> Iterator for VectorIterator<'a, I> {
    type Item = Vector<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        let quote_classified = self.iter.next();
        quote_classified.map(|b| Vector::new(b, self.opening))
    }
}

impl<'a, I: QuoteClassifiedIterator<'a>> DepthIterator<'a, I> for VectorIterator<'a, I> {
    type Block = Vector<'a>;

    fn stop(self, block: Option<Self::Block>) -> ResumeClassifierState<'a, I> {
        let block_state = block.and_then(|b| {
            debug!("Depth iterator stopping at index {}", b.idx);
            if b.idx >= b.quote_classified.len() {
                None
            } else {
                Some(ResumeClassifierBlockState {
                    block: b.quote_classified,
                    idx: b.idx,
                })
            }
        });

        ResumeClassifierState {
            iter: self.iter,
            block: block_state,
        }
    }

    fn resume(state: ResumeClassifierState<'a, I>, opening: u8) -> (Option<Self::Block>, Self) {
        let first_block = state
            .block
            .map(|b| Vector::new_from(b.block, opening, b.idx));

        (
            first_block,
            VectorIterator {
                iter: state.iter,
                opening,
                phantom: PhantomData,
            },
        )
    }
}

pub(crate) struct Vector<'a> {
    quote_classified: QuoteClassifiedBlock<'a>,
    depth: isize,
    idx: usize,
    opening: u8,
}

impl<'a> Vector<'a> {
    #[inline]
    pub(crate) fn new(bytes: QuoteClassifiedBlock<'a>, opening: u8) -> Self {
        Self::new_from(bytes, opening, 0)
    }

    #[inline]
    fn new_from(bytes: QuoteClassifiedBlock<'a>, opening: u8, idx: usize) -> Self {
        Self {
            quote_classified: bytes,
            depth: 0,
            idx,
            opening,
        }
    }

    #[inline]
    fn map_depths<F: FnMut(isize)>(&self, mut f: F) {
        let mut current = self.depth;
        f(current);
        let mut offset = 0;

        while self.idx + offset < self.quote_classified.len() {
            if let Some(character) = self.get_char(self.idx + offset) {
                current += match character {
                    b'{' | b'[' => 1,
                    b'}' | b']' => -1,
                    _ => 0,
                };
            }

            f(current);
            offset += 1;
        }
    }

    #[inline(always)]
    fn get_char(&self, idx: usize) -> Option<u8> {
        let idx_mask = 1_u64 << idx;
        let is_quoted = (self.quote_classified.within_quotes_mask & idx_mask) == idx_mask;

        if is_quoted {
            None
        } else {
            let character = self.quote_classified.block[idx];
            Some(character)
        }
    }
}

impl<'a> DepthBlock<'a> for Vector<'a> {
    #[inline]
    fn get_depth(&self) -> isize {
        self.depth
    }

    #[inline]
    fn depth_at_end(&self) -> isize {
        let mut current = 0;
        self.map_depths(|x| current = x);

        current
    }

    #[inline]
    fn advance_to_next_depth_decrease(&mut self) -> bool {
        let closing = self.opening + 2;
        while self.idx < self.quote_classified.len() {
            let character = self.get_char(self.idx);
            self.idx += 1;

            if character == Some(self.opening) {
                self.depth += 1;
            } else if character == Some(closing) {
                self.depth -= 1;
                return true;
            }
        }

        false
    }

    #[inline]
    fn add_depth(&mut self, depth: isize) {
        self.depth += depth;
    }

    fn estimate_lowest_possible_depth(&self) -> isize {
        let mut lowest = 0;
        self.map_depths(|x| lowest = std::cmp::min(lowest, x));

        lowest
    }
}