use crate::{BuildError, Key};
use either::Either;
use fst::{
map::{Keys, Stream, Values},
raw::Output,
IntoStreamer, Map, MapBuilder, Streamer,
};
use h3o::CellIndex;
use std::{
io,
ops::{Bound, RangeBounds},
};
pub struct FrozenMap<D>(Map<D>);
impl<D: AsRef<[u8]>> FrozenMap<D> {
pub fn new(data: D) -> Result<Self, BuildError> {
Ok(Map::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_key(&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
}
pub fn get(&self, index: CellIndex) -> Option<(CellIndex, u64)> {
let fst = self.0.as_fst();
let key = Key::from(index);
let mut output = Output::zero();
let mut node = fst.root();
for (i, b) in key.as_ref().iter().enumerate() {
let idx = node.find_input(*b)?;
let transition = node.transition(idx);
output = output.cat(transition.out);
node = fst.node(transition.addr);
if node.is_final() {
return Some((
Key::from(&key.as_ref()[..=i]).into(),
output.value(),
));
}
}
None
}
#[allow(clippy::missing_panics_doc)] pub fn descendants(
&self,
index: CellIndex,
) -> impl Iterator<Item = (CellIndex, u64)> + '_ {
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))),
)
},
)
}
pub fn iter(&self) -> FrozenMapIterator<'_> {
FrozenMapIterator::new(self)
}
pub fn keys(&self) -> FrozenMapKeys<'_> {
FrozenMapKeys::new(self)
}
pub fn values(&self) -> FrozenMapValues<'_> {
FrozenMapValues::new(self)
}
pub fn range(
&self,
range: impl RangeBounds<CellIndex>,
) -> impl Iterator<Item = (CellIndex, u64)> + '_ {
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(FrozenMapRangeIterator::new(builder.into_stream()))
}
}
impl FrozenMap<Vec<u8>> {
pub fn try_from_iter(
iter: impl IntoIterator<Item = (CellIndex, u64)>,
) -> Result<Self, BuildError> {
let mut builder = FrozenMapBuilder::memory();
builder.extend_iter(iter)?;
Self::new(builder.into_inner()?)
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_fst().as_bytes()
}
}
pub struct FrozenMapBuilder<W>(MapBuilder<W>);
impl<W: io::Write> FrozenMapBuilder<W> {
pub fn new(wtr: W) -> Result<Self, BuildError> {
MapBuilder::new(wtr).map(Self).map_err(Into::into)
}
pub fn insert(
&mut self,
index: CellIndex,
value: u64,
) -> Result<(), BuildError> {
self.0.insert(Key::from(index), value).map_err(Into::into)
}
pub fn extend_iter(
&mut self,
iter: impl IntoIterator<Item = (CellIndex, u64)>,
) -> Result<(), BuildError> {
self.0
.extend_iter(
iter.into_iter()
.map(|(index, value)| (Key::from(index), value)),
)
.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 FrozenMapBuilder<Vec<u8>> {
#[must_use]
#[inline]
pub fn memory() -> Self {
Self(MapBuilder::memory())
}
#[must_use]
#[inline]
pub fn into_map(self) -> FrozenMap<Vec<u8>> {
FrozenMap(self.0.into_map())
}
}
pub struct FrozenMapIterator<'a> {
stream: Stream<'a>,
len: usize,
count: usize,
}
impl<'a> FrozenMapIterator<'a> {
fn new<D>(map: &'a FrozenMap<D>) -> Self
where
D: AsRef<[u8]>,
{
Self {
stream: map.0.stream(),
len: map.len(),
count: 0,
}
}
}
impl Iterator for FrozenMapIterator<'_> {
type Item = (CellIndex, u64);
fn next(&mut self) -> Option<Self::Item> {
self.stream.next().map(|(key, value)| {
self.count += 1;
(Key::from(key).into(), value)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
}
impl ExactSizeIterator for FrozenMapIterator<'_> {
fn len(&self) -> usize {
self.len - self.count
}
}
pub struct FrozenMapKeys<'a> {
keys: Keys<'a>,
len: usize,
count: usize,
}
impl<'a> FrozenMapKeys<'a> {
fn new<D>(map: &'a FrozenMap<D>) -> Self
where
D: AsRef<[u8]>,
{
Self {
keys: map.0.keys(),
len: map.len(),
count: 0,
}
}
}
impl Iterator for FrozenMapKeys<'_> {
type Item = CellIndex;
fn next(&mut self) -> Option<Self::Item> {
self.keys.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 FrozenMapKeys<'_> {
fn len(&self) -> usize {
self.len - self.count
}
}
pub struct FrozenMapValues<'a> {
values: Values<'a>,
len: usize,
count: usize,
}
impl<'a> FrozenMapValues<'a> {
fn new<D>(map: &'a FrozenMap<D>) -> Self
where
D: AsRef<[u8]>,
{
Self {
values: map.0.values(),
len: map.len(),
count: 0,
}
}
}
impl Iterator for FrozenMapValues<'_> {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
self.values.next().map(|value| {
self.count += 1;
value
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
}
impl ExactSizeIterator for FrozenMapValues<'_> {
fn len(&self) -> usize {
self.len - self.count
}
}
struct FrozenMapRangeIterator<'a> {
stream: Stream<'a>,
}
impl<'a> FrozenMapRangeIterator<'a> {
const fn new(stream: Stream<'a>) -> Self {
Self { stream }
}
}
impl Iterator for FrozenMapRangeIterator<'_> {
type Item = (CellIndex, u64);
fn next(&mut self) -> Option<Self::Item> {
self.stream
.next()
.map(|(key, value)| (Key::from(key).into(), value))
}
}