sark-core 0.11.0

the L7 layer for dope
Documentation
use std::ops::Range;

const INLINE_PATH_PARAM_CAP: usize = 2;

type PathParam = (Box<str>, Range<usize>);

#[derive(Clone)]
enum PathParamStorage {
    Inline {
        items: [Option<PathParam>; INLINE_PATH_PARAM_CAP],
        len: u8,
    },
    Heap(Vec<PathParam>),
}

#[derive(Clone)]
pub struct PathParamRanges(PathParamStorage);

impl Default for PathParamRanges {
    fn default() -> Self {
        Self::new()
    }
}

impl PathParamRanges {
    pub fn new() -> Self {
        Self(PathParamStorage::Inline {
            items: [const { None }; INLINE_PATH_PARAM_CAP],
            len: 0,
        })
    }

    pub fn with_capacity(cap: usize) -> Self {
        if cap > INLINE_PATH_PARAM_CAP {
            Self(PathParamStorage::Heap(Vec::with_capacity(cap)))
        } else {
            Self::new()
        }
    }

    pub fn push(&mut self, key: Box<str>, range: Range<usize>) {
        match &mut self.0 {
            PathParamStorage::Heap(heap) => heap.push((key, range)),
            PathParamStorage::Inline { items, len }
                if usize::from(*len) < INLINE_PATH_PARAM_CAP =>
            {
                items[usize::from(*len)] = Some((key, range));
                *len += 1;
            }
            PathParamStorage::Inline { items, len } => {
                let mut heap = Vec::with_capacity(usize::from(*len).saturating_add(1));
                for slot in items.iter_mut().take(usize::from(*len)) {
                    if let Some(item) = slot.take() {
                        heap.push(item);
                    }
                }
                heap.push((key, range));
                self.0 = PathParamStorage::Heap(heap);
            }
        }
    }

    pub fn find_last(&self, key: &str) -> Option<&Range<usize>> {
        match &self.0 {
            PathParamStorage::Heap(heap) => heap
                .iter()
                .rev()
                .find(|(k, _)| k.as_ref() == key)
                .map(|(_, r)| r),
            PathParamStorage::Inline { items, len } => items
                .iter()
                .take(usize::from(*len))
                .rev()
                .find_map(|slot| slot.as_ref().filter(|(k, _)| k.as_ref() == key))
                .map(|(_, r)| r),
        }
    }
}