use super::block::{get_stringtable_key_value, str_from_stringtable};
use super::wire::{
Cursor, PackedBoolIter, PackedInt32Iter, PackedSint32Iter, PackedSint64Iter, WireBlock,
WireDenseInfo, WireDenseNodes,
};
use crate::error::Result;
#[derive(Clone, Debug)]
pub struct DenseNode<'a> {
block: &'a WireBlock<'static>,
pub(crate) id: i64,
lat: i64,
lon: i64,
tag_bytes: &'a [u8],
info: Option<DenseNodeInfo<'a>>,
granularity: i64,
lat_offset: i64,
lon_offset: i64,
}
impl<'a> DenseNode<'a> {
#[inline]
pub fn id(&self) -> i64 {
self.id
}
#[inline]
pub fn info(&'a self) -> Option<&'a DenseNodeInfo<'a>> {
self.info.as_ref()
}
#[inline]
pub fn nano_lat(&self) -> i64 {
self.lat_offset + self.granularity * self.lat
}
#[inline]
pub fn nano_lon(&self) -> i64 {
self.lon_offset + self.granularity * self.lon
}
crate::impl_coordinate_conversions!();
pub fn tags(&self) -> DenseTagIter<'a> {
DenseTagIter {
block: self.block,
cursor: Cursor::new(self.tag_bytes),
}
}
pub fn raw_tags(&self) -> DenseRawTagIter<'a> {
DenseRawTagIter {
cursor: Cursor::new(self.tag_bytes),
}
}
}
pub struct DenseNodeIter<'a> {
block: &'a WireBlock<'static>,
dids: PackedSint64Iter<'a>,
cid: i64,
dlats: PackedSint64Iter<'a>,
clat: i64,
dlons: PackedSint64Iter<'a>,
clon: i64,
kv_data: &'a [u8],
kv_pos: usize,
info_iter: Option<DenseNodeInfoIter<'a>>,
granularity: i64,
lat_offset: i64,
lon_offset: i64,
}
impl<'a> DenseNodeIter<'a> {
pub(crate) fn new(
block: &'a WireBlock<'static>,
dense: WireDenseNodes<'a>,
) -> DenseNodeIter<'a> {
let info_iter = dense
.info_data
.and_then(|data| WireDenseInfo::parse(data).ok())
.map(|info| DenseNodeInfoIter::new(block, info));
DenseNodeIter {
block,
dids: PackedSint64Iter::new(dense.id_data),
cid: 0,
dlats: PackedSint64Iter::new(dense.lat_data),
clat: 0,
dlons: PackedSint64Iter::new(dense.lon_data),
clon: 0,
kv_data: dense.keys_vals_data,
kv_pos: 0,
info_iter,
granularity: i64::from(block.granularity),
lat_offset: block.lat_offset,
lon_offset: block.lon_offset,
}
}
pub(crate) fn new_skip_metadata(
block: &'a WireBlock<'static>,
dense: WireDenseNodes<'a>,
) -> DenseNodeIter<'a> {
DenseNodeIter {
block,
dids: PackedSint64Iter::new(dense.id_data),
cid: 0,
dlats: PackedSint64Iter::new(dense.lat_data),
clat: 0,
dlons: PackedSint64Iter::new(dense.lon_data),
clon: 0,
kv_data: dense.keys_vals_data,
kv_pos: 0,
info_iter: None,
granularity: i64::from(block.granularity),
lat_offset: block.lat_offset,
lon_offset: block.lon_offset,
}
}
pub(crate) fn empty(block: &'a WireBlock<'static>) -> DenseNodeIter<'a> {
DenseNodeIter {
block,
dids: PackedSint64Iter::empty(),
cid: 0,
dlats: PackedSint64Iter::empty(),
clat: 0,
dlons: PackedSint64Iter::empty(),
clon: 0,
kv_data: &[],
kv_pos: 0,
info_iter: None,
granularity: i64::from(block.granularity),
lat_offset: block.lat_offset,
lon_offset: block.lon_offset,
}
}
}
impl<'a> Iterator for DenseNodeIter<'a> {
type Item = DenseNode<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match (
self.dids.next(),
self.dlats.next(),
self.dlons.next(),
self.info_iter.as_mut().and_then(Iterator::next),
) {
(Some(did), Some(dlat), Some(dlon), info) => {
self.cid += did;
self.clat += dlat;
self.clon += dlon;
let tag_start = self.kv_pos;
let mut cursor = Cursor::new(&self.kv_data[self.kv_pos..]);
while !cursor.is_empty() {
let before = cursor.remaining();
match cursor.read_varint() {
Ok(0) => {
let consumed = before - cursor.remaining();
self.kv_pos += consumed;
break;
}
Ok(_key) => {
if cursor.read_varint().is_err() {
break;
}
let consumed = before - cursor.remaining();
self.kv_pos += consumed;
}
Err(_) => break,
}
}
let tag_end = self.kv_pos.saturating_sub(if tag_start < self.kv_pos {
1
} else {
0
});
let tag_bytes = &self.kv_data[tag_start..tag_end.min(self.kv_data.len())];
Some(DenseNode {
block: self.block,
id: self.cid,
lat: self.clat,
lon: self.clon,
tag_bytes,
info,
granularity: self.granularity,
lat_offset: self.lat_offset,
lon_offset: self.lon_offset,
})
}
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.dids.size_hint()
}
}
#[derive(Clone, Debug)]
pub struct DenseNodeInfo<'a> {
block: &'a WireBlock<'static>,
version: i32,
timestamp: i64,
changeset: i64,
uid: i32,
user_sid: i32,
visible: bool,
date_granularity: i64,
}
impl<'a> DenseNodeInfo<'a> {
#[inline]
pub fn version(&self) -> i32 {
self.version
}
#[inline]
pub fn changeset(&self) -> i64 {
self.changeset
}
#[inline]
pub fn uid(&self) -> i32 {
self.uid
}
#[inline]
pub fn raw_user_sid(&self) -> i32 {
self.user_sid
}
#[allow(clippy::cast_sign_loss)]
pub fn user(&self) -> Result<&'a str> {
if self.user_sid < 0 {
return Err(crate::error::new_error(
crate::error::ErrorKind::StringtableIndexOutOfBounds { index: 0 },
));
}
str_from_stringtable(self.block, self.user_sid as usize)
}
#[inline]
pub fn milli_timestamp(&self) -> i64 {
self.timestamp * self.date_granularity
}
#[inline]
pub fn visible(&self) -> bool {
self.visible
}
#[inline]
pub fn deleted(&self) -> bool {
!self.visible
}
}
pub struct DenseNodeInfoIter<'a> {
block: &'a WireBlock<'static>,
versions: PackedInt32Iter<'a>,
dtimestamps: PackedSint64Iter<'a>,
ctimestamp: i64,
dchangesets: PackedSint64Iter<'a>,
cchangeset: i64,
duids: PackedSint32Iter<'a>,
cuid: i32,
duser_sids: PackedSint32Iter<'a>,
cuser_sid: i32,
visible: PackedBoolIter<'a>,
date_granularity: i64,
}
impl<'a> DenseNodeInfoIter<'a> {
fn new(block: &'a WireBlock<'static>, info: WireDenseInfo<'a>) -> DenseNodeInfoIter<'a> {
DenseNodeInfoIter {
block,
versions: PackedInt32Iter::new(info.version_data),
dtimestamps: PackedSint64Iter::new(info.timestamp_data),
ctimestamp: 0,
dchangesets: PackedSint64Iter::new(info.changeset_data),
cchangeset: 0,
duids: PackedSint32Iter::new(info.uid_data),
cuid: 0,
duser_sids: PackedSint32Iter::new(info.user_sid_data),
cuser_sid: 0,
visible: PackedBoolIter::new(info.visible_data),
date_granularity: i64::from(block.date_granularity),
}
}
}
impl<'a> Iterator for DenseNodeInfoIter<'a> {
type Item = DenseNodeInfo<'a>;
fn next(&mut self) -> Option<Self::Item> {
let version = self.versions.next()?;
let dtimestamp = self.dtimestamps.next()?;
let dchangeset = self.dchangesets.next()?;
let duid = self.duids.next()?;
let duser_sid = self.duser_sids.next()?;
let visible_opt = self.visible.next();
self.ctimestamp += dtimestamp;
self.cchangeset += dchangeset;
self.cuid += duid;
self.cuser_sid += duser_sid;
Some(DenseNodeInfo {
block: self.block,
version,
timestamp: self.ctimestamp,
changeset: self.cchangeset,
uid: self.cuid,
user_sid: self.cuser_sid,
visible: visible_opt.unwrap_or(true),
date_granularity: self.date_granularity,
})
}
}
#[derive(Clone)]
pub struct DenseTagIter<'a> {
block: &'a WireBlock<'static>,
cursor: Cursor<'a>,
}
#[allow(clippy::cast_possible_truncation)]
impl<'a> Iterator for DenseTagIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.cursor.is_empty() {
return None;
}
let key = self.cursor.read_varint().ok()? as usize;
let val = self.cursor.read_varint().ok()? as usize;
get_stringtable_key_value(self.block, Some(key), Some(val))
}
}
#[derive(Clone)]
pub struct DenseRawTagIter<'a> {
cursor: Cursor<'a>,
}
impl Iterator for DenseRawTagIter<'_> {
type Item = (i32, i32);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.cursor.is_empty() {
return None;
}
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
let key = self.cursor.read_varint().ok()? as i32;
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
let val = self.cursor.read_varint().ok()? as i32;
Some((key, val))
}
}