#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, doc(cfg_hide(doc)))]
use std::{
ops::{Bound, RangeBounds},
pin::pin,
};
use futures_util::{Stream, TryStream, TryStreamExt};
use genawaiter_try_stream::{Co, try_stream};
use object_rainbow::{
Equivalent, Fetch, Inline, InlineOutput, ListHashes, Parse, ParseInline, ParseSliceRefless,
ReflessObject, Tagged, ToOutput, Topological, Traversible, assert_impl,
object_marker::ObjectMarker,
};
use object_rainbow_array_map::ArrayMap;
use object_rainbow_point::{IntoPoint, Point};
#[cfg(feature = "serde")]
mod serde;
type TriePoint<Tr> = Point<(Tr, Vec<u8>)>;
#[derive(ToOutput, InlineOutput, Tagged, ListHashes, Topological, Parse, ParseInline, Clone)]
#[topology(recursive, inline)]
pub struct Trie<T> {
value: Option<T>,
#[tags(skip)]
#[parse(unchecked)]
#[topology(unchecked)]
children: ArrayMap<TriePoint<Self>>,
}
assert_impl!(
impl<T, E> Inline<E> for Trie<T>
where
E: 'static + Clone + Send + Sync,
Option<T>: Inline<E>,
{
}
);
impl<T> Default for Trie<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Trie<T> {
pub const fn new() -> Self {
Self {
value: None,
children: ArrayMap::new(),
}
}
}
trait TrieChildren<Tr = Self>: Sized {
fn c_get_mut(&mut self, key: u8) -> Option<&mut TriePoint<Tr>>;
fn c_get(&self, key: u8) -> Option<&TriePoint<Tr>>;
fn c_contains(&self, key: u8) -> bool;
fn c_insert(&mut self, key: u8, point: TriePoint<Tr>);
fn c_empty(&self) -> bool;
fn c_len(&self) -> usize;
fn c_remove(&mut self, key: u8) -> Option<TriePoint<Tr>>;
fn c_range<'a>(
&'a self,
min_inclusive: u8,
max_inclusive: u8,
) -> impl Iterator<Item = (u8, &'a TriePoint<Tr>)>
where
Tr: 'a;
fn c_pop_first(&mut self) -> Option<(u8, TriePoint<Tr>)>;
fn c_iter_mut<'a>(&'a mut self) -> impl Iterator<Item = (u8, &'a mut TriePoint<Tr>)>
where
Tr: 'a;
}
impl<T> TrieChildren for Trie<T> {
fn c_get_mut(&mut self, key: u8) -> Option<&mut TriePoint<Self>> {
self.children.get_mut(key)
}
fn c_get(&self, key: u8) -> Option<&TriePoint<Self>> {
self.children.get(key)
}
fn c_contains(&self, key: u8) -> bool {
self.children.contains(key)
}
fn c_insert(&mut self, key: u8, point: TriePoint<Self>) {
self.children.insert(key, point);
}
fn c_empty(&self) -> bool {
self.children.is_empty()
}
fn c_len(&self) -> usize {
self.children.len()
}
fn c_remove(&mut self, key: u8) -> Option<TriePoint<Self>> {
self.children.remove(key)
}
fn c_range<'a>(
&'a self,
min_inclusive: u8,
max_inclusive: u8,
) -> impl Iterator<Item = (u8, &'a TriePoint<Self>)>
where
Self: 'a,
{
self.children.range(min_inclusive..=max_inclusive)
}
fn c_pop_first(&mut self) -> Option<(u8, TriePoint<Self>)> {
self.children.pop_first()
}
fn c_iter_mut<'a>(&'a mut self) -> impl Iterator<Item = (u8, &'a mut TriePoint<Self>)>
where
Self: 'a,
{
self.children.iter_mut()
}
}
fn common_length(a: &[u8], b: &[u8]) -> usize {
a.iter().zip(b).take_while(|(a, b)| a == b).count()
}
impl<T: 'static + Send + Sync + Clone> Trie<T>
where
Option<T>: Traversible + InlineOutput,
{
pub async fn get(&self, key: &[u8]) -> object_rainbow::Result<Option<T>> {
let Some((first, key)) = key.split_first() else {
return Ok(self.value.clone());
};
let Some(point) = self.c_get(*first) else {
return Ok(None);
};
let (trie, prefix) = point.fetch().await?;
let Some(key) = key.strip_prefix(prefix.as_slice()) else {
return Ok(None);
};
Box::pin(trie.get(key)).await
}
fn internal_state_check(&self) {
assert!(!self.is_empty());
assert!(self.value.is_some() || self.children.len() > 1);
}
async fn from_f<O>(
f: impl AsyncFnOnce(&mut Self) -> object_rainbow::Result<O>,
) -> object_rainbow::Result<(Self, O)> {
let mut trie = Self::default();
let o = f(&mut trie).await?;
trie.internal_state_check();
Ok((trie, o))
}
async fn update_point<O>(
point: &mut TriePoint<Self>,
key: &[u8],
f: impl AsyncFnOnce(&mut Self) -> object_rainbow::Result<O>,
) -> object_rainbow::Result<O> {
let (trie, prefix) = &mut *point.fetch_mut().await?;
let o = if let Some(key) = key.strip_prefix(prefix.as_slice()) {
Box::pin(trie.update(key, f)).await?
} else {
let (new, o) = Self::from_f(f).await?;
if let Some(suffix) = prefix.strip_prefix(key) {
let child = std::mem::replace(trie, new);
let (first, suffix) = suffix.split_first().expect("must be at least 1");
let mut overlay = Self::new();
overlay.c_insert(*first, (child, suffix.into()).point());
trie.append(&mut overlay).await?;
prefix.truncate(key.len());
} else {
let common = common_length(prefix, key);
let child = std::mem::take(trie);
let mut overlay = Self::new();
overlay.c_insert(
prefix[common],
(child, prefix[common + 1..].to_vec()).point(),
);
overlay.c_insert(key[common], (new, key[common + 1..].to_vec()).point());
trie.append(&mut overlay).await?;
prefix.truncate(common);
}
o
};
trie.internal_state_check();
Ok(o)
}
async fn update<O>(
&mut self,
key: &[u8],
f: impl AsyncFnOnce(&mut Self) -> object_rainbow::Result<O>,
) -> object_rainbow::Result<O> {
let Some((first, key)) = key.split_first() else {
return f(self).await;
};
if let Some(point) = self.c_get_mut(*first) {
Self::update_point(point, key, f).await
} else {
let (new, o) = Self::from_f(f).await?;
self.c_insert(*first, (new, key.into()).point());
Ok(o)
}
}
pub async fn insert(&mut self, key: &[u8], value: T) -> object_rainbow::Result<Option<T>> {
self.update(key, async |trie| Ok(trie.value.replace(value)))
.await
}
pub fn is_empty(&self) -> bool {
self.c_empty() && self.value.is_none()
}
pub async fn remove(&mut self, key: &[u8]) -> object_rainbow::Result<Option<T>> {
let Some((first, key)) = key.split_first() else {
return Ok(self.value.take());
};
let (item, is_empty) = {
let Some(point) = self.c_get_mut(*first) else {
return Ok(None);
};
let (trie, prefix) = &mut *point.fetch_mut().await?;
let Some(key) = key.strip_prefix(prefix.as_slice()) else {
return Ok(None);
};
let item = Box::pin(trie.remove(key)).await?;
if trie.value.is_none()
&& trie.c_len() < 2
&& let Some((first, point)) = trie.c_pop_first()
{
let (child, suffix) = point.fetch().await?;
prefix.push(first);
prefix.extend_from_slice(&suffix);
assert!(trie.is_empty());
*trie = child;
}
(item, trie.is_empty())
};
if is_empty {
self.c_remove(*first);
}
Ok(item)
}
pub async fn append(&mut self, other: &mut Self) -> object_rainbow::Result<()> {
if let Some(value) = other.value.take() {
self.value = Some(value);
}
{
let mut futures = futures_util::stream::FuturesUnordered::new();
for (key, point) in self.c_iter_mut() {
if let Some(other) = other.c_remove(key) {
futures.push(async move {
let (mut other, key) = other.fetch().await?;
Self::update_point(point, &key, async |trie| trie.append(&mut other).await)
.await
});
}
}
while futures.try_next().await?.is_some() {}
}
while let Some((key, point)) = other.c_pop_first() {
assert!(!self.c_contains(key));
self.c_insert(key, point);
}
assert!(other.c_empty());
Ok(())
}
async fn yield_all(
&self,
context: &mut Vec<u8>,
co: &Co<(Vec<u8>, T), object_rainbow::Error>,
) -> object_rainbow::Result<()> {
if let Some(value) = self.value.clone() {
co.yield_((context.clone(), value)).await;
}
let len = context.len();
for (first, point) in self.c_range(u8::MIN, u8::MAX) {
{
context.push(first);
let (trie, prefix) = point.fetch().await?;
context.extend_from_slice(&prefix);
Box::pin(trie.yield_all(context, co)).await?;
}
context.truncate(len);
}
Ok(())
}
async fn prefix_yield(
&self,
context: &mut Vec<u8>,
key: &[u8],
co: &Co<(Vec<u8>, T), object_rainbow::Error>,
) -> object_rainbow::Result<()> {
let Some((first, key)) = key.split_first() else {
self.yield_all(context, co).await?;
return Ok(());
};
let Some(point) = self.c_get(*first) else {
return Ok(());
};
let len = context.len();
'done: {
context.push(*first);
let (trie, prefix) = point.fetch().await?;
context.extend_from_slice(&prefix);
if prefix.starts_with(key) {
trie.yield_all(context, co).await?;
break 'done;
}
let Some(key) = key.strip_prefix(prefix.as_slice()) else {
break 'done;
};
Box::pin(trie.prefix_yield(context, key, co)).await?;
}
context.truncate(len);
Ok(())
}
async fn range_yield(
&self,
context: &mut Vec<u8>,
range_start: Bound<&[u8]>,
range_end: Bound<&[u8]>,
co: &Co<(Vec<u8>, T), object_rainbow::Error>,
) -> object_rainbow::Result<()> {
if (range_start, range_end).contains(b"".as_slice())
&& let Some(value) = self.value.clone()
{
co.yield_((context.clone(), value)).await;
}
let min = match range_start {
Bound::Included(x) | Bound::Excluded(x) => x.first().copied().unwrap_or(0),
Bound::Unbounded => 0,
};
let max = match range_end {
Bound::Included(x) => x.first().copied().unwrap_or(0),
Bound::Excluded(x) => {
if let Some(min) = x.first().copied() {
if x.len() == 1 {
if let Some(min) = min.checked_sub(1) {
min
} else {
return Ok(());
}
} else {
min
}
} else {
return Ok(());
}
}
Bound::Unbounded => 255,
};
let len = context.len();
for (first, point) in self.c_range(min, max) {
'done: {
context.push(first);
let (trie, prefix) = point.fetch().await?;
context.extend_from_slice(&prefix);
let extra = &context[context.len() - prefix.len() - 1..];
let start_bound = match range_start {
Bound::Included(x) => {
if x <= extra {
Bound::Unbounded
} else if let Some(suffix) = x.strip_prefix(extra) {
Bound::Included(suffix)
} else {
break 'done;
}
}
Bound::Excluded(x) => {
if x < extra {
Bound::Unbounded
} else if let Some(suffix) = x.strip_prefix(extra) {
Bound::Excluded(suffix)
} else {
break 'done;
}
}
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range_end {
Bound::Included(x) => {
if x < extra {
break 'done;
} else if let Some(suffix) = x.strip_prefix(extra) {
Bound::Included(suffix)
} else {
Bound::Unbounded
}
}
Bound::Excluded(x) => {
if x <= extra {
break 'done;
} else if let Some(suffix) = x.strip_prefix(extra) {
Bound::Excluded(suffix)
} else {
Bound::Unbounded
}
}
Bound::Unbounded => Bound::Unbounded,
};
Box::pin(trie.range_yield(context, start_bound, end_bound, co)).await?;
}
context.truncate(len);
}
Ok(())
}
pub fn prefix_stream(
&self,
prefix: &[u8],
) -> impl Send + Stream<Item = object_rainbow::Result<(Vec<u8>, T)>> {
try_stream(async |co| self.prefix_yield(&mut Vec::new(), prefix, &co).await)
}
pub fn range_stream<'a, B: AsRef<[u8]>>(
&'a self,
range: impl 'a + Send + Sync + RangeBounds<B>,
) -> impl Send + Stream<Item = object_rainbow::Result<(Vec<u8>, T)>> {
try_stream(async move |co| {
self.range_yield(
&mut Vec::new(),
range.start_bound().map(AsRef::as_ref),
range.end_bound().map(AsRef::as_ref),
&co,
)
.await
})
}
pub async fn count(&self) -> object_rainbow::Result<u64> {
self.range_stream::<&[u8]>(..)
.try_fold(0u64, async |ctr, _| Ok(ctr.saturating_add(1)))
.await
}
pub async fn from_stream<K: AsRef<[u8]>>(
stream: impl TryStream<Ok = (K, T), Error = object_rainbow::Error>,
) -> object_rainbow::Result<Self> {
let mut trie = Self::default();
let mut stream = pin!(stream.into_stream());
while let Some((key, value)) = stream.try_next().await? {
trie.insert(key.as_ref(), value).await?;
}
Ok(trie)
}
}
#[derive(ToOutput, InlineOutput, Tagged, ListHashes, Topological, Parse, ParseInline)]
pub struct TrieMap<K, V> {
key: ObjectMarker<K>,
trie: Trie<V>,
}
assert_impl!(
impl<K, V, E> Inline<E> for TrieMap<K, V>
where
K: ReflessObject,
Option<V>: Inline<E>,
E: 'static + Send + Sync + Clone,
{
}
);
impl<K, V: Clone> Clone for TrieMap<K, V> {
fn clone(&self) -> Self {
Self {
key: self.key,
trie: self.trie.clone(),
}
}
}
impl<K, V> Default for TrieMap<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K, V> TrieMap<K, V> {
pub const fn new() -> Self {
Self {
key: ObjectMarker::new(),
trie: Trie::new(),
}
}
}
impl<K: ReflessObject, V: 'static + Send + Sync + Clone> TrieMap<K, V>
where
Option<V>: Traversible + InlineOutput,
{
pub async fn get(&self, key: &K) -> object_rainbow::Result<Option<V>> {
self.trie.get(&key.vec()).await
}
pub async fn insert(&mut self, key: &K, value: V) -> object_rainbow::Result<Option<V>> {
self.trie.insert(&key.vec(), value).await
}
pub fn is_empty(&self) -> bool {
self.trie.is_empty()
}
pub async fn remove(&mut self, key: &K) -> object_rainbow::Result<Option<V>> {
self.trie.remove(&key.vec()).await
}
pub async fn append(&mut self, other: &mut Self) -> object_rainbow::Result<()> {
self.trie.append(&mut other.trie).await
}
pub fn prefix_stream(
&self,
prefix: &[u8],
) -> impl Send + Stream<Item = object_rainbow::Result<(K, V)>> {
self.trie
.prefix_stream(prefix)
.and_then(async |(key, value)| Ok((K::parse_slice_refless(&key)?, value)))
}
pub fn range_stream<'a>(
&'a self,
range: impl 'a + Send + Sync + RangeBounds<&'a K>,
) -> impl Send + Stream<Item = object_rainbow::Result<(K, V)>> {
self.trie
.range_stream((
range.start_bound().map(|b| b.vec()),
range.end_bound().map(|b| b.vec()),
))
.and_then(async |(key, value)| Ok((K::parse_slice_refless(&key)?, value)))
}
pub async fn from_stream(
stream: impl TryStream<Ok = (K, V), Error = object_rainbow::Error>,
) -> object_rainbow::Result<Self> {
Ok(Self {
key: Default::default(),
trie: Trie::from_stream(stream.map_ok(|(key, value)| (key.vec(), value))).await?,
})
}
}
#[derive(ToOutput, InlineOutput, Tagged, ListHashes, Topological, Parse, ParseInline)]
pub struct TrieSet<T> {
map: TrieMap<T, ()>,
}
assert_impl!(
impl<T, E> Inline<E> for TrieSet<T>
where
T: ReflessObject,
E: 'static + Send + Sync + Clone,
{
}
);
impl<T> Clone for TrieSet<T> {
fn clone(&self) -> Self {
Self {
map: self.map.clone(),
}
}
}
impl<T> Default for TrieSet<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> TrieSet<T> {
pub const fn new() -> Self {
Self {
map: TrieMap::new(),
}
}
}
impl<T: ReflessObject> TrieSet<T> {
pub async fn contains(&self, value: &T) -> object_rainbow::Result<bool> {
Ok(self.map.get(value).await?.is_some())
}
pub async fn insert(&mut self, value: &T) -> object_rainbow::Result<bool> {
Ok(self.map.insert(value, ()).await?.is_none())
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub async fn remove(&mut self, value: &T) -> object_rainbow::Result<bool> {
Ok(self.map.remove(value).await?.is_some())
}
pub async fn append(&mut self, other: &mut Self) -> object_rainbow::Result<()> {
self.map.append(&mut other.map).await
}
pub fn prefix_stream(
&self,
prefix: &[u8],
) -> impl Send + Stream<Item = object_rainbow::Result<T>> {
self.map.prefix_stream(prefix).map_ok(|(value, ())| value)
}
pub fn range_stream<'a>(
&'a self,
range: impl 'a + Send + Sync + RangeBounds<&'a T>,
) -> impl Send + Stream<Item = object_rainbow::Result<T>> {
self.map.range_stream(range).map_ok(|(value, ())| value)
}
pub async fn from_stream(
stream: impl TryStream<Ok = T, Error = object_rainbow::Error>,
) -> object_rainbow::Result<Self> {
Ok(Self {
map: TrieMap::from_stream(stream.map_ok(|value| (value, ()))).await?,
})
}
}
impl<T> Equivalent<TrieMap<T, ()>> for TrieSet<T> {
fn into_equivalent(self) -> TrieMap<T, ()> {
self.map
}
fn from_equivalent(map: TrieMap<T, ()>) -> Self {
Self { map }
}
}
#[cfg(test)]
mod test {
use macro_rules_attribute::apply;
use object_rainbow::ParseSlice;
use smol::stream::StreamExt;
use smol_macros::test;
use crate::{Trie, TrieSet};
#[apply(test!)]
async fn test() -> object_rainbow::Result<()> {
let mut trie = Trie::<u8>::default();
trie.insert(b"abc", 1).await?;
assert_eq!(trie.get(b"abc").await?.unwrap(), 1);
trie.insert(b"abd", 2).await?;
assert_eq!(trie.get(b"abd").await?.unwrap(), 2);
trie.insert(b"ab", 3).await?;
assert_eq!(trie.get(b"ab").await?.unwrap(), 3);
trie.insert(b"a", 4).await?;
assert_eq!(trie.get(b"a").await?.unwrap(), 4);
trie.insert(b"abce", 5).await?;
assert_eq!(trie.get(b"abce").await?.unwrap(), 5);
assert_eq!(
trie.prefix_stream(b"")
.try_collect::<_, _, Vec<_>>()
.await?,
[
(b"a".into(), 4),
(b"ab".into(), 3),
(b"abc".into(), 1),
(b"abce".into(), 5),
(b"abd".into(), 2),
],
);
assert_eq!(
trie.prefix_stream(b"a")
.try_collect::<_, _, Vec<_>>()
.await?,
[
(b"a".into(), 4),
(b"ab".into(), 3),
(b"abc".into(), 1),
(b"abce".into(), 5),
(b"abd".into(), 2),
],
);
assert_eq!(
trie.prefix_stream(b"ab")
.try_collect::<_, _, Vec<_>>()
.await?,
[
(b"ab".into(), 3),
(b"abc".into(), 1),
(b"abce".into(), 5),
(b"abd".into(), 2),
],
);
assert_eq!(
trie.range_stream::<&[u8]>(..)
.try_collect::<_, _, Vec<_>>()
.await?,
[
(b"a".into(), 4),
(b"ab".into(), 3),
(b"abc".into(), 1),
(b"abce".into(), 5),
(b"abd".into(), 2),
],
);
assert_eq!(
trie.range_stream(..=b"abc".as_slice())
.try_collect::<_, _, Vec<_>>()
.await?,
[(b"a".into(), 4), (b"ab".into(), 3), (b"abc".into(), 1)],
);
assert_eq!(
trie.range_stream(..b"abc".as_slice())
.try_collect::<_, _, Vec<_>>()
.await?,
[(b"a".into(), 4), (b"ab".into(), 3)],
);
assert_eq!(
trie.range_stream(b"ab".as_slice()..)
.try_collect::<_, _, Vec<_>>()
.await?,
[
(b"ab".into(), 3),
(b"abc".into(), 1),
(b"abce".into(), 5),
(b"abd".into(), 2),
],
);
assert_eq!(
trie.range_stream(b"ab".as_slice()..=b"abce".as_slice())
.try_collect::<_, _, Vec<_>>()
.await?,
[(b"ab".into(), 3), (b"abc".into(), 1), (b"abce".into(), 5)],
);
assert_eq!(trie.remove(b"a").await?.unwrap(), 4);
assert_eq!(trie.remove(b"ab").await?.unwrap(), 3);
assert_eq!(trie.remove(b"abc").await?.unwrap(), 1);
assert_eq!(trie.remove(b"abce").await?.unwrap(), 5);
assert_eq!(trie.remove(b"abd").await?.unwrap(), 2);
assert!(trie.is_empty());
Ok(())
}
#[apply(test!)]
async fn reparse() -> object_rainbow::Result<()> {
let mut trie = Trie::<u8>::default();
trie.insert(b"abc", 123).await?;
trie = trie.reparse()?;
assert_eq!(trie.get(b"abc").await?.unwrap(), 123);
Ok(())
}
#[apply(test!)]
async fn test_apple_apricot() -> object_rainbow::Result<()> {
let mut trie = Trie::<u8>::default();
trie.insert(b"apple", 1).await?;
trie.insert(b"apricot", 2).await?;
assert_eq!(trie.get(b"apple").await?, Some(1));
assert_eq!(trie.get(b"apricot").await?, Some(2));
Ok(())
}
#[apply(test!)]
async fn append() -> object_rainbow::Result<()> {
let mut enormita = TrieSet::new();
enormita.insert(&b"Magia Baiser".to_vec()).await?;
enormita.insert(&b"Leopard".to_vec()).await?;
enormita.insert(&b"Nero Alice".to_vec()).await?;
let mut rd = TrieSet::new();
rd.insert(&b"Lord Enorme".to_vec()).await?;
rd.insert(&b"Loco Musica".to_vec()).await?;
rd.insert(&b"Leberblume".to_vec()).await?;
enormita.append(&mut rd).await?;
assert!(enormita.contains(&b"Magia Baiser".to_vec()).await?);
assert!(enormita.contains(&b"Leopard".to_vec()).await?);
assert!(enormita.contains(&b"Nero Alice".to_vec()).await?);
assert!(enormita.contains(&b"Lord Enorme".to_vec()).await?);
assert!(enormita.contains(&b"Loco Musica".to_vec()).await?);
assert!(enormita.contains(&b"Leberblume".to_vec()).await?);
assert!(rd.is_empty());
Ok(())
}
}