1use std::ops::Deref;
2
3use bitflags::bitflags;
4use bytes::Bytes;
5use protobuf::SpecialFields;
6
7use crate::osmformat::{
8 ChangeSet, DenseInfo, Info, Node, PrimitiveBlock, PrimitiveGroup, Relation, Way,
9};
10
11bitflags! {
12 pub struct PrimitiveType: u32 {
13 const NODE = 1;
14 const WAY = 2;
15 const RELATION = 4;
16 const CHANGE_SET = 8;
17
18 const DEFAULT = Self::NODE.bits() | Self::WAY.bits() | Self::RELATION.bits();
19 }
20}
21
22#[derive(Copy, Clone)]
23pub struct PrimitiveRef<'l, T: ?Sized> {
24 value: &'l T,
25 block: &'l PrimitiveBlock,
26}
27
28impl<T: ?Sized> Deref for PrimitiveRef<'_, T> {
29 type Target = T;
30 fn deref(&self) -> &T {
31 self.value
32 }
33}
34
35pub type PrimitiveGroupRef<'l> = PrimitiveRef<'l, PrimitiveGroup>;
36pub type WayRef<'l> = PrimitiveRef<'l, Way>;
37pub type RelationRef<'l> = PrimitiveRef<'l, Relation>;
38pub type ChangeSetRef<'l> = PrimitiveRef<'l, ChangeSet>;
39
40#[derive(PartialEq, Clone, Debug)]
41pub struct NodeRef<'l> {
42 pub id: i64,
43 pub nano_lat: i64,
44 pub nano_lon: i64,
45 pub index: usize,
46 data: NodeData<'l>,
47 block: &'l PrimitiveBlock,
48}
49
50impl<'l> NodeRef<'l> {
51 #[inline]
52 fn from_node(index: usize, node: &'l Node, block: &'l PrimitiveBlock) -> Self {
53 Self {
54 id: node.id(),
55 nano_lat: block.lat_offset() + node.lat() * block.granularity() as i64,
56 nano_lon: block.lon_offset() + node.lon() * block.granularity() as i64,
57 index,
58 data: NodeData::Node {
59 keys: &node.keys,
60 vals: &node.vals,
61 info: &node.info,
62 },
63 block,
64 }
65 }
66
67 #[inline]
68 fn from_dense_node(
69 index: usize,
70 dense_state: &DenseState,
71 kv_pairs: &'l [i32],
72 info: &'l DenseInfo,
73 block: &'l PrimitiveBlock,
74 ) -> Self {
75 Self {
76 id: dense_state.id,
77 nano_lat: block.lat_offset() + dense_state.lat * block.granularity() as i64,
78 nano_lon: block.lon_offset() + dense_state.lon * block.granularity() as i64,
79 index,
80 data: NodeData::DenseNode { kv_pairs, info },
81 block,
82 }
83 }
84
85 #[inline]
86 pub const fn id(&self) -> i64 {
87 self.id
88 }
89
90 #[inline]
92 pub fn lat(&self) -> f64 {
93 self.nano_lat as f64 * 1e-9
94 }
95
96 #[inline]
98 pub fn lon(&self) -> f64 {
99 self.nano_lon as f64 * 1e-9
100 }
101
102 pub fn info(&self) -> Info {
103 match self.data {
104 NodeData::Node { info, .. } => info.clone(),
105 NodeData::DenseNode { info, .. } => Info {
106 version: info.version.get(self.index).copied(),
107 timestamp: info.timestamp.get(self.index).copied(),
108 changeset: info.changeset.get(self.index).copied(),
109 uid: info.uid.get(self.index).copied(),
110 user_sid: info.user_sid.get(self.index).copied().map(|v| v as u32),
111 visible: info.visible.get(self.index).copied(),
112 special_fields: SpecialFields::new(),
113 },
114 }
115 }
116
117 pub fn tags(&self) -> Tags<'_> {
118 match self.data {
119 NodeData::Node { keys, vals, .. } => Tags {
120 kv: TagsData::Normal(keys.iter(), vals.iter()),
121 s: &self.block.stringtable.s,
122 },
123 NodeData::DenseNode { kv_pairs, .. } => Tags {
124 kv: TagsData::Dense(kv_pairs.iter()),
125 s: &self.block.stringtable.s,
126 },
127 }
128 }
129}
130
131#[derive(PartialEq, Clone, Debug)]
132enum NodeData<'l> {
133 Node {
134 keys: &'l [u32],
135 vals: &'l [u32],
136 info: &'l Info,
137 },
138 DenseNode {
139 kv_pairs: &'l [i32],
140 info: &'l DenseInfo,
141 },
142}
143
144#[derive(Default)]
145struct DenseState {
146 id: i64,
147 lat: i64,
148 lon: i64,
149 kv_pos: usize,
150}
151
152impl WayRef<'_> {
153 #[inline]
154 pub fn tags(&self) -> Tags<'_> {
155 Tags {
156 kv: TagsData::Normal(self.value.keys.iter(), self.value.vals.iter()),
157 s: &self.block.stringtable.s,
158 }
159 }
160}
161
162impl RelationRef<'_> {
163 #[inline]
164 pub fn tags(&self) -> Tags<'_> {
165 Tags {
166 kv: TagsData::Normal(self.value.keys.iter(), self.value.vals.iter()),
167 s: &self.block.stringtable.s,
168 }
169 }
170}
171
172#[derive(Clone, Debug)]
173enum TagsData<'l> {
174 Normal(std::slice::Iter<'l, u32>, std::slice::Iter<'l, u32>),
175 Dense(std::slice::Iter<'l, i32>),
176}
177
178#[derive(Clone, Debug)]
179pub struct Tags<'l> {
180 kv: TagsData<'l>,
181 s: &'l [Bytes],
182}
183
184impl<'l> Tags<'l> {
185 pub fn get(&self, key: &str) -> Option<&'l str> {
186 let key = key.as_bytes();
187 let s = self.s;
188 match self.kv.clone() {
189 TagsData::Normal(mut keys, mut vals) => loop {
190 let key_index = keys.next().copied()? as usize;
191 if let Some(k) = s.get(key_index) {
192 if k == key {
193 let value_index = vals.next().copied()? as usize;
194 return s.get(value_index).and_then(|b| std::str::from_utf8(b).ok());
195 }
196 }
197 },
198 TagsData::Dense(mut kv_pairs) => loop {
199 let key_index = kv_pairs.next().copied()? as usize;
200 let value_index = kv_pairs.next().copied()? as usize;
201 if let Some(k) = s.get(key_index) {
202 if k == key {
203 return s.get(value_index).and_then(|b| std::str::from_utf8(b).ok());
204 }
205 }
206 },
207 }
208 }
209}
210
211impl<'l> Iterator for Tags<'l> {
212 type Item = (&'l str, &'l str);
213 #[inline]
214 fn next(&mut self) -> Option<Self::Item> {
215 let s = self.s;
216 loop {
217 let key_index;
218 let value_index;
219 match &mut self.kv {
220 TagsData::Normal(keys, vals) => {
221 key_index = keys.next().copied()? as usize;
222 value_index = vals.next().copied()? as usize;
223 }
224 TagsData::Dense(kv_pairs) => {
225 key_index = kv_pairs.next().copied()? as usize;
226 value_index = kv_pairs.next().copied()? as usize;
227 }
228 }
229 let Some(key) = s.get(key_index).and_then(|b| std::str::from_utf8(b).ok()) else {
231 continue;
232 };
233 let Some(value) = s.get(value_index).and_then(|b| std::str::from_utf8(b).ok()) else {
234 continue;
235 };
236 return Some((key, value));
237 }
238 }
239
240 #[inline]
241 fn size_hint(&self) -> (usize, Option<usize>) {
242 match &self.kv {
243 TagsData::Normal(keys, vals) => {
244 let (keys_lower, keys_upper) = keys.size_hint();
245 let (values_lower, values_upper) = vals.size_hint();
246 (
247 keys_lower.min(values_lower),
248 keys_upper.zip(values_upper).map(|(k, v)| k.min(v)),
249 )
250 }
251 TagsData::Dense(kv_pairs) => {
252 let (lower, upper) = kv_pairs.size_hint();
253 (lower / 2, upper.map(|l| l / 2))
254 }
255 }
256 }
257}
258
259impl<'l> std::iter::FusedIterator for Tags<'l> {}
260
261#[non_exhaustive]
262pub enum Primitive<'l> {
263 Node(NodeRef<'l>),
264 Way(WayRef<'l>),
265 Relation(RelationRef<'l>),
266 ChangeSet(ChangeSetRef<'l>),
267}
268
269pub struct PrimitivesIter<'l> {
270 block: &'l PrimitiveBlock,
271 groups: &'l [PrimitiveGroup],
272 filter: PrimitiveType,
273 group_pos: usize,
274 prim_pos: usize,
275 dense_state: DenseState,
276}
277
278impl PrimitiveBlock {
279 #[inline]
280 pub fn primitives(&self) -> PrimitivesIter<'_> {
281 PrimitivesIter {
282 block: self,
283 groups: &self.primitivegroup,
284 filter: PrimitiveType::DEFAULT,
285 group_pos: 0,
286 prim_pos: 0,
287 dense_state: DenseState::default(),
288 }
289 }
290 #[inline]
291 pub fn primitivegroup(&self, i: usize) -> Option<PrimitiveGroupRef<'_>> {
292 Some(PrimitiveGroupRef {
293 value: self.primitivegroup.get(i)?,
294 block: self,
295 })
296 }
297}
298
299impl<'l> PrimitiveGroupRef<'l> {
300 #[inline]
301 pub fn primitives(self) -> PrimitivesIter<'l> {
302 PrimitivesIter {
303 block: self.block,
304 groups: std::slice::from_ref(self.value),
305 filter: PrimitiveType::DEFAULT,
306 group_pos: 0,
307 prim_pos: 0,
308 dense_state: DenseState::default(),
309 }
310 }
311}
312
313impl<'l> PrimitivesIter<'l> {
314 #[inline]
315 pub fn filter_types(mut self, types: PrimitiveType) -> Self {
316 self.filter = types;
317 self
318 }
319}
320
321impl<'l> IntoIterator for &'l PrimitiveBlock {
322 type Item = Primitive<'l>;
323 type IntoIter = PrimitivesIter<'l>;
324 #[inline]
325 fn into_iter(self) -> PrimitivesIter<'l> {
326 self.primitives()
327 }
328}
329
330impl<'l> IntoIterator for PrimitiveGroupRef<'l> {
331 type Item = Primitive<'l>;
332 type IntoIter = PrimitivesIter<'l>;
333 #[inline]
334 fn into_iter(self) -> PrimitivesIter<'l> {
335 self.primitives()
336 }
337}
338
339impl<'l> Iterator for PrimitivesIter<'l> {
340 type Item = Primitive<'l>;
341 fn next(&mut self) -> Option<Self::Item> {
342 loop {
343 let group = self.groups.get(self.group_pos)?;
344 if self.filter.contains(PrimitiveType::NODE) && !group.nodes.is_empty() {
345 let index = self.prim_pos;
346 if let Some(n) = group.nodes.get(index) {
347 self.prim_pos = index + 1;
348 return Some(Primitive::Node(NodeRef::from_node(index, n, self.block)));
349 }
350 } else if self.filter.contains(PrimitiveType::NODE) && group.dense.is_some() {
351 let dense = &group.dense;
352 let index = self.prim_pos;
353 if let (Some(id), Some(lat), Some(lon)) = (
354 dense.id.get(index).copied(),
355 dense.lat.get(index).copied(),
356 dense.lon.get(index).copied(),
357 ) {
358 self.prim_pos = index + 1;
359 self.dense_state.id += id;
360 self.dense_state.lat += lat;
361 self.dense_state.lon += lon;
362
363 let kv_from = self.dense_state.kv_pos;
365 while let Some(k) = dense.keys_vals.get(self.dense_state.kv_pos).copied() {
366 if k == 0 {
367 self.dense_state.kv_pos += 1;
368 } else {
369 self.dense_state.kv_pos += 2;
370 }
371 }
372 let key_values = &dense.keys_vals[kv_from..self.dense_state.kv_pos];
373
374 let n = NodeRef::from_dense_node(
375 index,
376 &self.dense_state,
377 key_values,
378 &dense.denseinfo,
379 self.block,
380 );
381 return Some(Primitive::Node(n));
382 }
383 self.dense_state = DenseState::default();
385 } else if self.filter.contains(PrimitiveType::WAY) && !group.ways.is_empty() {
386 if let Some(w) = group.ways.get(self.prim_pos) {
387 self.prim_pos += 1;
388 return Some(Primitive::Way(PrimitiveRef {
389 value: w,
390 block: self.block,
391 }));
392 }
393 } else if self.filter.contains(PrimitiveType::RELATION) && !group.relations.is_empty() {
394 if let Some(r) = group.relations.get(self.prim_pos) {
395 self.prim_pos += 1;
396 return Some(Primitive::Relation(PrimitiveRef {
397 value: r,
398 block: self.block,
399 }));
400 }
401 } else if self.filter.contains(PrimitiveType::CHANGE_SET)
402 && !group.changesets.is_empty()
403 {
404 if let Some(c) = group.changesets.get(self.prim_pos) {
405 self.prim_pos += 1;
406 return Some(Primitive::ChangeSet(PrimitiveRef {
407 value: c,
408 block: self.block,
409 }));
410 }
411 }
412 self.group_pos += 1;
413 }
414 }
415}