use crate::geometry::{Box2D, Box3D};
use crate::persistence::{read_f32_le_unchecked, read_f64_le_unchecked};
#[cfg(feature = "async")]
mod async_io;
mod core;
mod directory;
mod error;
mod limits;
mod payload;
mod planner;
mod readers;
#[cfg(feature = "async")]
pub use self::async_io::AsyncRangeReader;
pub(crate) use self::core::{StreamCore, read_index};
pub use self::directory::StreamDirectory;
pub use self::error::StreamError;
pub use self::limits::StreamLimits;
#[cfg(any(unix, windows))]
pub use self::readers::FileReader;
#[cfg(test)]
use self::readers::unexpected_eof;
pub use self::readers::{RangeReader, SliceReader};
pub struct StreamIndex2D<R> {
core: StreamCore<R>,
}
impl<R> StreamIndex2D<R> {
pub fn into_directory(self) -> (StreamDirectory, R) {
let (parts, reader) = self.core.into_parts();
(StreamDirectory { parts }, reader)
}
pub fn from_directory(dir: &StreamDirectory, reader: R) -> Result<Self, StreamError> {
Self::from_directory_with_limits(dir, reader, StreamLimits::default())
}
pub fn from_directory_with_limits(
dir: &StreamDirectory,
reader: R,
limits: StreamLimits,
) -> Result<Self, StreamError> {
Ok(Self {
core: dir.reattach(reader, limits, 2 * 2 * 8)?,
})
}
}
impl<R: RangeReader> StreamIndex2D<R> {
pub fn open(reader: R) -> Result<Self, StreamError> {
Self::open_with_limits(reader, StreamLimits::default())
}
pub fn open_with_limits(reader: R, limits: StreamLimits) -> Result<Self, StreamError> {
Ok(Self {
core: StreamCore::open(reader, 2, 8, limits)?,
})
}
pub fn num_items(&self) -> usize {
self.core.num_items
}
pub fn is_empty(&self) -> bool {
self.core.num_items == 0
}
pub fn node_size(&self) -> usize {
self.core.node_size
}
pub fn extent(&self) -> Option<Box2D> {
if self.core.num_items == 0 {
return None;
}
let root = self.core.num_nodes - 1;
let bytes = self.core.cached_box_bytes(root)?;
Some(parse_box2d(bytes))
}
pub fn visit<F: FnMut(usize)>(&self, query: Box2D, visitor: F) -> Result<(), StreamError> {
self.core
.visit_ids(|record| parse_box2d(record).overlaps(query), visitor)
}
pub fn search(&self, query: Box2D) -> Result<Vec<usize>, StreamError> {
let mut out = Vec::new();
self.search_into(query, &mut out)?;
Ok(out)
}
pub fn search_into(&self, query: Box2D, out: &mut Vec<usize>) -> Result<(), StreamError> {
out.clear();
self.visit(query, |index| out.push(index))
}
pub fn has_payload(&self) -> bool {
self.core.has_payload()
}
pub fn visit_payloads<F: FnMut(usize, &[u8])>(
&self,
query: Box2D,
visitor: F,
) -> Result<(), StreamError> {
self.core
.visit_payloads(|record| parse_box2d(record).overlaps(query), visitor)
}
pub fn search_payloads(&self, query: Box2D) -> Result<Vec<(usize, Vec<u8>)>, StreamError> {
let mut out = Vec::new();
self.visit_payloads(query, |id, blob| out.push((id, blob.to_vec())))?;
Ok(out)
}
}
fn parse_box2d(bytes: &[u8]) -> Box2D {
Box2D::new(
read_f64_le_unchecked(bytes, 0),
read_f64_le_unchecked(bytes, 8),
read_f64_le_unchecked(bytes, 16),
read_f64_le_unchecked(bytes, 24),
)
}
pub struct StreamIndex3D<R> {
core: StreamCore<R>,
}
impl<R> StreamIndex3D<R> {
pub fn into_directory(self) -> (StreamDirectory, R) {
let (parts, reader) = self.core.into_parts();
(StreamDirectory { parts }, reader)
}
pub fn from_directory(dir: &StreamDirectory, reader: R) -> Result<Self, StreamError> {
Self::from_directory_with_limits(dir, reader, StreamLimits::default())
}
pub fn from_directory_with_limits(
dir: &StreamDirectory,
reader: R,
limits: StreamLimits,
) -> Result<Self, StreamError> {
Ok(Self {
core: dir.reattach(reader, limits, 3 * 2 * 8)?,
})
}
}
impl<R: RangeReader> StreamIndex3D<R> {
pub fn open(reader: R) -> Result<Self, StreamError> {
Self::open_with_limits(reader, StreamLimits::default())
}
pub fn open_with_limits(reader: R, limits: StreamLimits) -> Result<Self, StreamError> {
Ok(Self {
core: StreamCore::open(reader, 3, 8, limits)?,
})
}
pub fn num_items(&self) -> usize {
self.core.num_items
}
pub fn is_empty(&self) -> bool {
self.core.num_items == 0
}
pub fn node_size(&self) -> usize {
self.core.node_size
}
pub fn extent(&self) -> Option<Box3D> {
if self.core.num_items == 0 {
return None;
}
let root = self.core.num_nodes - 1;
let bytes = self.core.cached_box_bytes(root)?;
Some(parse_box3d(bytes))
}
pub fn visit<F: FnMut(usize)>(&self, query: Box3D, visitor: F) -> Result<(), StreamError> {
self.core
.visit_ids(|record| parse_box3d(record).overlaps(query), visitor)
}
pub fn search(&self, query: Box3D) -> Result<Vec<usize>, StreamError> {
let mut out = Vec::new();
self.search_into(query, &mut out)?;
Ok(out)
}
pub fn search_into(&self, query: Box3D, out: &mut Vec<usize>) -> Result<(), StreamError> {
out.clear();
self.visit(query, |index| out.push(index))
}
pub fn has_payload(&self) -> bool {
self.core.has_payload()
}
pub fn visit_payloads<F: FnMut(usize, &[u8])>(
&self,
query: Box3D,
visitor: F,
) -> Result<(), StreamError> {
self.core
.visit_payloads(|record| parse_box3d(record).overlaps(query), visitor)
}
pub fn search_payloads(&self, query: Box3D) -> Result<Vec<(usize, Vec<u8>)>, StreamError> {
let mut out = Vec::new();
self.visit_payloads(query, |id, blob| out.push((id, blob.to_vec())))?;
Ok(out)
}
}
fn parse_box3d(bytes: &[u8]) -> Box3D {
Box3D::new(
read_f64_le_unchecked(bytes, 0),
read_f64_le_unchecked(bytes, 8),
read_f64_le_unchecked(bytes, 16),
read_f64_le_unchecked(bytes, 24),
read_f64_le_unchecked(bytes, 32),
read_f64_le_unchecked(bytes, 40),
)
}
fn parse_box2d_f32(bytes: &[u8]) -> Box2D {
Box2D::new(
read_f32_le_unchecked(bytes, 0) as f64,
read_f32_le_unchecked(bytes, 4) as f64,
read_f32_le_unchecked(bytes, 8) as f64,
read_f32_le_unchecked(bytes, 12) as f64,
)
}
fn parse_box3d_f32(bytes: &[u8]) -> Box3D {
Box3D::new(
read_f32_le_unchecked(bytes, 0) as f64,
read_f32_le_unchecked(bytes, 4) as f64,
read_f32_le_unchecked(bytes, 8) as f64,
read_f32_le_unchecked(bytes, 12) as f64,
read_f32_le_unchecked(bytes, 16) as f64,
read_f32_le_unchecked(bytes, 20) as f64,
)
}
pub struct StreamIndex2DF32<R> {
core: StreamCore<R>,
}
impl<R> StreamIndex2DF32<R> {
pub fn into_directory(self) -> (StreamDirectory, R) {
let (parts, reader) = self.core.into_parts();
(StreamDirectory { parts }, reader)
}
pub fn from_directory(dir: &StreamDirectory, reader: R) -> Result<Self, StreamError> {
Self::from_directory_with_limits(dir, reader, StreamLimits::default())
}
pub fn from_directory_with_limits(
dir: &StreamDirectory,
reader: R,
limits: StreamLimits,
) -> Result<Self, StreamError> {
Ok(Self {
core: dir.reattach(reader, limits, 2 * 2 * 4)?,
})
}
}
impl<R: RangeReader> StreamIndex2DF32<R> {
pub fn open(reader: R) -> Result<Self, StreamError> {
Self::open_with_limits(reader, StreamLimits::default())
}
pub fn open_with_limits(reader: R, limits: StreamLimits) -> Result<Self, StreamError> {
Ok(Self {
core: StreamCore::open(reader, 2, 4, limits)?,
})
}
pub fn num_items(&self) -> usize {
self.core.num_items
}
pub fn is_empty(&self) -> bool {
self.core.num_items == 0
}
pub fn node_size(&self) -> usize {
self.core.node_size
}
pub fn extent(&self) -> Option<Box2D> {
if self.core.num_items == 0 {
return None;
}
let root = self.core.num_nodes - 1;
Some(parse_box2d_f32(self.core.cached_box_bytes(root)?))
}
pub fn visit<F: FnMut(usize)>(&self, query: Box2D, visitor: F) -> Result<(), StreamError> {
self.core
.visit_ids(|r| parse_box2d_f32(r).overlaps(query), visitor)
}
pub fn search(&self, query: Box2D) -> Result<Vec<usize>, StreamError> {
let mut out = Vec::new();
self.search_into(query, &mut out)?;
Ok(out)
}
pub fn search_into(&self, query: Box2D, out: &mut Vec<usize>) -> Result<(), StreamError> {
out.clear();
self.visit(query, |index| out.push(index))
}
pub fn has_payload(&self) -> bool {
self.core.has_payload()
}
pub fn visit_payloads<F: FnMut(usize, &[u8])>(
&self,
query: Box2D,
visitor: F,
) -> Result<(), StreamError> {
self.core
.visit_payloads(|r| parse_box2d_f32(r).overlaps(query), visitor)
}
pub fn search_payloads(&self, query: Box2D) -> Result<Vec<(usize, Vec<u8>)>, StreamError> {
let mut out = Vec::new();
self.visit_payloads(query, |id, blob| out.push((id, blob.to_vec())))?;
Ok(out)
}
}
pub struct StreamIndex3DF32<R> {
core: StreamCore<R>,
}
impl<R> StreamIndex3DF32<R> {
pub fn into_directory(self) -> (StreamDirectory, R) {
let (parts, reader) = self.core.into_parts();
(StreamDirectory { parts }, reader)
}
pub fn from_directory(dir: &StreamDirectory, reader: R) -> Result<Self, StreamError> {
Self::from_directory_with_limits(dir, reader, StreamLimits::default())
}
pub fn from_directory_with_limits(
dir: &StreamDirectory,
reader: R,
limits: StreamLimits,
) -> Result<Self, StreamError> {
Ok(Self {
core: dir.reattach(reader, limits, 3 * 2 * 4)?,
})
}
}
impl<R: RangeReader> StreamIndex3DF32<R> {
pub fn open(reader: R) -> Result<Self, StreamError> {
Self::open_with_limits(reader, StreamLimits::default())
}
pub fn open_with_limits(reader: R, limits: StreamLimits) -> Result<Self, StreamError> {
Ok(Self {
core: StreamCore::open(reader, 3, 4, limits)?,
})
}
pub fn num_items(&self) -> usize {
self.core.num_items
}
pub fn is_empty(&self) -> bool {
self.core.num_items == 0
}
pub fn node_size(&self) -> usize {
self.core.node_size
}
pub fn extent(&self) -> Option<Box3D> {
if self.core.num_items == 0 {
return None;
}
let root = self.core.num_nodes - 1;
Some(parse_box3d_f32(self.core.cached_box_bytes(root)?))
}
pub fn visit<F: FnMut(usize)>(&self, query: Box3D, visitor: F) -> Result<(), StreamError> {
self.core
.visit_ids(|r| parse_box3d_f32(r).overlaps(query), visitor)
}
pub fn search(&self, query: Box3D) -> Result<Vec<usize>, StreamError> {
let mut out = Vec::new();
self.search_into(query, &mut out)?;
Ok(out)
}
pub fn search_into(&self, query: Box3D, out: &mut Vec<usize>) -> Result<(), StreamError> {
out.clear();
self.visit(query, |index| out.push(index))
}
pub fn has_payload(&self) -> bool {
self.core.has_payload()
}
pub fn visit_payloads<F: FnMut(usize, &[u8])>(
&self,
query: Box3D,
visitor: F,
) -> Result<(), StreamError> {
self.core
.visit_payloads(|r| parse_box3d_f32(r).overlaps(query), visitor)
}
pub fn search_payloads(&self, query: Box3D) -> Result<Vec<(usize, Vec<u8>)>, StreamError> {
let mut out = Vec::new();
self.visit_payloads(query, |id, blob| out.push((id, blob.to_vec())))?;
Ok(out)
}
}
#[cfg(test)]
mod tests;