1use std::fmt;
20
21use geo_types::Geometry;
22use usize_cast::IntoUsize as _;
23
24use crate::decoder::{Layer01, ParsedLayer01, ParsedProperty, ParsedScalar, RawProperty};
25use crate::{Lazy, LazyParsed, MltResult, Parsed};
26
27pub trait LendingIterator {
42 type Item<'this>
44 where
45 Self: 'this;
46
47 fn next(&mut self) -> Option<Self::Item<'_>>;
49}
50
51impl<'a> Layer01<'a, Lazy> {
52 pub fn iterate_prop_names(&self) -> impl Iterator<Item = PropName<'a>> + '_ {
60 let props = &self.properties;
61 let mut col_idx = 0;
62 let mut dict_idx = 0;
63 std::iter::from_fn(move || {
64 loop {
65 let idx = col_idx;
66 col_idx += 1;
67 let name = match props.get(idx)? {
68 LazyParsed::Raw(r) => raw_col_name(r, &mut dict_idx),
69 LazyParsed::Parsed(p) => parsed_col_name(p, &mut dict_idx),
70 LazyParsed::ParsingFailed => None,
71 };
72 if dict_idx != 0 {
73 col_idx -= 1;
74 }
75 if let Some(n) = name {
76 return Some(n);
77 }
78 }
79 })
80 }
81}
82
83impl<'a> ParsedLayer01<'a> {
84 #[must_use]
103 pub fn iter_features(&self) -> Layer01FeatureIter<'_, 'a> {
104 Layer01FeatureIter::new(self)
105 }
106
107 pub fn iterate_prop_names(&self) -> impl Iterator<Item = PropName<'a>> + '_ {
110 Layer01PropNamesIter::new(&self.properties)
111 }
112}
113
114#[derive(Debug, Clone, Copy)] pub struct PropName<'a>(&'a str, &'a str);
125
126impl fmt::Display for PropName<'_> {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.write_str(self.0)?;
129 f.write_str(self.1)
130 }
131}
132
133impl PartialEq<PropName<'_>> for PropName<'_> {
134 fn eq(&self, other: &PropName<'_>) -> bool {
135 let (a0, a1) = (self.0.as_bytes(), self.1.as_bytes());
137 let a = a0.iter().chain(a1);
138 let (b0, b1) = (other.0.as_bytes(), other.1.as_bytes());
139 let b = b0.iter().chain(b1);
140 let combined_len_eq = a0.len() + a1.len() == b0.len() + b1.len();
141 combined_len_eq && a.eq(b)
142 }
143}
144
145impl PartialEq<str> for PropName<'_> {
146 fn eq(&self, other: &str) -> bool {
148 other.strip_prefix(self.0) == Some(self.1)
149 }
150}
151
152impl PartialEq<PropName<'_>> for str {
153 fn eq(&self, other: &PropName<'_>) -> bool {
154 other == self
155 }
156}
157
158impl PartialEq<&str> for PropName<'_> {
159 fn eq(&self, other: &&str) -> bool {
160 self == *other
161 }
162}
163
164impl PartialEq<PropName<'_>> for &str {
165 fn eq(&self, other: &PropName<'_>) -> bool {
166 other == *self
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq)]
175pub enum PropValueRef<'a> {
176 Bool(bool),
177 I8(i8),
178 U8(u8),
179 I32(i32),
180 U32(u32),
181 I64(i64),
182 U64(u64),
183 F32(f32),
184 F64(f64),
185 Str(&'a str),
186}
187
188macro_rules! impl_from_for_prop_value_ref {
189 ($($ty:ty => $variant:ident),+ $(,)?) => {
190 $(impl From<$ty> for PropValueRef<'_> {
191 fn from(v: $ty) -> Self { Self::$variant(v) }
192 })+
193 };
194}
195impl_from_for_prop_value_ref!(
196 bool => Bool, i8 => I8, u8 => U8,
197 i32 => I32, u32 => U32,
198 i64 => I64, u64 => U64,
199 f32 => F32, f64 => F64,
200);
201
202#[derive(Debug, Clone, Copy, PartialEq)]
207pub struct ColumnRef<'a> {
208 pub name: PropName<'a>,
209 pub value: PropValueRef<'a>,
210}
211
212#[derive(Debug)]
217pub struct FeatureRef<'feat, 'layer: 'feat> {
218 pub id: Option<u64>,
220 pub geometry: Geometry<i32>,
222 columns: &'layer [ParsedProperty<'layer>],
224 values: &'feat [Option<PropValueRef<'layer>>],
227}
228
229impl<'feat, 'layer: 'feat> FeatureRef<'feat, 'layer> {
230 pub fn iter_all_properties(&self) -> impl Iterator<Item = Option<PropValueRef<'layer>>> + '_ {
238 self.values.iter().copied()
239 }
240
241 pub fn iter_properties(&self) -> impl Iterator<Item = ColumnRef<'layer>> + '_ {
246 Layer01PropNamesIter::new(self.columns)
247 .zip(self.values.iter().copied())
248 .filter_map(|(name, opt_val)| opt_val.map(|value| ColumnRef { name, value }))
249 }
250
251 #[must_use]
256 pub fn get_property(&self, name: &str) -> Option<PropValueRef<'layer>> {
257 self.iter_properties()
258 .find(|col| col.name == name)
259 .map(|col| col.value)
260 }
261}
262
263pub(crate) struct Layer01PropNamesIter<'a, 'p> {
270 props: &'a [ParsedProperty<'p>],
271 col_idx: usize,
272 dict_idx: usize,
273}
274
275impl<'a, 'p> Layer01PropNamesIter<'a, 'p> {
276 pub(crate) fn new(props: &'a [ParsedProperty<'p>]) -> Self {
277 Self {
278 props,
279 col_idx: 0,
280 dict_idx: 0,
281 }
282 }
283}
284
285impl<'a> Iterator for Layer01PropNamesIter<'_, 'a> {
286 type Item = PropName<'a>;
287
288 fn next(&mut self) -> Option<PropName<'a>> {
289 loop {
290 let col_idx = self.col_idx;
291 self.col_idx += 1;
292 let name = parsed_col_name(self.props.get(col_idx)?, &mut self.dict_idx);
293 if self.dict_idx != 0 {
294 self.col_idx -= 1; }
296 if let Some(n) = name {
297 return Some(n);
298 }
299 }
300 }
301}
302
303#[inline]
305fn parsed_col_name<'p>(prop: &ParsedProperty<'p>, dict_idx: &mut usize) -> Option<PropName<'p>> {
306 use ParsedProperty as P;
307 match prop {
308 P::Bool(s) => Some(PropName(s.name, "")),
309 P::I8(s) => Some(PropName(s.name, "")),
310 P::U8(s) => Some(PropName(s.name, "")),
311 P::I32(s) => Some(PropName(s.name, "")),
312 P::U32(s) => Some(PropName(s.name, "")),
313 P::I64(s) => Some(PropName(s.name, "")),
314 P::U64(s) => Some(PropName(s.name, "")),
315 P::F32(s) => Some(PropName(s.name, "")),
316 P::F64(s) => Some(PropName(s.name, "")),
317 P::Str(s) => Some(PropName(s.name, "")),
318 P::SharedDict(sd) => {
319 if *dict_idx < sd.items.len() {
320 let idx = *dict_idx;
321 *dict_idx += 1;
322 Some(PropName(sd.prefix, sd.items[idx].suffix))
323 } else {
324 *dict_idx = 0;
325 None
326 }
327 }
328 }
329}
330
331#[inline]
333fn raw_col_name<'p>(prop: &RawProperty<'p>, dict_idx: &mut usize) -> Option<PropName<'p>> {
334 use RawProperty as P;
335 match prop {
336 P::Bool(s)
337 | P::I8(s)
338 | P::U8(s)
339 | P::I32(s)
340 | P::U32(s)
341 | P::I64(s)
342 | P::U64(s)
343 | P::F32(s)
344 | P::F64(s) => Some(PropName(s.name, "")),
345 P::Str(s) => Some(PropName(s.name, "")),
346 P::SharedDict(sd) => {
347 if *dict_idx < sd.children.len() {
348 let idx = *dict_idx;
349 *dict_idx += 1;
350 Some(PropName(sd.name, sd.children[idx].name))
351 } else {
352 *dict_idx = 0;
353 None
354 }
355 }
356 }
357}
358
359type ColValIter<'l> = Box<dyn Iterator<Item = Option<PropValueRef<'l>>> + 'l>;
361
362fn build_col_iters<'p>(columns: &'p [ParsedProperty<'p>]) -> Vec<ColValIter<'p>> {
367 use ParsedProperty as PP;
368 let mut iters: Vec<ColValIter<'p>> = Vec::new();
369 for col in columns {
370 match col {
371 PP::Bool(s) => iters.push(scalar_col_iter(s)),
372 PP::I8(s) => iters.push(scalar_col_iter(s)),
373 PP::U8(s) => iters.push(scalar_col_iter(s)),
374 PP::I32(s) => iters.push(scalar_col_iter(s)),
375 PP::U32(s) => iters.push(scalar_col_iter(s)),
376 PP::I64(s) => iters.push(scalar_col_iter(s)),
377 PP::U64(s) => iters.push(scalar_col_iter(s)),
378 PP::F32(s) => iters.push(scalar_col_iter(s)),
379 PP::F64(s) => iters.push(scalar_col_iter(s)),
380 PP::Str(strings) => {
381 let data: &'p str = strings.data.as_ref();
382 let lengths: &'p [i32] = &strings.lengths;
383 let mut curr_end: usize = 0;
384 let mut feat_idx = 0usize;
385 iters.push(Box::new(std::iter::from_fn(move || {
386 let &end_i32 = lengths.get(feat_idx)?;
387 feat_idx += 1;
388 if end_i32 >= 0 {
389 let start = curr_end;
390 curr_end = end_i32.cast_unsigned().into_usize();
391 Some(data.get(start..curr_end).map(PropValueRef::Str))
392 } else {
393 Some(None)
395 }
396 })));
397 }
398 PP::SharedDict(dict) => {
399 for item in &dict.items {
400 let dict_ref: &'p _ = dict;
401 let item_ref: &'p _ = item;
402 let mut feat_idx = 0usize;
403 iters.push(Box::new(std::iter::from_fn(move || {
404 if feat_idx >= item_ref.ranges.len() {
405 return None;
406 }
407 let idx = feat_idx;
408 feat_idx += 1;
409 Some(item_ref.get(dict_ref, idx).map(PropValueRef::Str))
410 })));
411 }
412 }
413 }
414 }
415 iters
416}
417
418fn scalar_col_iter<'p, T>(scalar: &'p ParsedScalar<'p, T>) -> ColValIter<'p>
420where
421 T: Copy + PartialEq,
422 PropValueRef<'p>: From<T>,
423{
424 Box::new(scalar.iter_optional().map(|o| o.map(PropValueRef::from)))
425}
426
427pub struct Layer01FeatureIter<'layer, 'data: 'layer> {
437 layer: &'layer Layer01<'data, Parsed>,
438 index: usize,
439 feature_count: usize,
440 id_iter: Option<crate::utils::PresenceOptIter<'layer, u64>>,
442 col_iters: Vec<ColValIter<'layer>>,
444 values_buf: Vec<Option<PropValueRef<'layer>>>,
446}
447
448impl<'layer, 'data: 'layer> Layer01FeatureIter<'layer, 'data> {
449 fn new(layer: &'layer Layer01<'data, Parsed>) -> Self {
450 let col_iters = build_col_iters(&layer.properties);
451 let cap = col_iters.len();
452 Self {
453 layer,
454 index: 0,
455 feature_count: layer.feature_count(),
456 id_iter: layer.id.as_ref().map(|id| id.iter_optional()),
457 col_iters,
458 values_buf: Vec::with_capacity(cap),
459 }
460 }
461
462 #[must_use]
464 pub fn len(&self) -> usize {
465 self.feature_count - self.index
466 }
467
468 #[must_use]
470 pub fn is_empty(&self) -> bool {
471 self.index >= self.feature_count
472 }
473}
474
475impl<'layer> LendingIterator for Layer01FeatureIter<'layer, '_> {
476 type Item<'this>
477 = MltResult<FeatureRef<'this, 'layer>>
478 where
479 Self: 'this;
480
481 fn next(&mut self) -> Option<Self::Item<'_>> {
482 let index = self.index;
483 if index >= self.feature_count {
484 return None;
485 }
486 self.index += 1;
487
488 let id = self.id_iter.as_mut().and_then(Iterator::next).flatten();
491 self.values_buf.clear();
492 self.values_buf
493 .extend(self.col_iters.iter_mut().map(|it| it.next().flatten()));
494
495 Some(
496 self.layer
497 .geometry
498 .to_geojson(index)
499 .map(|geometry| FeatureRef {
500 id,
501 geometry,
502 columns: &self.layer.properties,
503 values: &self.values_buf,
504 }),
505 )
506 }
507}
508
509#[cfg(test)]
510mod tests {
511 use geo_types::Point;
512 use serde_json::Value;
513
514 use super::*;
515 use crate::Layer;
516 use crate::decoder::GeometryValues;
517 use crate::encoder::model::StagedLayer;
518 use crate::encoder::{Codecs, Encoder, Presence, StagedId, StagedProperty, StagedSharedDict};
519 use crate::test_helpers::{dec, parser};
520
521 fn layer_buf(staged: StagedLayer) -> Vec<u8> {
522 staged
523 .encode_into(Encoder::default(), &mut Codecs::default())
524 .unwrap()
525 .into_layer_bytes()
526 .unwrap()
527 }
528
529 fn three_points() -> GeometryValues {
530 let mut g = GeometryValues::default();
531 g.push_geom(&Geometry::<i32>::Point(Point::new(1, 2)));
532 g.push_geom(&Geometry::<i32>::Point(Point::new(3, 4)));
533 g.push_geom(&Geometry::<i32>::Point(Point::new(5, 6)));
534 g
535 }
536
537 fn empty_layer(name: &str) -> StagedLayer {
538 StagedLayer {
539 name: name.to_string(),
540 extent: 4096,
541 id: StagedId::None,
542 geometry: GeometryValues::default(),
543 properties: vec![],
544 }
545 }
546
547 #[test]
548 fn prop_name_display_concatenates_parts() {
549 assert_eq!(PropName("addr:", "city").to_string(), "addr:city");
550 assert_eq!(PropName("name", "").to_string(), "name");
551 assert_eq!(PropName("", "").to_string(), "");
552 }
553
554 #[test]
555 fn prop_name_eq_str_matches_concatenation() {
556 assert_eq!(PropName("addr:", "city"), "addr:city");
557 assert_eq!("addr:city", PropName("addr:", "city"));
558 assert_ne!(PropName("addr:", "city"), "addr:");
559 assert_ne!(PropName("addr:", "city"), "city");
560 assert_eq!(PropName("name", ""), "name");
561 }
562
563 #[test]
564 fn prop_name_structural_eq_is_part_wise() {
565 assert_eq!(PropName("a", "b"), PropName("a", "b"));
566 assert_eq!(PropName("ab", ""), PropName("a", "b"));
567 }
568
569 #[test]
570 fn prop_name_eq_prop_name_semantic_equality() {
571 assert_eq!(PropName("ab", ""), PropName("a", "b"));
572 assert_eq!(PropName("", "ab"), PropName("a", "b"));
573 assert_eq!(PropName("abc", "def"), PropName("ab", "cdef"));
574 assert_eq!(PropName("a", "bcdef"), PropName("abcde", "f"));
575
576 assert_ne!(PropName("a", "b"), PropName("a", "c"));
577 assert_ne!(PropName("a", "b"), PropName("ab", "c"));
578 assert_ne!(PropName("abc", ""), PropName("ab", ""));
579 }
580
581 #[test]
582 fn prop_value_ref_scalars_convert_to_json() {
583 assert_eq!(Value::from(PropValueRef::Bool(true)), Value::Bool(true));
584 assert_eq!(Value::from(PropValueRef::Bool(false)), Value::Bool(false));
585 assert_eq!(Value::from(PropValueRef::I8(-1)), Value::from(-1_i8));
586 assert_eq!(Value::from(PropValueRef::U8(255)), Value::from(255_u8));
587 assert_eq!(
588 Value::from(PropValueRef::I32(-1000)),
589 Value::from(-1000_i32)
590 );
591 assert_eq!(Value::from(PropValueRef::U32(1000)), Value::from(1000_u32));
592 assert_eq!(
593 Value::from(PropValueRef::I64(i64::MIN)),
594 Value::from(i64::MIN)
595 );
596 assert_eq!(
597 Value::from(PropValueRef::U64(u64::MAX)),
598 Value::from(u64::MAX)
599 );
600 assert_eq!(
601 Value::from(PropValueRef::Str("hello")),
602 Value::String("hello".into())
603 );
604 }
605
606 #[test]
607 fn prop_value_ref_float_finite_is_number() {
608 assert!(matches!(
609 Value::from(PropValueRef::F32(1.5)),
610 Value::Number(_)
611 ));
612 assert!(matches!(
613 Value::from(PropValueRef::F64(2.5)),
614 Value::Number(_)
615 ));
616 }
617
618 #[test]
619 fn prop_value_ref_float_non_finite_becomes_string_sentinel() {
620 assert_eq!(
621 Value::from(PropValueRef::F32(f32::NAN)),
622 Value::String("f32::NAN".into())
623 );
624 assert_eq!(
625 Value::from(PropValueRef::F32(f32::INFINITY)),
626 Value::String("f32::INFINITY".into())
627 );
628 assert_eq!(
629 Value::from(PropValueRef::F64(f64::NAN)),
630 Value::String("f64::NAN".into())
631 );
632 assert_eq!(
633 Value::from(PropValueRef::F64(f64::NEG_INFINITY)),
634 Value::String("f64::NEG_INFINITY".into())
635 );
636 }
637
638 #[test]
639 fn empty_layer_yields_no_features() {
640 let buf = layer_buf(empty_layer("empty"));
641 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
642 let Layer::Tag01(lazy) = layer else {
643 panic!("expected Tag01")
644 };
645 let parsed = lazy.decode_all(&mut dec()).unwrap();
646
647 let iter = parsed.iter_features();
648 assert_eq!(iter.len(), 0);
649 assert!(iter.is_empty());
650 assert_eq!(parsed.iter_features().len(), 0);
651 }
652
653 #[test]
654 fn len_decreases_with_each_next() {
655 let buf = layer_buf(StagedLayer {
656 name: "test".into(),
657 extent: 4096,
658 id: StagedId::None,
659 geometry: three_points(),
660 properties: vec![],
661 });
662 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
663 let Layer::Tag01(lazy) = layer else { panic!() };
664 let parsed = lazy.decode_all(&mut dec()).unwrap();
665
666 let mut iter = parsed.iter_features();
667 assert_eq!(iter.len(), 3);
668 iter.next().unwrap().unwrap();
669 assert_eq!(iter.len(), 2);
670 iter.next().unwrap().unwrap();
671 assert_eq!(iter.len(), 1);
672 iter.next().unwrap().unwrap();
673 assert_eq!(iter.len(), 0);
674 assert!(iter.is_empty());
675 assert!(iter.next().is_none());
676 }
677
678 #[test]
679 fn feature_ids_are_preserved() {
680 let buf = layer_buf(StagedLayer {
681 name: "test".into(),
682 extent: 4096,
683 id: StagedId::from_optional(vec![Some(100), None, Some(200)]),
684 geometry: three_points(),
685 properties: vec![],
686 });
687 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
688 let Layer::Tag01(lazy) = layer else { panic!() };
689 let parsed = lazy.decode_all(&mut dec()).unwrap();
690
691 let mut ids = Vec::new();
692 let mut iter = parsed.iter_features();
693 while let Some(r) = iter.next() {
694 ids.push(r.unwrap().id);
695 }
696 assert_eq!(ids, [Some(100), None, Some(200)]);
697 }
698
699 #[test]
700 fn geometry_values_match_input() {
701 let buf = layer_buf(StagedLayer {
702 name: "test".into(),
703 extent: 4096,
704 id: StagedId::None,
705 geometry: three_points(),
706 properties: vec![],
707 });
708 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
709 let Layer::Tag01(lazy) = layer else { panic!() };
710 let parsed = lazy.decode_all(&mut dec()).unwrap();
711
712 let mut geoms = Vec::new();
713 let mut iter = parsed.iter_features();
714 while let Some(r) = iter.next() {
715 geoms.push(r.unwrap().geometry);
716 }
717 assert_eq!(geoms[0], Geometry::<i32>::Point(Point::new(1, 2)));
718 assert_eq!(geoms[1], Geometry::<i32>::Point(Point::new(3, 4)));
719 assert_eq!(geoms[2], Geometry::<i32>::Point(Point::new(5, 6)));
720 }
721
722 #[test]
723 fn null_scalar_values_are_skipped() {
724 let buf = layer_buf(StagedLayer {
725 name: "test".into(),
726 extent: 4096,
727 id: StagedId::None,
728 geometry: three_points(),
729 properties: vec![StagedProperty::opt_u32("n", vec![Some(1), None, Some(3)])],
730 });
731 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
732 let Layer::Tag01(lazy) = layer else { panic!() };
733 let parsed = lazy.decode_all(&mut dec()).unwrap();
734
735 let mut iter = parsed.iter_features();
736
737 {
738 let feat = iter.next().unwrap().unwrap();
739 let cols: Vec<_> = feat.iter_properties().collect();
740 assert_eq!(cols.len(), 1);
741 assert_eq!(cols[0].name, PropName("n", ""));
742 assert_eq!(cols[0].name, "n");
743 assert_eq!(cols[0].value, PropValueRef::U32(1));
744 let all: Vec<_> = feat.iter_all_properties().collect();
745 assert_eq!(all, [Some(PropValueRef::U32(1))]);
746 }
747 {
748 let feat = iter.next().unwrap().unwrap();
749 assert!(feat.iter_properties().next().is_none());
750 let all: Vec<_> = feat.iter_all_properties().collect();
751 assert_eq!(all, [None]);
752 }
753 {
754 let feat = iter.next().unwrap().unwrap();
755 assert_eq!(feat.get_property("n"), Some(PropValueRef::U32(3)));
756 let all: Vec<_> = feat.iter_all_properties().collect();
757 assert_eq!(all, [Some(PropValueRef::U32(3))]);
758 }
759
760 let names: Vec<_> = parsed.iterate_prop_names().map(|n| n.to_string()).collect();
761 assert_eq!(names, ["n"]);
762 }
763
764 #[test]
765 fn null_string_values_are_skipped() {
766 let buf = layer_buf(StagedLayer {
767 name: "test".into(),
768 extent: 4096,
769 id: StagedId::None,
770 geometry: three_points(),
771 properties: vec![StagedProperty::opt_str(
772 "label",
773 vec![Some("foo"), None, Some("bar")],
774 )],
775 });
776 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
777 let Layer::Tag01(lazy) = layer else { panic!() };
778 let parsed = lazy.decode_all(&mut dec()).unwrap();
779
780 let mut iter = parsed.iter_features();
781 {
782 let feat = iter.next().unwrap().unwrap();
783 assert_eq!(feat.get_property("label"), Some(PropValueRef::Str("foo")));
784 }
785 {
786 let feat = iter.next().unwrap().unwrap();
787 assert_eq!(feat.get_property("label"), None);
788 }
789 {
790 let feat = iter.next().unwrap().unwrap();
791 assert_eq!(feat.get_property("label"), Some(PropValueRef::Str("bar")));
792 }
793 }
794
795 #[test]
796 fn multiple_columns_independently_nullable() {
797 let buf = layer_buf(StagedLayer {
798 name: "test".into(),
799 extent: 4096,
800 id: StagedId::None,
801 geometry: three_points(),
802 properties: vec![
803 StagedProperty::opt_bool("flag", vec![Some(true), Some(false), None]),
804 StagedProperty::opt_i32("score", vec![None, Some(-5), Some(7)]),
805 ],
806 });
807 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
808 let Layer::Tag01(lazy) = layer else { panic!() };
809 let parsed = lazy.decode_all(&mut dec()).unwrap();
810
811 let mut iter = parsed.iter_features();
812
813 {
815 let feat = iter.next().unwrap().unwrap();
816 assert_eq!(feat.iter_properties().count(), 1);
817 assert_eq!(feat.get_property("flag"), Some(PropValueRef::Bool(true)));
818 assert_eq!(feat.get_property("score"), None);
819 }
820 {
822 let feat = iter.next().unwrap().unwrap();
823 assert_eq!(feat.iter_properties().count(), 2);
824 assert_eq!(feat.get_property("flag"), Some(PropValueRef::Bool(false)));
825 assert_eq!(feat.get_property("score"), Some(PropValueRef::I32(-5)));
826 }
827 {
829 let feat = iter.next().unwrap().unwrap();
830 assert_eq!(feat.iter_properties().count(), 1);
831 assert_eq!(feat.get_property("flag"), None);
832 assert_eq!(feat.get_property("score"), Some(PropValueRef::I32(7)));
833 }
834 }
835
836 #[test]
837 fn geometry_error_does_not_misalign_ids() {
838 use crate::decoder::GeometryType;
839
840 let buf = layer_buf(StagedLayer {
841 name: "test".into(),
842 extent: 4096,
843 id: StagedId::from_optional(vec![Some(10), Some(20), Some(30)]),
844 geometry: three_points(),
845 properties: vec![],
846 });
847 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
848 let Layer::Tag01(lazy) = layer else { panic!() };
849 let mut parsed = lazy.decode_all(&mut dec()).unwrap();
850
851 parsed.geometry.vector_types[1] = GeometryType::LineString;
855
856 let mut iter = parsed.iter_features();
857
858 let feat0 = iter.next().unwrap().unwrap();
860 assert_eq!(feat0.id, Some(10));
861
862 assert!(iter.next().unwrap().is_err());
864
865 let feat2 = iter.next().unwrap().unwrap();
867 assert_eq!(
868 feat2.id,
869 Some(30),
870 "id cursor was not advanced on geometry error"
871 );
872
873 assert!(iter.next().is_none());
874 }
875
876 #[test]
877 fn get_property_absent_column_returns_none() {
878 let buf = layer_buf(StagedLayer {
879 name: "test".into(),
880 extent: 4096,
881 id: StagedId::None,
882 geometry: three_points(),
883 properties: vec![StagedProperty::u32("x", vec![1, 2, 3])],
884 });
885 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
886 let Layer::Tag01(lazy) = layer else { panic!() };
887 let parsed = lazy.decode_all(&mut dec()).unwrap();
888
889 let mut iter = parsed.iter_features();
890 let feat = iter.next().unwrap().unwrap();
891 assert_eq!(feat.get_property("no_such_column"), None);
892 }
893
894 #[test]
895 fn shared_dict_columns_are_expanded() {
896 let shared_dict = StagedSharedDict::new(
897 "addr:",
898 [
899 (
900 "city",
901 vec![Some("Paris"), Some("Rome"), None],
902 Presence::Mixed,
903 ),
904 (
905 "zip",
906 vec![Some("75001"), None, Some("00100")],
907 Presence::Mixed,
908 ),
909 ],
910 )
911 .unwrap();
912
913 let buf = layer_buf(StagedLayer {
914 name: "test".into(),
915 extent: 4096,
916 id: StagedId::None,
917 geometry: three_points(),
918 properties: vec![StagedProperty::SharedDict(shared_dict)],
919 });
920 let (_, layer) = Layer::from_bytes(&buf, &mut parser()).unwrap();
921 let Layer::Tag01(lazy) = layer else { panic!() };
922 let parsed = lazy.decode_all(&mut dec()).unwrap();
923
924 let mut iter = parsed.iter_features();
925
926 {
928 let feat = iter.next().unwrap().unwrap();
929 assert_eq!(
930 feat.get_property("addr:city"),
931 Some(PropValueRef::Str("Paris"))
932 );
933 assert_eq!(
934 feat.get_property("addr:zip"),
935 Some(PropValueRef::Str("75001"))
936 );
937 assert_eq!(feat.iter_properties().count(), 2);
938 }
939 {
941 let feat = iter.next().unwrap().unwrap();
942 assert_eq!(
943 feat.get_property("addr:city"),
944 Some(PropValueRef::Str("Rome"))
945 );
946 assert_eq!(feat.get_property("addr:zip"), None);
947 assert_eq!(feat.iter_properties().count(), 1);
948 let all: Vec<_> = feat.iter_all_properties().collect();
950 assert_eq!(all, [Some(PropValueRef::Str("Rome")), None]);
951 }
952 {
954 let feat = iter.next().unwrap().unwrap();
955 assert_eq!(feat.get_property("addr:city"), None);
956 assert_eq!(
957 feat.get_property("addr:zip"),
958 Some(PropValueRef::Str("00100"))
959 );
960 }
961
962 let names: Vec<_> = parsed.iterate_prop_names().map(|n| n.to_string()).collect();
963 assert_eq!(names, ["addr:city", "addr:zip"]);
964 }
965}