osm_pbf_iter 0.2.2

Parse OpenStreetMap .pbf dumps while trying to avoid copying
Documentation
use protobuf_iter::*;
use std::fmt;
use std::hash::{Hash, Hasher};

use crate::{delta::DeltaEncodedIter, info::Info, primitive_block::PrimitiveBlock, tags::TagsIter};

#[derive(Debug, Clone)]
pub struct Relation<'a> {
    pub id: u64,
    pub info: Option<Info<'a>>,
    tags_iter: TagsIter<'a>,
    rels_iter: RelationMembersIter<'a>,
}

impl<'a> Hash for Relation<'a> {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.id.hash(state)
    }
}

impl<'a> Eq for Relation<'a> {}
impl<'a> PartialEq for Relation<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum RelationMemberType {
    Node,
    Way,
    Relation,
}

#[derive(Clone)]
pub struct RelationMembersIter<'a> {
    roles_sid: PackedIter<'a, PackedVarint, u32>,
    memids: DeltaEncodedIter<'a, PackedVarint, i64>,
    types: PackedIter<'a, PackedVarint, u32>,
    stringtable: &'a [&'a str],
}

impl<'a> Iterator for RelationMembersIter<'a> {
    type Item = (&'a str, u64, RelationMemberType);

    fn next(&mut self) -> Option<Self::Item> {
        let role_sid = self.roles_sid.next()? as usize;
        let role = if role_sid < self.stringtable.len() {
            self.stringtable[role_sid]
        } else {
            return None;
        };

        let memid = self.memids.next()?.try_into().ok()?;

        let memtype = match self.types.next() {
            Some(0) => RelationMemberType::Node,
            Some(1) => RelationMemberType::Way,
            Some(2) => RelationMemberType::Relation,
            _ => return None,
        };

        Some((role, memid, memtype))
    }
}

impl<'a> fmt::Debug for RelationMembersIter<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{{")?;
        for (i, (role, id, reltype)) in self.clone().enumerate() {
            if i > 0 {
                write!(f, ",")?;
            }
            write!(f, " {:?} {} {:?}", reltype, id, role)?;
        }
        write!(f, " }}")?;
        Ok(())
    }
}

impl<'a> Relation<'a> {
    pub fn parse(primitive_block: &'a PrimitiveBlock<'a>, data: &'a [u8]) -> Self {
        let iter = MessageIter::new(data);

        let mut relation = Relation {
            id: 0,
            info: None,
            tags_iter: TagsIter::new(&primitive_block.stringtable),
            rels_iter: RelationMembersIter {
                roles_sid: PackedIter::new(&[]),
                memids: DeltaEncodedIter::new(ParseValue::LengthDelimited(&[])),
                types: PackedIter::new(&[]),
                stringtable: &primitive_block.stringtable,
            },
        };

        for m in iter.clone() {
            match m.tag {
                1 => relation.id = Into::into(m.value),
                2 => relation.tags_iter.set_keys(*m.value),
                3 => relation.tags_iter.set_values(*m.value),
                4 => relation.info = Some(Info::parse(&primitive_block.stringtable, *m.value)),
                8 => relation.rels_iter.roles_sid = PackedIter::new(*m.value),
                9 => relation.rels_iter.memids = DeltaEncodedIter::new(m.value),
                10 => relation.rels_iter.types = PackedIter::new(*m.value),
                _ => (),
            }
        }

        relation
    }

    pub fn tags(&self) -> TagsIter<'a> {
        self.tags_iter.clone()
    }

    pub fn members(&self) -> RelationMembersIter<'a> {
        self.rels_iter.clone()
    }
}