#[cfg(test)]
mod tests;
#[cfg(feature = "alloc")]
pub use self::factory::{store, Builder};
#[cfg(feature = "alloc")]
mod factory;
use self::walk::Walk;
mod walk;
use core::fmt;
use core::marker::PhantomData;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crate::endian::Native;
use crate::lossy_str::LossyStr;
use crate::slice::{binary_search_by, BinarySearch, Slice};
use crate::stack::ArrayStack;
use crate::{Buf, ByteOrder, DefaultSize, Error, Ref, Size, ZeroCopy};
type StackEntry<'buf, T, F> = (LinksRef<T, F>, usize, &'buf [u8]);
pub trait Flavor {
type String: Slice<Item = u8>;
type Values<T>: Slice<Item = T>
where
T: ZeroCopy;
type Children<T>: Slice<Item = T>
where
T: ZeroCopy;
}
pub struct DefaultFlavor<E = Native, O = DefaultSize>(PhantomData<(E, O)>)
where
E: ByteOrder,
O: Size;
impl<E, O> Flavor for DefaultFlavor<E, O>
where
E: ByteOrder,
O: Size,
{
type String = Ref<[u8], E, O>;
type Values<T> = Ref<[T], E, O> where T: ZeroCopy;
type Children<T> = Ref<[T], E, O> where T: ZeroCopy;
}
#[derive(ZeroCopy)]
#[zero_copy(crate)]
#[repr(C)]
pub struct TrieRef<T, F = DefaultFlavor>
where
T: ZeroCopy,
F: Flavor,
{
links: LinksRef<T, F>,
}
impl<T, F> TrieRef<T, F>
where
T: ZeroCopy,
F: Flavor,
{
#[cfg(feature = "alloc")]
pub fn debug<'a, 'buf>(&'a self, buf: &'buf Buf) -> Debug<'a, 'buf, T, F>
where
T: fmt::Debug,
{
Debug { trie: self, buf }
}
pub fn debug_fixed<'a, 'buf, const N: usize>(
&'a self,
buf: &'buf Buf,
) -> DebugFixed<'a, 'buf, N, T, F>
where
T: fmt::Debug,
{
DebugFixed { trie: self, buf }
}
pub fn get<'buf, S>(&self, buf: &'buf Buf, string: &S) -> Result<Option<&'buf [T]>, Error>
where
S: ?Sized + AsRef<[u8]>,
{
let mut this = self.links;
let mut string = string.as_ref();
loop {
let search =
binary_search_by(buf, this.children, |c| Ok(buf.load(c.string)?.cmp(string)))?;
match search {
BinarySearch::Found(n) => {
let child = this.children.get_unchecked(n);
let child = buf.load(child)?;
let values = buf.load(child.links.values)?;
return Ok(Some(values));
}
BinarySearch::Missing(0) => {
return Ok(None);
}
BinarySearch::Missing(n) => {
let child = this.children.get_unchecked(n - 1);
let child = buf.load(child)?;
let prefix = prefix(buf.load(child.string)?, string);
if prefix == 0 {
return Ok(None);
}
string = &string[prefix..];
this = child.links;
}
};
}
}
#[cfg(feature = "alloc")]
pub fn values<'buf>(&self, buf: &'buf Buf) -> Values<'buf, T, F> {
Values {
iter: Walk::find(buf, self.links, &[]),
}
}
pub fn values_fixed<'buf, const N: usize>(&self, buf: &'buf Buf) -> ValuesFixed<'buf, N, T, F> {
ValuesFixed {
iter: Walk::find(buf, self.links, &[]),
}
}
#[cfg(feature = "alloc")]
pub fn values_in<'a, 'buf, S>(&self, buf: &'buf Buf, prefix: &'a S) -> ValuesIn<'a, 'buf, T, F>
where
S: ?Sized + AsRef<[u8]>,
{
ValuesIn {
iter: Walk::find(buf, self.links, prefix.as_ref()),
}
}
pub fn values_in_fixed<'a, 'buf, const N: usize, S>(
&self,
buf: &'buf Buf,
prefix: &'a S,
) -> ValuesInFixed<'a, 'buf, N, T, F>
where
S: ?Sized + AsRef<[u8]>,
{
ValuesInFixed {
iter: Walk::find(buf, self.links, prefix.as_ref()),
}
}
#[cfg(feature = "alloc")]
pub fn iter<'buf>(&self, buf: &'buf Buf) -> Iter<'buf, T, F> {
Iter {
iter: Walk::find(buf, self.links, &[]),
}
}
pub fn iter_fixed<'buf, const N: usize>(&self, buf: &'buf Buf) -> IterFixed<'buf, N, T, F> {
IterFixed {
iter: Walk::find(buf, self.links, &[]),
}
}
#[cfg(feature = "alloc")]
pub fn iter_in<'a, 'buf, S>(&self, buf: &'buf Buf, prefix: &'a S) -> IterIn<'a, 'buf, T, F>
where
S: ?Sized + AsRef<[u8]>,
{
IterIn {
iter: Walk::find(buf, self.links, prefix.as_ref()),
}
}
pub fn iter_in_fixed<'a, 'buf, const N: usize, S>(
&self,
buf: &'buf Buf,
prefix: &'a S,
) -> IterInFixed<'a, 'buf, N, T, F>
where
S: ?Sized + AsRef<[u8]>,
{
IterInFixed {
iter: Walk::find(buf, self.links, prefix.as_ref()),
}
}
}
#[cfg(feature = "alloc")]
pub struct ValuesIn<'a, 'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'a, 'buf, T, F, Vec<StackEntry<'buf, T, F>>>,
}
#[cfg(feature = "alloc")]
impl<'a, 'buf, T, F> Iterator for ValuesIn<'a, 'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<&'buf T, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (_, value) = match self.iter.poll() {
Ok(entry) => entry?,
Err(error) => return Some(Err(error)),
};
Some(Ok(value))
}
}
pub struct ValuesInFixed<'a, 'buf, const N: usize, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'a, 'buf, T, F, ArrayStack<StackEntry<'buf, T, F>, N>>,
}
impl<'a, 'buf, const N: usize, T, F> Iterator for ValuesInFixed<'a, 'buf, N, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<&'buf T, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (_, value) = match self.iter.poll() {
Ok(entry) => entry?,
Err(error) => return Some(Err(error)),
};
Some(Ok(value))
}
}
#[cfg(feature = "alloc")]
pub struct Values<'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'static, 'buf, T, F, Vec<StackEntry<'buf, T, F>>>,
}
#[cfg(feature = "alloc")]
impl<'buf, T, F> Iterator for Values<'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<&'buf T, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (_, value) = match self.iter.poll() {
Ok(entry) => entry?,
Err(error) => return Some(Err(error)),
};
Some(Ok(value))
}
}
pub struct ValuesFixed<'buf, const N: usize, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'static, 'buf, T, F, ArrayStack<StackEntry<'buf, T, F>, N>>,
}
impl<'buf, const N: usize, T, F> Iterator for ValuesFixed<'buf, N, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<&'buf T, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (_, value) = match self.iter.poll() {
Ok(entry) => entry?,
Err(error) => return Some(Err(error)),
};
Some(Ok(value))
}
}
#[cfg(feature = "alloc")]
pub struct Iter<'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'static, 'buf, T, F, Vec<StackEntry<'buf, T, F>>>,
}
#[cfg(feature = "alloc")]
impl<'buf, T, F> Iterator for Iter<'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<(&'buf [u8], &'buf T), Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.poll().transpose()
}
}
pub struct IterFixed<'buf, const N: usize, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'static, 'buf, T, F, ArrayStack<StackEntry<'buf, T, F>, N>>,
}
impl<'buf, const N: usize, T, F> Iterator for IterFixed<'buf, N, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<(&'buf [u8], &'buf T), Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.poll().transpose()
}
}
#[cfg(feature = "alloc")]
pub struct IterIn<'a, 'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'a, 'buf, T, F, Vec<StackEntry<'buf, T, F>>>,
}
#[cfg(feature = "alloc")]
impl<'a, 'buf, T, F> Iterator for IterIn<'a, 'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<(&'buf [u8], &'buf T), Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.poll().transpose()
}
}
pub struct IterInFixed<'a, 'buf, const N: usize, T, F>
where
T: ZeroCopy,
F: Flavor,
{
iter: Walk<'a, 'buf, T, F, ArrayStack<StackEntry<'buf, T, F>, N>>,
}
impl<'a, 'buf, const N: usize, T, F> Iterator for IterInFixed<'a, 'buf, N, T, F>
where
T: ZeroCopy,
F: Flavor,
{
type Item = Result<(&'buf [u8], &'buf T), Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.poll().transpose()
}
}
#[cfg(feature = "alloc")]
pub struct Debug<'a, 'buf, T, F>
where
T: ZeroCopy,
F: Flavor,
{
trie: &'a TrieRef<T, F>,
buf: &'buf Buf,
}
#[cfg(feature = "alloc")]
impl<'a, 'buf, T, F> fmt::Debug for Debug<'a, 'buf, T, F>
where
T: fmt::Debug + ZeroCopy,
F: Flavor,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_map();
for result in self.trie.iter(self.buf) {
let (key, value) = result.map_err(|_| fmt::Error)?;
f.entry(&LossyStr::new(key), value);
}
f.finish()
}
}
pub struct DebugFixed<'a, 'buf, const N: usize, T, F>
where
T: ZeroCopy,
F: Flavor,
{
trie: &'a TrieRef<T, F>,
buf: &'buf Buf,
}
impl<'a, 'buf, const N: usize, T, F> fmt::Debug for DebugFixed<'a, 'buf, N, T, F>
where
T: fmt::Debug + ZeroCopy,
F: Flavor,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_map();
for result in self.trie.iter_fixed::<N>(self.buf) {
let (key, value) = result.map_err(|_| fmt::Error)?;
f.entry(&LossyStr::new(key), value);
}
f.finish()
}
}
impl<T, F> Clone for TrieRef<T, F>
where
T: ZeroCopy,
F: Flavor,
F::Values<T>: Clone,
F::Children<NodeRef<T, F>>: Clone,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T, F> Copy for TrieRef<T, F>
where
T: ZeroCopy,
F: Flavor,
F::Values<T>: Copy,
F::Children<NodeRef<T, F>>: Copy,
{
}
#[derive(ZeroCopy)]
#[zero_copy(crate)]
#[repr(C)]
struct LinksRef<T, F>
where
T: ZeroCopy,
F: Flavor,
{
values: F::Values<T>,
children: F::Children<NodeRef<T, F>>,
}
impl<T, F> Clone for LinksRef<T, F>
where
T: ZeroCopy,
F: Flavor,
F::Values<T>: Copy,
F::Children<NodeRef<T, F>>: Copy,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T, F> Copy for LinksRef<T, F>
where
T: ZeroCopy,
F: Flavor,
F::Values<T>: Copy,
F::Children<NodeRef<T, F>>: Copy,
{
}
#[derive(ZeroCopy)]
#[zero_copy(crate)]
#[repr(C)]
struct NodeRef<T, F>
where
T: ZeroCopy,
F: Flavor,
{
string: F::String,
links: LinksRef<T, F>,
}
fn prefix(a: &[u8], b: &[u8]) -> usize {
a.iter().zip(b.iter()).take_while(|(a, b)| a == b).count()
}