perl-dap 0.15.0

Debug Adapter Protocol server for Perl
use crate::types::Variable;
use std::collections::HashMap;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum VariableCacheKind {
    Root,
    Child,
}

#[derive(Debug, Clone)]
struct VariableCacheEntry {
    kind: VariableCacheKind,
    full: Vec<Variable>,
    page_slices: HashMap<(usize, usize), Vec<Variable>>,
}

#[derive(Debug, Default)]
pub(super) struct VariableCache {
    entries: HashMap<i32, VariableCacheEntry>,
}

impl VariableCache {
    pub(super) fn clear(&mut self) {
        self.entries.clear();
    }

    pub(super) fn upsert(
        &mut self,
        reference: i32,
        kind: VariableCacheKind,
        variables: Vec<Variable>,
    ) {
        let _ = self.entries.insert(
            reference,
            VariableCacheEntry { kind, full: variables, page_slices: HashMap::new() },
        );
    }

    pub(super) fn get_page(
        &mut self,
        reference: i32,
        start: usize,
        count: usize,
    ) -> Option<Vec<Variable>> {
        let entry = self.entries.get_mut(&reference)?;
        let key = (start, count);
        if let Some(cached) = entry.page_slices.get(&key) {
            return Some(cached.clone());
        }

        let page = slice_variables(&entry.full, start, count);
        let _ = entry.page_slices.insert(key, page.clone());
        Some(page)
    }

    pub(super) fn all_variables(&self) -> impl Iterator<Item = &Variable> {
        self.entries
            .values()
            .filter(|entry| entry.kind == VariableCacheKind::Root)
            .chain(self.entries.values().filter(|entry| entry.kind == VariableCacheKind::Child))
            .flat_map(|entry| entry.full.iter())
    }
}

pub(super) fn slice_variables(variables: &[Variable], start: usize, count: usize) -> Vec<Variable> {
    variables.iter().skip(start).take(count).cloned().collect()
}