use crate::{BuildError, Key};
use either::Either;
use fst::{IntoStreamer, Set, SetBuilder, Streamer, set::Stream};
use h3o::CellIndex;
use std::{
io,
ops::{Bound, RangeBounds},
};
pub struct FrozenSet<D>(Set<D>);
impl<D: AsRef<[u8]>> FrozenSet<D> {
pub fn new(data: D) -> Result<Self, BuildError> {
Ok(Set::new(data).map(Self)?)
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn contains(&self, index: CellIndex) -> Option<CellIndex> {
let fst = self.0.as_fst();
let key = Key::from(index);
let mut node = fst.root();
for (i, b) in key.as_ref().iter().enumerate() {
let idx = node.find_input(*b)?;
node = fst.node(node.transition_addr(idx));
if node.is_final() {
return Some(Key::from(&key.as_ref()[..=i]).into());
}
}
None
}
#[expect(
clippy::missing_panics_doc,
reason = "expect don't need to be documented"
)]
pub fn descendants(
&self,
index: CellIndex,
) -> impl Iterator<Item = CellIndex> + '_ {
index.resolution().succ().map_or_else(
|| Either::Left(std::iter::empty()),
|resolution| {
let mut children = index.children(resolution);
let start = children.next().expect("first child");
let end = children.last().expect("last child");
Either::Right(
self.range((Bound::Included(start), Bound::Included(end))),
)
},
)
}
#[must_use]
pub fn iter(&self) -> FrozenSetIterator<'_> {
FrozenSetIterator::new(self)
}
pub fn range(
&self,
range: impl RangeBounds<CellIndex>,
) -> impl Iterator<Item = CellIndex> + '_ {
let (start, end) = (range.start_bound(), range.end_bound());
if matches!((start, end), (Bound::Unbounded, Bound::Unbounded)) {
return Either::Left(self.iter());
}
let builder = self.0.range();
let builder = match start {
Bound::Included(lower) => builder.ge(Key::from(*lower)),
Bound::Excluded(lower) => builder.gt(Key::from(*lower)),
Bound::Unbounded => builder,
};
let builder = match end {
Bound::Included(upper) => builder.le(Key::from(*upper)),
Bound::Excluded(upper) => builder.lt(Key::from(*upper)),
Bound::Unbounded => builder,
};
Either::Right(FrozenSetRangeIterator::new(builder.into_stream()))
}
}
impl FrozenSet<Vec<u8>> {
pub fn try_from_iter(
iter: impl IntoIterator<Item = CellIndex>,
) -> Result<Self, BuildError> {
let mut builder = FrozenSetBuilder::memory();
builder.extend_iter(iter)?;
Self::new(builder.into_inner()?)
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_fst().as_bytes()
}
}
impl<'a, D: AsRef<[u8]>> IntoIterator for &'a FrozenSet<D> {
type IntoIter = FrozenSetIterator<'a>;
type Item = CellIndex;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct FrozenSetBuilder<W>(SetBuilder<W>);
impl<W: io::Write> FrozenSetBuilder<W> {
pub fn new(wtr: W) -> Result<Self, BuildError> {
SetBuilder::new(wtr).map(Self).map_err(Into::into)
}
pub fn insert(&mut self, index: CellIndex) -> Result<(), BuildError> {
self.0.insert(Key::from(index)).map_err(Into::into)
}
pub fn extend_iter(
&mut self,
iter: impl IntoIterator<Item = CellIndex>,
) -> Result<(), BuildError> {
self.0
.extend_iter(iter.into_iter().map(Key::from))
.map_err(Into::into)
}
pub fn finish(self) -> Result<(), BuildError> {
self.0.finish().map_err(Into::into)
}
pub fn into_inner(self) -> Result<W, BuildError> {
self.0.into_inner().map_err(Into::into)
}
}
impl FrozenSetBuilder<Vec<u8>> {
#[inline]
#[must_use]
pub fn memory() -> Self {
Self(SetBuilder::memory())
}
#[inline]
#[must_use]
pub fn into_set(self) -> FrozenSet<Vec<u8>> {
FrozenSet(self.0.into_set())
}
}
pub struct FrozenSetIterator<'a> {
stream: Stream<'a>,
len: usize,
count: usize,
}
impl<'a> FrozenSetIterator<'a> {
fn new<D>(set: &'a FrozenSet<D>) -> Self
where
D: AsRef<[u8]>,
{
Self {
stream: set.0.stream(),
len: set.len(),
count: 0,
}
}
}
impl Iterator for FrozenSetIterator<'_> {
type Item = CellIndex;
fn next(&mut self) -> Option<Self::Item> {
self.stream.next().map(|key| {
self.count += 1;
Key::from(key).into()
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
}
impl ExactSizeIterator for FrozenSetIterator<'_> {
fn len(&self) -> usize {
self.len - self.count
}
}
struct FrozenSetRangeIterator<'a> {
stream: Stream<'a>,
}
impl<'a> FrozenSetRangeIterator<'a> {
const fn new(stream: Stream<'a>) -> Self {
Self { stream }
}
}
impl Iterator for FrozenSetRangeIterator<'_> {
type Item = CellIndex;
fn next(&mut self) -> Option<Self::Item> {
self.stream.next().map(|key| Key::from(key).into())
}
}