use super::block::{get_stringtable_key_value, str_from_stringtable};
use super::dense::DenseNode;
use super::wire::{
PackedInt32Iter, PackedSint64Iter, PackedUint32Iter, WireBlock, WireInfo, WireNode,
WireRelation, WireWay,
};
use crate::error::Result;
#[doc(hidden)]
#[macro_export]
macro_rules! impl_coordinate_conversions {
() => {
#[inline]
#[allow(clippy::cast_precision_loss)]
pub fn lat(&self) -> f64 {
1e-9 * self.nano_lat() as f64
}
#[inline]
#[allow(clippy::cast_precision_loss)]
pub fn lon(&self) -> f64 {
1e-9 * self.nano_lon() as f64
}
#[inline]
#[allow(clippy::cast_possible_truncation)]
pub fn decimicro_lat(&self) -> i32 {
(self.nano_lat() / 100) as i32
}
#[inline]
#[allow(clippy::cast_possible_truncation)]
pub fn decimicro_lon(&self) -> i32 {
(self.nano_lon() / 100) as i32
}
};
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Element<'a> {
Node(Node<'a>),
DenseNode(DenseNode<'a>),
Way(Way<'a>),
Relation(Relation<'a>),
}
#[derive(Clone, Debug)]
pub struct Node<'a> {
block: &'a WireBlock<'static>,
node: WireNode<'a>,
granularity: i64,
lat_offset: i64,
lon_offset: i64,
}
impl<'a> Node<'a> {
pub(crate) fn new(block: &'a WireBlock<'static>, node: WireNode<'a>) -> Node<'a> {
Node {
block,
node,
granularity: i64::from(block.granularity),
lat_offset: block.lat_offset,
lon_offset: block.lon_offset,
}
}
#[inline]
pub fn id(&self) -> i64 {
self.node.id
}
pub fn tags(&self) -> TagIter<'a> {
TagIter {
block: self.block,
key_indices: PackedUint32Iter::new(self.node.keys_data),
val_indices: PackedUint32Iter::new(self.node.vals_data),
}
}
pub fn info(&self) -> Info<'a> {
let wire_info = self
.node
.info_data
.and_then(|data| WireInfo::parse(data).ok())
.unwrap_or_default();
Info::new(self.block, wire_info)
}
#[inline]
pub fn nano_lat(&self) -> i64 {
self.lat_offset + self.granularity * self.node.lat
}
#[inline]
pub fn nano_lon(&self) -> i64 {
self.lon_offset + self.granularity * self.node.lon
}
impl_coordinate_conversions!();
pub fn raw_tags(&self) -> RawTagIter<'a> {
RawTagIter {
key_indices: PackedUint32Iter::new(self.node.keys_data),
val_indices: PackedUint32Iter::new(self.node.vals_data),
}
}
}
#[derive(Clone, Debug)]
pub struct Way<'a> {
block: &'a WireBlock<'static>,
way: WireWay<'a>,
granularity: i64,
lat_offset: i64,
lon_offset: i64,
}
impl<'a> Way<'a> {
pub(crate) fn new(block: &'a WireBlock<'static>, way: WireWay<'a>) -> Way<'a> {
Way {
block,
way,
granularity: i64::from(block.granularity),
lat_offset: block.lat_offset,
lon_offset: block.lon_offset,
}
}
#[inline]
pub fn id(&self) -> i64 {
self.way.id
}
pub fn tags(&self) -> TagIter<'a> {
TagIter {
block: self.block,
key_indices: PackedUint32Iter::new(self.way.keys_data),
val_indices: PackedUint32Iter::new(self.way.vals_data),
}
}
pub fn info(&self) -> Info<'a> {
let wire_info = self
.way
.info_data
.and_then(|data| WireInfo::parse(data).ok())
.unwrap_or_default();
Info::new(self.block, wire_info)
}
pub fn refs(&self) -> WayRefIter<'a> {
WayRefIter {
deltas: PackedSint64Iter::new(self.way.refs_data),
current: 0,
}
}
pub fn node_locations(&self) -> WayNodeLocationsIter<'a> {
WayNodeLocationsIter {
dlats: PackedSint64Iter::new(self.way.lat_data),
dlons: PackedSint64Iter::new(self.way.lon_data),
clat: 0,
clon: 0,
granularity: self.granularity,
lat_offset: self.lat_offset,
lon_offset: self.lon_offset,
}
}
pub fn raw_tags(&self) -> RawTagIter<'a> {
RawTagIter {
key_indices: PackedUint32Iter::new(self.way.keys_data),
val_indices: PackedUint32Iter::new(self.way.vals_data),
}
}
pub(crate) fn keys_data(&self) -> &[u8] {
self.way.keys_data
}
pub(crate) fn vals_data(&self) -> &[u8] {
self.way.vals_data
}
pub(crate) fn refs_data(&self) -> &[u8] {
self.way.refs_data
}
pub(crate) fn info_data(&self) -> Option<&[u8]> {
self.way.info_data
}
pub(crate) fn lat_data(&self) -> &[u8] {
self.way.lat_data
}
pub(crate) fn lon_data(&self) -> &[u8] {
self.way.lon_data
}
}
#[derive(Clone, Debug)]
pub struct Relation<'a> {
block: &'a WireBlock<'static>,
rel: WireRelation<'a>,
}
impl<'a> Relation<'a> {
pub(crate) fn new(
block: &'a WireBlock<'static>,
rel: WireRelation<'a>,
) -> Relation<'a> {
Relation { block, rel }
}
#[inline]
pub fn id(&self) -> i64 {
self.rel.id
}
pub fn tags(&self) -> TagIter<'a> {
TagIter {
block: self.block,
key_indices: PackedUint32Iter::new(self.rel.keys_data),
val_indices: PackedUint32Iter::new(self.rel.vals_data),
}
}
pub fn info(&self) -> Info<'a> {
let wire_info = self
.rel
.info_data
.and_then(|data| WireInfo::parse(data).ok())
.unwrap_or_default();
Info::new(self.block, wire_info)
}
pub fn members(&self) -> RelMemberIter<'a> {
RelMemberIter::new(self.block, &self.rel)
}
pub fn raw_tags(&self) -> RawTagIter<'a> {
RawTagIter {
key_indices: PackedUint32Iter::new(self.rel.keys_data),
val_indices: PackedUint32Iter::new(self.rel.vals_data),
}
}
pub(crate) fn keys_data(&self) -> &[u8] {
self.rel.keys_data
}
pub(crate) fn vals_data(&self) -> &[u8] {
self.rel.vals_data
}
pub(crate) fn roles_sid_data(&self) -> &[u8] {
self.rel.roles_sid_data
}
pub(crate) fn memids_data(&self) -> &[u8] {
self.rel.memids_data
}
pub(crate) fn types_data(&self) -> &[u8] {
self.rel.types_data
}
pub(crate) fn info_data(&self) -> Option<&[u8]> {
self.rel.info_data
}
}
#[derive(Clone)]
pub struct WayRefIter<'a> {
deltas: PackedSint64Iter<'a>,
current: i64,
}
impl Iterator for WayRefIter<'_> {
type Item = i64;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.deltas.next().map(|d| {
self.current += d;
self.current
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.deltas.size_hint()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WayNodeLocation {
lat: i64,
lon: i64,
}
impl WayNodeLocation {
#[inline]
pub fn nano_lat(&self) -> i64 {
self.lat
}
#[inline]
pub fn nano_lon(&self) -> i64 {
self.lon
}
impl_coordinate_conversions!();
}
#[derive(Clone)]
pub struct WayNodeLocationsIter<'a> {
dlats: PackedSint64Iter<'a>,
dlons: PackedSint64Iter<'a>,
clat: i64,
clon: i64,
granularity: i64,
lat_offset: i64,
lon_offset: i64,
}
impl Iterator for WayNodeLocationsIter<'_> {
type Item = WayNodeLocation;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match (self.dlats.next(), self.dlons.next()) {
(Some(dlat), Some(dlon)) => {
self.clat += dlat;
self.clon += dlon;
Some(WayNodeLocation {
lat: self.lat_offset + self.granularity * self.clat,
lon: self.lon_offset + self.granularity * self.clon,
})
}
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.dlats.size_hint()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum MemberType {
Node,
Way,
Relation,
Unknown(i32),
}
impl From<i32> for MemberType {
#[inline]
fn from(v: i32) -> MemberType {
match v {
0 => MemberType::Node,
1 => MemberType::Way,
2 => MemberType::Relation,
other => MemberType::Unknown(other),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum MemberId {
Node(i64),
Way(i64),
Relation(i64),
Unknown(i32, i64),
}
impl MemberId {
#[inline]
pub fn id(self) -> i64 {
match self {
MemberId::Node(id)
| MemberId::Way(id)
| MemberId::Relation(id)
| MemberId::Unknown(_, id) => id,
}
}
#[inline]
pub fn member_type(self) -> MemberType {
match self {
MemberId::Node(_) => MemberType::Node,
MemberId::Way(_) => MemberType::Way,
MemberId::Relation(_) => MemberType::Relation,
MemberId::Unknown(raw, _) => MemberType::Unknown(raw),
}
}
#[inline]
pub fn from_id_and_type(id: i64, member_type: MemberType) -> Self {
match member_type {
MemberType::Node => MemberId::Node(id),
MemberType::Way => MemberId::Way(id),
MemberType::Relation => MemberId::Relation(id),
MemberType::Unknown(raw) => MemberId::Unknown(raw, id),
}
}
}
#[derive(Clone, Debug)]
pub struct RelMember<'a> {
block: &'a WireBlock<'static>,
pub role_sid: i32,
pub id: MemberId,
}
impl<'a> RelMember<'a> {
#[allow(clippy::cast_sign_loss)]
pub fn role(&self) -> Result<&'a str> {
if self.role_sid < 0 {
return Err(crate::error::new_error(
crate::error::ErrorKind::WireFormat {
msg: "relation member has negative role string index",
},
));
}
str_from_stringtable(self.block, self.role_sid as usize)
}
}
#[derive(Clone)]
pub struct RelMemberIter<'a> {
block: &'a WireBlock<'static>,
role_sids: PackedInt32Iter<'a>,
member_id_deltas: PackedSint64Iter<'a>,
member_types: PackedInt32Iter<'a>,
current_member_id: i64,
}
impl<'a> RelMemberIter<'a> {
fn new(block: &'a WireBlock<'static>, rel: &WireRelation<'a>) -> RelMemberIter<'a> {
RelMemberIter {
block,
role_sids: PackedInt32Iter::new(rel.roles_sid_data),
member_id_deltas: PackedSint64Iter::new(rel.memids_data),
member_types: PackedInt32Iter::new(rel.types_data),
current_member_id: 0,
}
}
}
impl<'a> Iterator for RelMemberIter<'a> {
type Item = RelMember<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match (
self.role_sids.next(),
self.member_id_deltas.next(),
self.member_types.next(),
) {
(Some(role_sid), Some(mem_id_delta), Some(member_type)) => {
self.current_member_id += mem_id_delta;
let mt = MemberType::from(member_type);
Some(RelMember {
block: self.block,
role_sid,
id: MemberId::from_id_and_type(self.current_member_id, mt),
})
}
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.role_sids.size_hint()
}
}
#[derive(Clone)]
pub struct TagIter<'a> {
block: &'a WireBlock<'static>,
key_indices: PackedUint32Iter<'a>,
val_indices: PackedUint32Iter<'a>,
}
impl<'a> Iterator for TagIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
get_stringtable_key_value(
self.block,
self.key_indices.next().map(|v| v as usize),
self.val_indices.next().map(|v| v as usize),
)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.key_indices.size_hint()
}
}
#[derive(Clone)]
pub struct RawTagIter<'a> {
key_indices: PackedUint32Iter<'a>,
val_indices: PackedUint32Iter<'a>,
}
impl Iterator for RawTagIter<'_> {
type Item = (u32, u32);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match (self.key_indices.next(), self.val_indices.next()) {
(Some(key_index), Some(val_index)) => Some((key_index, val_index)),
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.key_indices.size_hint()
}
}
#[derive(Clone, Debug)]
pub struct Info<'a> {
block: &'a WireBlock<'static>,
info: WireInfo,
}
impl<'a> Info<'a> {
fn new(block: &'a WireBlock<'static>, info: WireInfo) -> Info<'a> {
Info { block, info }
}
#[inline]
pub fn version(&self) -> Option<i32> {
self.info.version
}
#[inline]
pub fn milli_timestamp(&self) -> Option<i64> {
self.info
.timestamp
.map(|ts| ts * i64::from(self.block.date_granularity))
}
#[inline]
pub fn changeset(&self) -> Option<i64> {
self.info.changeset
}
#[inline]
pub fn uid(&self) -> Option<i32> {
self.info.uid
}
#[inline]
pub fn raw_user_sid(&self) -> Option<i32> {
self.info.user_sid
}
#[allow(clippy::cast_sign_loss)]
pub fn user(&self) -> Option<Result<&'a str>> {
self.info.user_sid.map(|sid| {
if sid < 0 {
return Err(crate::error::new_error(
crate::error::ErrorKind::StringtableIndexOutOfBounds { index: 0 },
));
}
str_from_stringtable(self.block, sid as usize)
})
}
#[inline]
pub fn visible(&self) -> bool {
self.info.visible.unwrap_or(true)
}
#[inline]
pub fn deleted(&self) -> bool {
!self.visible()
}
}