1use crate::Osm;
6use std::ops::Range;
7
8#[inline]
13pub fn iter_tags(archive: &Osm, range: Range<u64>) -> impl Iterator<Item = (&[u8], &[u8])> + Clone {
14 let tags = archive.tags();
15 let tags_index = archive.tags_index();
16 let strings = archive.stringtable();
17
18 range.map(move |idx| {
19 let tag = &tags[tags_index[idx as usize].value() as usize];
20 let key = strings.substring_raw(tag.key_idx() as usize);
21 let val = strings.substring_raw(tag.value_idx() as usize);
22 (key, val)
23 })
24}
25
26#[inline]
35pub fn find_tag_by(
36 archive: &Osm,
37 mut range: Range<u64>,
38 mut predicate: impl FnMut(&[u8], &[u8]) -> bool,
39) -> Option<&[u8]> {
40 let tags = archive.tags();
41 let tags_index = archive.tags_index();
42 let strings = archive.stringtable();
43
44 range.find_map(move |idx| {
45 let tag = &tags[tags_index[idx as usize].value() as usize];
46 let key_block = &strings.as_bytes()[tag.key_idx() as usize..];
47 let value_block = &strings.as_bytes()[tag.value_idx() as usize..];
48 if predicate(key_block, value_block) {
49 Some(strings.substring_raw(tag.value_idx() as usize))
50 } else {
51 None
52 }
53 })
54}
55
56#[inline]
59pub fn find_tag<'a>(archive: &'a Osm, range: Range<u64>, key: &[u8]) -> Option<&'a [u8]> {
60 find_tag_by(archive, range, |key_block, _| {
61 key_block.starts_with(key) && *key_block.get(key.len()).unwrap_or(&0) == 0
62 })
63}
64
65#[inline]
67pub fn has_tag(archive: &Osm, range: Range<u64>, key: &[u8], value: &[u8]) -> bool {
68 let tags = archive.tags();
69 let tags_index = archive.tags_index();
70 let strings = archive.stringtable();
71
72 let matches = |idx, value| {
73 let block = &strings.as_bytes()[idx as usize..];
74 block.starts_with(value) && *block.get(value.len()).unwrap_or(&0) == 0
75 };
76
77 for idx in range {
78 let tag = &tags[tags_index[idx as usize].value() as usize];
79 if matches(tag.key_idx(), key) {
80 return matches(tag.value_idx(), value);
81 }
82 }
83 false
84}