use crate::read::elements::MemberType;
use super::interner::StringInterner;
#[inline]
fn read_i64_le(data: &[u8], offset: usize) -> i64 {
let bytes: [u8; 8] = data[offset..offset + 8].try_into().expect("slice length");
i64::from_le_bytes(bytes)
}
#[inline]
fn read_i32_le(data: &[u8], offset: usize) -> i32 {
let bytes: [u8; 4] = data[offset..offset + 4].try_into().expect("slice length");
i32::from_le_bytes(bytes)
}
#[inline]
fn read_u32_le(data: &[u8], offset: usize) -> u32 {
let bytes: [u8; 4] = data[offset..offset + 4].try_into().expect("slice length");
u32::from_le_bytes(bytes)
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub(super) fn member_type_to_byte(mt: MemberType) -> u8 {
match mt {
MemberType::Node => 0,
MemberType::Way => 1,
MemberType::Relation => 2,
MemberType::Unknown(v) => v as u8,
}
}
fn byte_to_member_type(b: u8) -> MemberType {
match b {
0 => MemberType::Node,
1 => MemberType::Way,
2 => MemberType::Relation,
other => MemberType::Unknown(i32::from(other)),
}
}
#[allow(clippy::cast_possible_truncation)]
pub(super) fn arena_append_node(arena: &mut Vec<u8>, id: i64, lat: i32, lon: i32, tags: &[(u32, &str)]) -> u32 {
let offset = arena.len() as u32;
arena.extend_from_slice(&id.to_le_bytes());
arena.extend_from_slice(&lat.to_le_bytes());
arena.extend_from_slice(&lon.to_le_bytes());
let tag_count = tags.len() as u32;
arena.extend_from_slice(&tag_count.to_le_bytes());
for &(key_id, value) in tags {
arena.extend_from_slice(&key_id.to_le_bytes());
let value_len = value.len() as u32;
arena.extend_from_slice(&value_len.to_le_bytes());
arena.extend_from_slice(value.as_bytes());
}
offset
}
#[allow(clippy::cast_possible_truncation)]
pub(super) fn arena_append_way(arena: &mut Vec<u8>, id: i64, refs: &[i64], tags: &[(u32, &str)]) -> u32 {
let offset = arena.len() as u32;
arena.extend_from_slice(&id.to_le_bytes());
let ref_count = refs.len() as u32;
arena.extend_from_slice(&ref_count.to_le_bytes());
let tag_count = tags.len() as u32;
arena.extend_from_slice(&tag_count.to_le_bytes());
for &r in refs {
arena.extend_from_slice(&r.to_le_bytes());
}
for &(key_id, value) in tags {
arena.extend_from_slice(&key_id.to_le_bytes());
let value_len = value.len() as u32;
arena.extend_from_slice(&value_len.to_le_bytes());
arena.extend_from_slice(value.as_bytes());
}
offset
}
#[allow(clippy::cast_possible_truncation)]
pub(super) fn arena_append_relation(
arena: &mut Vec<u8>,
id: i64,
members: &[(i64, u8, u32)],
tags: &[(u32, &str)],
) -> u32 {
let offset = arena.len() as u32;
arena.extend_from_slice(&id.to_le_bytes());
let member_count = members.len() as u32;
arena.extend_from_slice(&member_count.to_le_bytes());
let tag_count = tags.len() as u32;
arena.extend_from_slice(&tag_count.to_le_bytes());
for &(ref_id, type_byte, role_id) in members {
arena.extend_from_slice(&ref_id.to_le_bytes());
arena.push(type_byte);
arena.extend_from_slice(&role_id.to_le_bytes());
}
for &(key_id, value) in tags {
arena.extend_from_slice(&key_id.to_le_bytes());
let value_len = value.len() as u32;
arena.extend_from_slice(&value_len.to_le_bytes());
arena.extend_from_slice(value.as_bytes());
}
offset
}
pub struct CompactTagIter<'a> {
data: &'a [u8],
offset: usize,
remaining: usize,
interner: &'a StringInterner,
}
impl<'a> Iterator for CompactTagIter<'a> {
type Item = (&'a str, &'a str);
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
let key_id = read_u32_le(self.data, self.offset);
self.offset += 4;
let value_len = read_u32_le(self.data, self.offset) as usize;
self.offset += 4;
let value_bytes = &self.data[self.offset..self.offset + value_len];
self.offset += value_len;
let key = self.interner.resolve(key_id);
let value = std::str::from_utf8(value_bytes).unwrap_or("");
Some((key, value))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl ExactSizeIterator for CompactTagIter<'_> {}
pub struct CompactRefIter<'a> {
data: &'a [u8],
offset: usize,
remaining: usize,
}
impl Iterator for CompactRefIter<'_> {
type Item = i64;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
let val = read_i64_le(self.data, self.offset);
self.offset += 8;
Some(val)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl ExactSizeIterator for CompactRefIter<'_> {}
pub struct CompactMemberIter<'a> {
data: &'a [u8],
offset: usize,
remaining: usize,
interner: &'a StringInterner,
}
impl<'a> Iterator for CompactMemberIter<'a> {
type Item = (MemberType, i64, &'a str);
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
let ref_id = read_i64_le(self.data, self.offset);
self.offset += 8;
let type_byte = self.data[self.offset];
self.offset += 1;
let role_id = read_u32_le(self.data, self.offset);
self.offset += 4;
let member_type = byte_to_member_type(type_byte);
let role = self.interner.resolve(role_id);
Some((member_type, ref_id, role))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl ExactSizeIterator for CompactMemberIter<'_> {}
pub struct CompactNodeRef<'a> {
pub(super) data: &'a [u8],
pub(super) interner: &'a StringInterner,
}
impl<'a> CompactNodeRef<'a> {
const HEADER_LEN: usize = 20;
pub fn id(&self) -> i64 {
read_i64_le(self.data, 0)
}
pub fn decimicro_lat(&self) -> i32 {
read_i32_le(self.data, 8)
}
pub fn decimicro_lon(&self) -> i32 {
read_i32_le(self.data, 12)
}
pub fn tag_count(&self) -> usize {
read_u32_le(self.data, 16) as usize
}
pub fn tags(&self) -> CompactTagIter<'a> {
CompactTagIter {
data: self.data,
offset: Self::HEADER_LEN,
remaining: self.tag_count(),
interner: self.interner,
}
}
}
pub struct CompactWayRef<'a> {
pub(super) data: &'a [u8],
pub(super) interner: &'a StringInterner,
}
impl<'a> CompactWayRef<'a> {
const HEADER_LEN: usize = 16;
pub fn id(&self) -> i64 {
read_i64_le(self.data, 0)
}
pub fn ref_count(&self) -> usize {
read_u32_le(self.data, 8) as usize
}
pub fn tag_count(&self) -> usize {
read_u32_le(self.data, 12) as usize
}
pub fn refs(&self) -> CompactRefIter<'a> {
CompactRefIter {
data: self.data,
offset: Self::HEADER_LEN,
remaining: self.ref_count(),
}
}
pub fn tags(&self) -> CompactTagIter<'a> {
let tag_offset = Self::HEADER_LEN + self.ref_count() * 8;
CompactTagIter {
data: self.data,
offset: tag_offset,
remaining: self.tag_count(),
interner: self.interner,
}
}
}
pub struct CompactRelationRef<'a> {
pub(super) data: &'a [u8],
pub(super) interner: &'a StringInterner,
}
impl<'a> CompactRelationRef<'a> {
const HEADER_LEN: usize = 16;
const MEMBER_SIZE: usize = 13;
pub fn id(&self) -> i64 {
read_i64_le(self.data, 0)
}
pub fn member_count(&self) -> usize {
read_u32_le(self.data, 8) as usize
}
pub fn tag_count(&self) -> usize {
read_u32_le(self.data, 12) as usize
}
pub fn members(&self) -> CompactMemberIter<'a> {
CompactMemberIter {
data: self.data,
offset: Self::HEADER_LEN,
remaining: self.member_count(),
interner: self.interner,
}
}
pub fn tags(&self) -> CompactTagIter<'a> {
let tag_offset = Self::HEADER_LEN + self.member_count() * Self::MEMBER_SIZE;
CompactTagIter {
data: self.data,
offset: tag_offset,
remaining: self.tag_count(),
interner: self.interner,
}
}
}