1#[cfg(feature = "unstable-v2")]
9use std::collections::BTreeMap;
10use std::num::NonZeroU32;
11
12use geo_types::{Coord, Geometry, LineString};
13#[cfg(feature = "unstable-v2")]
14use num_traits::ToPrimitive as _;
15
16use crate::{MltError, MltResult};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub struct Extent(NonZeroU32);
24
25impl Extent {
26 pub fn new(value: u32) -> MltResult<Self> {
27 NonZeroU32::new(value)
28 .map(Self)
29 .ok_or(MltError::InvalidExtent(value))
30 }
31
32 #[must_use]
33 pub fn get(self) -> u32 {
34 self.0.get()
35 }
36}
37
38impl From<Extent> for NonZeroU32 {
39 fn from(value: Extent) -> Self {
40 value.0
41 }
42}
43
44#[cfg(feature = "unstable-v2")]
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49pub struct ZStep(i8);
50
51#[cfg(feature = "unstable-v2")]
52impl ZStep {
53 pub const MIN_EXPONENT: i8 = -3;
55 pub const MAX_EXPONENT: i8 = 4;
57 pub const BASE_METRES: f64 = -10_000.0;
59
60 pub fn new(exponent: i8) -> MltResult<Self> {
62 if (Self::MIN_EXPONENT..=Self::MAX_EXPONENT).contains(&exponent) {
63 Ok(Self(exponent))
64 } else {
65 Err(MltError::InvalidZStep(exponent))
66 }
67 }
68
69 #[must_use]
70 pub fn exponent(self) -> i8 {
71 self.0
72 }
73
74 pub(crate) fn code(self) -> u8 {
76 (self.0 - Self::MIN_EXPONENT).cast_unsigned()
77 }
78
79 pub(crate) fn from_code(code: u8) -> MltResult<Self> {
81 i8::try_from(code)
82 .ok()
83 .and_then(|c| Self::new(c + Self::MIN_EXPONENT).ok())
84 .ok_or(MltError::InvalidZStepCode(code))
85 }
86
87 #[must_use]
89 pub fn metres(self) -> f64 {
90 if self.0 < 0 {
91 1.0 / self.power()
92 } else {
93 self.power()
94 }
95 }
96
97 #[must_use]
101 pub fn elevation(self, z: i32) -> f64 {
102 let power = self.power();
103 if self.0 < 0 {
104 (f64::from(z) + Self::BASE_METRES * power) / power
105 } else {
106 Self::BASE_METRES + f64::from(z) * power
107 }
108 }
109
110 #[must_use]
112 pub fn z(self, elevation: f64) -> Option<i32> {
113 let power = self.power();
114 let z = if self.0 < 0 {
115 elevation * power - Self::BASE_METRES * power
116 } else {
117 (elevation - Self::BASE_METRES) / power
118 };
119 z.round().to_i32()
120 }
121
122 fn power(self) -> f64 {
124 10f64.powi(self.0.unsigned_abs().into())
125 }
126}
127
128#[cfg(feature = "unstable-v2")]
130impl std::fmt::Display for ZStep {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 f.write_str(match self.0 {
133 -3 => "1 mm",
134 -2 => "1 cm",
135 -1 => "1 dm",
136 0 => "1 m",
137 1 => "10 m",
138 2 => "100 m",
139 3 => "1 km",
140 _ => "10 km",
141 })
142 }
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display)]
147pub enum ColumnRole {
148 #[strum(serialize = "property")]
150 Property,
151 #[cfg(feature = "unstable-v2")]
153 #[strum(serialize = "m-value")]
154 MValue,
155 #[cfg(feature = "unstable-v2")]
157 #[strum(serialize = "nested")]
158 Nested,
159}
160
161#[derive(Debug, Clone, PartialEq)]
167pub struct TileLayer {
168 pub(crate) name: String,
169 pub(crate) extent: Extent,
170 pub(crate) property_names: Vec<String>,
172 pub(crate) property_kinds: Vec<PropKind>,
174 #[cfg(feature = "unstable-v2")]
176 pub(crate) m_value_names: Vec<String>,
177 #[cfg(feature = "unstable-v2")]
179 pub(crate) m_value_kinds: Vec<PropKind>,
180 #[cfg(feature = "unstable-v2")]
182 pub(crate) nested_names: Vec<String>,
183 #[cfg(feature = "unstable-v2")]
185 pub(crate) nested_kinds: Vec<NestedKind>,
186 #[cfg(feature = "unstable-v2")]
188 pub(crate) z_step: Option<ZStep>,
189 pub(crate) features: Vec<TileFeature>,
190}
191
192#[derive(Debug, Clone, PartialEq)]
194pub struct TileFeature {
195 pub(crate) id: Option<u64>,
196 pub(crate) geometry: Geometry<i32>,
198 pub(crate) properties: Vec<PropValue>,
201 #[cfg(feature = "unstable-v2")]
205 pub(crate) m_values: Vec<MValue>,
206 #[cfg(feature = "unstable-v2")]
208 pub(crate) nested: Vec<NestedValue>,
209 #[cfg(feature = "unstable-v2")]
211 pub(crate) z: Vec<i32>,
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
215pub struct PropertyKey(usize);
216
217impl PropertyKey {
218 pub(crate) const fn new(index: usize) -> Self {
219 Self(index)
220 }
221
222 #[must_use]
223 pub fn index(self) -> usize {
224 self.0
225 }
226}
227
228#[cfg(feature = "unstable-v2")]
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
231pub struct MValueKey(usize);
232
233#[cfg(feature = "unstable-v2")]
234impl MValueKey {
235 #[must_use]
236 pub fn index(self) -> usize {
237 self.0
238 }
239}
240
241#[cfg(feature = "unstable-v2")]
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
244pub struct NestedKey(usize);
245
246#[cfg(feature = "unstable-v2")]
247impl NestedKey {
248 #[must_use]
249 pub fn index(self) -> usize {
250 self.0
251 }
252}
253
254#[cfg(feature = "unstable-v2")]
256pub(crate) const MAX_NESTED_DEPTH: usize = 8;
257
258#[cfg(feature = "unstable-v2")]
260#[derive(Debug, Clone, PartialEq, Eq)]
261pub enum NestedKind {
262 Leaf(PropKind),
263 List(Box<Self>),
264 Map(BTreeMap<String, Self>),
266}
267
268#[cfg(feature = "unstable-v2")]
269impl NestedKind {
270 #[must_use]
272 pub fn map<K: Into<String>>(fields: impl IntoIterator<Item = (K, Self)>) -> Self {
273 Self::Map(fields.into_iter().map(|(k, v)| (k.into(), v)).collect())
274 }
275
276 #[must_use]
278 pub fn list(element: Self) -> Self {
279 Self::List(Box::new(element))
280 }
281
282 #[must_use]
284 pub fn depth(&self) -> usize {
285 1 + match self {
286 Self::Leaf(_) => 0,
287 Self::List(element) => element.depth(),
288 Self::Map(fields) => fields.values().map(Self::depth).max().unwrap_or(0),
289 }
290 }
291
292 #[must_use]
294 pub fn null_value(&self) -> NestedValue {
295 match self {
296 Self::Leaf(kind) => NestedValue::Leaf(PropValue::null(*kind)),
297 Self::List(_) => NestedValue::List(None),
298 Self::Map(_) => NestedValue::Map(None),
299 }
300 }
301
302 #[must_use]
306 pub fn accepts(&self, value: &NestedValue) -> bool {
307 match (self, value) {
308 (Self::Leaf(kind), NestedValue::Leaf(value)) => value.kind() == *kind,
309 (Self::List(_), NestedValue::List(None)) | (Self::Map(_), NestedValue::Map(None)) => {
310 true
311 }
312 (Self::List(element), NestedValue::List(Some(items))) => {
313 items.iter().all(|item| element.accepts(item))
314 }
315 (Self::Map(fields), NestedValue::Map(Some(entries))) => entries
316 .iter()
317 .all(|(key, value)| fields.get(key).is_some_and(|kind| kind.accepts(value))),
318 _ => false,
319 }
320 }
321
322 fn has_empty_map(&self) -> bool {
324 match self {
325 Self::Leaf(_) => false,
326 Self::List(element) => element.has_empty_map(),
327 Self::Map(fields) => fields.is_empty() || fields.values().any(Self::has_empty_map),
328 }
329 }
330}
331
332#[cfg(feature = "unstable-v2")]
336#[derive(Debug, Clone, PartialEq)]
337pub enum NestedValue {
338 Leaf(PropValue),
339 List(Option<Vec<Self>>),
340 Map(Option<BTreeMap<String, Self>>),
341}
342
343#[cfg(feature = "unstable-v2")]
344impl NestedValue {
345 #[must_use]
347 pub fn map<K: Into<String>>(entries: impl IntoIterator<Item = (K, Self)>) -> Self {
348 Self::Map(Some(
349 entries.into_iter().map(|(k, v)| (k.into(), v)).collect(),
350 ))
351 }
352
353 #[must_use]
355 pub fn list(items: impl IntoIterator<Item = Self>) -> Self {
356 Self::List(Some(items.into_iter().collect()))
357 }
358
359 #[must_use]
361 pub fn is_null(&self) -> bool {
362 match self {
363 Self::Leaf(value) => value.is_null(),
364 Self::List(items) => items.is_none(),
365 Self::Map(entries) => entries.is_none(),
366 }
367 }
368
369 #[must_use]
371 pub(crate) fn heap_bytes(&self) -> usize {
372 match self {
373 Self::Leaf(PropValue::Str(Some(value))) => value.len(),
374 Self::Leaf(_) => size_of::<PropValue>(),
375 Self::List(items) => items.iter().flatten().map(Self::heap_bytes).sum::<usize>(),
376 Self::Map(entries) => entries
377 .iter()
378 .flatten()
379 .map(|(key, value)| key.len() + value.heap_bytes())
380 .sum(),
381 }
382 }
383
384 fn same_shape(&self, other: &Self) -> bool {
387 matches!(
388 (self, other),
389 (Self::Leaf(_), Self::Leaf(_))
390 | (Self::List(_), Self::List(_))
391 | (Self::Map(_), Self::Map(_))
392 )
393 }
394}
395
396impl TileLayer {
397 pub fn new(name: impl Into<String>, extent: u32) -> MltResult<Self> {
398 Self::with_capacity(name, extent, 0)
399 }
400
401 pub fn with_capacity(name: impl Into<String>, extent: u32, features: usize) -> MltResult<Self> {
402 let name = name.into();
403 validate_layer_name(&name)?;
404 let extent = Extent::new(extent)?;
405 Ok(Self {
406 name,
407 extent,
408 property_names: Vec::new(),
409 property_kinds: Vec::new(),
410 #[cfg(feature = "unstable-v2")]
411 m_value_names: Vec::new(),
412 #[cfg(feature = "unstable-v2")]
413 m_value_kinds: Vec::new(),
414 #[cfg(feature = "unstable-v2")]
415 nested_names: Vec::new(),
416 #[cfg(feature = "unstable-v2")]
417 nested_kinds: Vec::new(),
418 #[cfg(feature = "unstable-v2")]
419 z_step: None,
420 features: Vec::with_capacity(features),
421 })
422 }
423
424 pub(crate) fn from_parts(
425 name: impl Into<String>,
426 extent: u32,
427 property_names: Vec<String>,
428 features: Vec<TileFeature>,
429 ) -> MltResult<Self> {
430 let name = name.into();
431 validate_layer_name(&name)?;
432 let extent = Extent::new(extent)?;
433 validate_unique_names(&property_names, ColumnRole::Property)?;
434 let property_kinds = infer_kinds::<PropValue>(&property_names, &features)?;
435 let layer = Self {
436 name,
437 extent,
438 property_names,
439 property_kinds,
440 #[cfg(feature = "unstable-v2")]
441 m_value_names: Vec::new(),
442 #[cfg(feature = "unstable-v2")]
443 m_value_kinds: Vec::new(),
444 #[cfg(feature = "unstable-v2")]
445 nested_names: Vec::new(),
446 #[cfg(feature = "unstable-v2")]
447 nested_kinds: Vec::new(),
448 #[cfg(feature = "unstable-v2")]
449 z_step: None,
450 features,
451 };
452 Ok(layer)
453 }
454
455 #[must_use]
456 pub fn name(&self) -> &str {
457 &self.name
458 }
459
460 #[must_use]
461 pub fn extent(&self) -> Extent {
462 self.extent
463 }
464
465 #[must_use]
466 pub fn property_names(&self) -> &[String] {
467 &self.property_names
468 }
469
470 #[must_use]
471 pub fn property_kinds(&self) -> &[PropKind] {
472 &self.property_kinds
473 }
474
475 #[must_use]
476 pub fn features(&self) -> &[TileFeature] {
477 &self.features
478 }
479
480 #[must_use]
481 pub fn feature_count(&self) -> usize {
482 self.features.len()
483 }
484
485 fn reject_name_in_use(&self, name: &str, role: ColumnRole) -> MltResult<()> {
487 let taken = self
488 .property_names
489 .iter()
490 .map(|n| (n.as_str(), ColumnRole::Property));
491 #[cfg(feature = "unstable-v2")]
492 let taken = taken
493 .chain(
494 self.m_value_names
495 .iter()
496 .map(|n| (n.as_str(), ColumnRole::MValue)),
497 )
498 .chain(
499 self.nested_names
500 .iter()
501 .map(|n| (n.as_str(), ColumnRole::Nested)),
502 );
503 reject_taken_name(name, role, taken)
504 }
505
506 pub fn add_property(
507 &mut self,
508 name: impl Into<String>,
509 kind: PropKind,
510 ) -> MltResult<PropertyKey> {
511 let name = name.into();
512 self.reject_name_in_use(&name, ColumnRole::Property)?;
513 for feature in &mut self.features {
514 feature.properties.push(PropValue::null(kind));
515 }
516 self.property_names.push(name);
517 self.property_kinds.push(kind);
518 Ok(PropertyKey(self.property_names.len() - 1))
519 }
520
521 #[cfg(feature = "unstable-v2")]
522 #[must_use]
523 pub fn m_value_names(&self) -> &[String] {
524 &self.m_value_names
525 }
526
527 #[cfg(feature = "unstable-v2")]
528 #[must_use]
529 pub fn m_value_kinds(&self) -> &[PropKind] {
530 &self.m_value_kinds
531 }
532
533 #[cfg(feature = "unstable-v2")]
535 pub fn add_m_value(&mut self, name: impl Into<String>, kind: PropKind) -> MltResult<MValueKey> {
536 let name = name.into();
537 self.reject_name_in_use(&name, ColumnRole::MValue)?;
538 for feature in &mut self.features {
539 feature.m_values.push(MValue::null(kind));
540 }
541 self.m_value_names.push(name);
542 self.m_value_kinds.push(kind);
543 Ok(MValueKey(self.m_value_names.len() - 1))
544 }
545
546 #[cfg(feature = "unstable-v2")]
549 pub(crate) fn with_m_value_names(mut self, names: Vec<String>) -> MltResult<Self> {
550 validate_unique_names(&names, ColumnRole::MValue)?;
551 for name in &names {
552 self.reject_name_in_use(name, ColumnRole::MValue)?;
553 }
554 self.m_value_kinds = infer_kinds::<MValue>(&names, &self.features)?;
555 self.m_value_names = names;
556 for feature in &self.features {
557 self.validate_m_values(feature)?;
558 }
559 Ok(self)
560 }
561
562 #[cfg(feature = "unstable-v2")]
563 #[must_use]
564 pub fn nested_names(&self) -> &[String] {
565 &self.nested_names
566 }
567
568 #[cfg(feature = "unstable-v2")]
569 #[must_use]
570 pub fn nested_kinds(&self) -> &[NestedKind] {
571 &self.nested_kinds
572 }
573
574 #[cfg(feature = "unstable-v2")]
576 #[must_use]
577 pub fn z_step(&self) -> Option<ZStep> {
578 self.z_step
579 }
580
581 #[cfg(feature = "unstable-v2")]
585 pub fn set_z_step(&mut self, step: ZStep) -> MltResult<()> {
586 if !self.features.is_empty() {
587 return Err(MltError::ZStepOnNonEmptyLayer(self.name.clone()));
588 }
589 self.z_step = Some(step);
590 Ok(())
591 }
592
593 #[cfg(feature = "unstable-v2")]
595 pub(crate) fn with_z_step(mut self, step: Option<ZStep>) -> MltResult<Self> {
596 self.z_step = step;
597 for feature in &self.features {
598 self.validate_z(feature)?;
599 }
600 Ok(self)
601 }
602
603 #[cfg(feature = "unstable-v2")]
607 pub fn add_nested(
608 &mut self,
609 name: impl Into<String>,
610 kind: NestedKind,
611 ) -> MltResult<NestedKey> {
612 let name = name.into();
613 self.reject_name_in_use(&name, ColumnRole::Nested)?;
614 validate_nested_kind(&name, &kind)?;
615 for feature in &mut self.features {
616 feature.nested.push(kind.null_value());
617 }
618 self.nested_names.push(name);
619 self.nested_kinds.push(kind);
620 Ok(NestedKey(self.nested_names.len() - 1))
621 }
622
623 #[cfg(feature = "unstable-v2")]
626 pub(crate) fn with_nested(
627 mut self,
628 names: Vec<String>,
629 kinds: Vec<NestedKind>,
630 ) -> MltResult<Self> {
631 validate_unique_names(&names, ColumnRole::Nested)?;
632 for name in &names {
633 self.reject_name_in_use(name, ColumnRole::Nested)?;
634 }
635 for (name, kind) in names.iter().zip(&kinds) {
636 validate_nested_kind(name, kind)?;
637 }
638 self.nested_names = names;
639 self.nested_kinds = kinds;
640 for feature in &self.features {
641 self.validate_nested(feature)?;
642 }
643 Ok(self)
644 }
645
646 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
647 self.validate_feature(&feature)?;
648 self.features.push(feature);
649 Ok(())
650 }
651
652 pub fn builder(name: impl Into<String>, extent: u32) -> MltResult<TileLayerBuilder> {
653 Ok(TileLayerBuilder {
654 layer: Self::new(name, extent)?,
655 })
656 }
657
658 #[must_use]
660 pub fn builder_like(&self) -> TileLayerBuilder {
661 let layer = Self {
662 name: self.name.clone(),
663 extent: self.extent,
664 property_names: Vec::new(),
665 property_kinds: Vec::new(),
666 #[cfg(feature = "unstable-v2")]
667 m_value_names: Vec::new(),
668 #[cfg(feature = "unstable-v2")]
669 m_value_kinds: Vec::new(),
670 #[cfg(feature = "unstable-v2")]
671 nested_names: Vec::new(),
672 #[cfg(feature = "unstable-v2")]
673 nested_kinds: Vec::new(),
674 #[cfg(feature = "unstable-v2")]
675 z_step: self.z_step,
676 features: Vec::new(),
677 };
678 TileLayerBuilder { layer }
679 }
680
681 fn validate_feature(&self, feature: &TileFeature) -> MltResult<()> {
682 validate_kinds::<PropValue>(&self.property_kinds, feature)?;
683 #[cfg(feature = "unstable-v2")]
684 self.validate_m_values(feature)?;
685 #[cfg(feature = "unstable-v2")]
686 self.validate_nested(feature)?;
687 #[cfg(feature = "unstable-v2")]
688 self.validate_z(feature)?;
689 Ok(())
690 }
691
692 #[cfg(feature = "unstable-v2")]
694 fn validate_z(&self, feature: &TileFeature) -> MltResult<()> {
695 let expected = if self.z_step.is_some() {
696 feature.vertex_count()
697 } else {
698 0
699 };
700 if feature.z.len() == expected {
701 Ok(())
702 } else {
703 Err(MltError::ZVertexCountMismatch {
704 expected,
705 actual: feature.z.len(),
706 })
707 }
708 }
709
710 #[cfg(feature = "unstable-v2")]
713 fn validate_nested(&self, feature: &TileFeature) -> MltResult<()> {
714 if feature.nested.len() != self.nested_kinds.len() {
715 return Err(MltError::NestedColumnCountMismatch {
716 expected: self.nested_kinds.len(),
717 actual: feature.nested.len(),
718 });
719 }
720 for (index, (value, kind)) in feature.nested.iter().zip(&self.nested_kinds).enumerate() {
721 if !kind.accepts(value) {
722 return Err(MltError::NestedValueMismatch {
723 index,
724 name: self.nested_names[index].clone(),
725 });
726 }
727 }
728 Ok(())
729 }
730
731 #[cfg(feature = "unstable-v2")]
734 fn validate_m_values(&self, feature: &TileFeature) -> MltResult<()> {
735 validate_kinds::<MValue>(&self.m_value_kinds, feature)?;
736 let vertices = feature.vertex_count();
737 for (index, m_value) in feature.m_values.iter().enumerate() {
738 if let Some(len) = m_value.count()
739 && len != vertices
740 {
741 return Err(MltError::MValueVertexCountMismatch {
742 index,
743 expected: vertices,
744 actual: len,
745 });
746 }
747 }
748 Ok(())
749 }
750}
751
752impl TileFeature {
753 #[must_use]
754 pub fn new(geometry: Geometry<i32>) -> Self {
755 Self {
756 id: None,
757 geometry,
758 properties: Vec::new(),
759 #[cfg(feature = "unstable-v2")]
760 m_values: Vec::new(),
761 #[cfg(feature = "unstable-v2")]
762 nested: Vec::new(),
763 #[cfg(feature = "unstable-v2")]
764 z: Vec::new(),
765 }
766 }
767
768 #[must_use]
769 pub fn with_id(geometry: Geometry<i32>, id: u64) -> Self {
770 Self {
771 id: Some(id),
772 geometry,
773 properties: Vec::new(),
774 #[cfg(feature = "unstable-v2")]
775 m_values: Vec::new(),
776 #[cfg(feature = "unstable-v2")]
777 nested: Vec::new(),
778 #[cfg(feature = "unstable-v2")]
779 z: Vec::new(),
780 }
781 }
782
783 #[must_use]
784 pub fn id(&self) -> Option<u64> {
785 self.id
786 }
787
788 #[must_use]
789 pub fn geometry(&self) -> &Geometry<i32> {
790 &self.geometry
791 }
792
793 #[must_use]
794 pub fn properties(&self) -> &[PropValue] {
795 &self.properties
796 }
797
798 #[cfg(feature = "unstable-v2")]
803 #[must_use]
804 pub fn vertex_count(&self) -> usize {
805 stored_vertex_count(&self.geometry)
806 }
807
808 #[cfg(feature = "unstable-v2")]
809 #[must_use]
810 pub fn m_values(&self) -> &[MValue] {
811 &self.m_values
812 }
813
814 #[cfg(feature = "unstable-v2")]
816 #[must_use]
817 pub fn z(&self) -> &[i32] {
818 &self.z
819 }
820
821 #[cfg(feature = "unstable-v2")]
823 pub fn set_z(&mut self, z: Vec<i32>) -> MltResult<()> {
824 let expected = self.vertex_count();
825 if z.len() != expected {
826 return Err(MltError::ZVertexCountMismatch {
827 expected,
828 actual: z.len(),
829 });
830 }
831 self.z = z;
832 Ok(())
833 }
834
835 #[cfg(feature = "unstable-v2")]
838 pub fn set_m_value(&mut self, key: MValueKey, value: MValue) -> MltResult<()> {
839 let vertices = self.vertex_count();
840 let Some(slot) = self.m_values.get_mut(key.index()) else {
841 return Err(MltError::UnknownMValueKey {
842 index: key.index(),
843 columns: self.m_values.len(),
844 });
845 };
846 let expected = slot.kind();
847 let actual = value.kind();
848 if actual != expected {
849 return Err(MltError::MValueKindMismatch {
850 index: key.index(),
851 expected,
852 actual,
853 });
854 }
855 if let Some(len) = value.count()
856 && len != vertices
857 {
858 return Err(MltError::MValueVertexCountMismatch {
859 index: key.index(),
860 expected: vertices,
861 actual: len,
862 });
863 }
864 *slot = value;
865 Ok(())
866 }
867
868 #[cfg(feature = "unstable-v2")]
869 #[must_use]
870 pub fn nested(&self) -> &[NestedValue] {
871 &self.nested
872 }
873
874 #[cfg(feature = "unstable-v2")]
880 pub fn set_nested(&mut self, key: NestedKey, value: NestedValue) -> MltResult<()> {
881 let columns = self.nested.len();
882 let Some(slot) = self.nested.get_mut(key.index()) else {
883 return Err(MltError::UnknownNestedKey {
884 index: key.index(),
885 columns,
886 });
887 };
888 if !slot.same_shape(&value) {
889 return Err(MltError::NestedShapeMismatch { index: key.index() });
890 }
891 *slot = value;
892 Ok(())
893 }
894
895 pub fn set_property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<()> {
896 let Some(prop) = self.properties.get_mut(key.index()) else {
897 return Err(MltError::UnknownProperty {
898 index: key.index(),
899 count: self.properties.len(),
900 });
901 };
902 let expected = PropKind::from(&*prop);
903 let actual = PropKind::from(&value);
904 if actual != expected {
905 return Err(MltError::PropertyKindMismatch {
906 index: key.index(),
907 expected,
908 actual,
909 });
910 }
911 *prop = value;
912 Ok(())
913 }
914}
915
916pub struct TileLayerBuilder {
917 layer: TileLayer,
918}
919
920impl TileLayerBuilder {
921 pub fn add_property(
922 &mut self,
923 name: impl Into<String>,
924 kind: PropKind,
925 ) -> MltResult<PropertyKey> {
926 self.layer.add_property(name, kind)
927 }
928
929 #[cfg(feature = "unstable-v2")]
930 pub fn add_m_value(&mut self, name: impl Into<String>, kind: PropKind) -> MltResult<MValueKey> {
931 self.layer.add_m_value(name, kind)
932 }
933
934 #[cfg(feature = "unstable-v2")]
935 pub fn add_nested(
936 &mut self,
937 name: impl Into<String>,
938 kind: NestedKind,
939 ) -> MltResult<NestedKey> {
940 self.layer.add_nested(name, kind)
941 }
942
943 #[cfg(feature = "unstable-v2")]
944 pub fn set_z_step(&mut self, step: ZStep) -> MltResult<()> {
945 self.layer.set_z_step(step)
946 }
947
948 pub fn feature(&mut self, geometry: Geometry<i32>) -> TileFeatureBuilder<'_> {
949 let properties = self
950 .layer
951 .property_kinds
952 .iter()
953 .copied()
954 .map(PropValue::null)
955 .collect();
956 #[cfg(feature = "unstable-v2")]
957 let m_values = self
958 .layer
959 .m_value_kinds
960 .iter()
961 .copied()
962 .map(MValue::null)
963 .collect();
964 #[cfg(feature = "unstable-v2")]
965 let nested = self
966 .layer
967 .nested_kinds
968 .iter()
969 .map(NestedKind::null_value)
970 .collect();
971 TileFeatureBuilder {
972 layer: self,
973 feature: TileFeature {
974 id: None,
975 geometry,
976 properties,
977 #[cfg(feature = "unstable-v2")]
978 m_values,
979 #[cfg(feature = "unstable-v2")]
980 nested,
981 #[cfg(feature = "unstable-v2")]
982 z: Vec::new(),
983 },
984 }
985 }
986
987 pub fn add_properties_like(&mut self, layer: &TileLayer) -> MltResult<Vec<PropertyKey>> {
989 (layer.property_names.iter().zip(&layer.property_kinds))
990 .map(|(name, &kind)| self.add_property(name, kind))
991 .collect()
992 }
993
994 #[cfg(feature = "unstable-v2")]
996 pub fn add_m_values_like(&mut self, layer: &TileLayer) -> MltResult<Vec<MValueKey>> {
997 (layer.m_value_names.iter().zip(&layer.m_value_kinds))
998 .map(|(name, &kind)| self.add_m_value(name, kind))
999 .collect()
1000 }
1001
1002 #[cfg(feature = "unstable-v2")]
1004 pub fn add_nested_like(&mut self, layer: &TileLayer) -> MltResult<Vec<NestedKey>> {
1005 (layer.nested_names.iter().zip(&layer.nested_kinds))
1006 .map(|(name, kind)| self.add_nested(name, kind.clone()))
1007 .collect()
1008 }
1009
1010 pub fn feature_like(&mut self, feature: &TileFeature) -> TileFeatureBuilder<'_> {
1012 let mut row = self.feature(feature.geometry.clone());
1013 row.feature.id = feature.id;
1014 #[cfg(feature = "unstable-v2")]
1015 row.feature.z.clone_from(&feature.z);
1016 row
1017 }
1018
1019 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
1020 self.layer.push_feature(feature)
1021 }
1022
1023 #[must_use]
1024 pub fn finish(self) -> TileLayer {
1025 self.layer
1026 }
1027}
1028
1029pub struct TileFeatureBuilder<'a> {
1030 layer: &'a mut TileLayerBuilder,
1031 feature: TileFeature,
1032}
1033
1034impl TileFeatureBuilder<'_> {
1035 pub fn id(&mut self, id: Option<u64>) -> &mut Self {
1036 self.feature.id = id;
1037 self
1038 }
1039
1040 pub fn property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<&mut Self> {
1041 self.feature.set_property(key, value)?;
1042 Ok(self)
1043 }
1044
1045 #[cfg(feature = "unstable-v2")]
1046 pub fn m_value(&mut self, key: MValueKey, value: MValue) -> MltResult<&mut Self> {
1047 self.feature.set_m_value(key, value)?;
1048 Ok(self)
1049 }
1050
1051 #[cfg(feature = "unstable-v2")]
1052 pub fn nested(&mut self, key: NestedKey, value: NestedValue) -> MltResult<&mut Self> {
1053 self.feature.set_nested(key, value)?;
1054 Ok(self)
1055 }
1056
1057 #[cfg(feature = "unstable-v2")]
1058 pub fn z(&mut self, z: Vec<i32>) -> MltResult<&mut Self> {
1059 self.feature.set_z(z)?;
1060 Ok(self)
1061 }
1062
1063 pub fn finish(self) -> MltResult<()> {
1064 self.layer.push_feature(self.feature)
1065 }
1066}
1067
1068#[derive(Debug, Clone, PartialEq)]
1076pub enum PropValue {
1077 Bool(Option<bool>),
1078 I8(Option<i8>),
1079 U8(Option<u8>),
1080 I32(Option<i32>),
1081 U32(Option<u32>),
1082 I64(Option<i64>),
1083 U64(Option<u64>),
1084 F32(Option<f32>),
1085 F64(Option<f64>),
1086 Str(Option<String>),
1087}
1088
1089impl PropValue {
1090 #[must_use]
1091 pub fn kind(&self) -> PropKind {
1092 self.into()
1093 }
1094}
1095
1096#[cfg(feature = "unstable-v2")]
1101#[derive(Debug, Clone, PartialEq)]
1102pub enum MValue {
1103 Bool(Option<Vec<bool>>),
1104 I8(Option<Vec<i8>>),
1105 U8(Option<Vec<u8>>),
1106 I32(Option<Vec<i32>>),
1107 U32(Option<Vec<u32>>),
1108 I64(Option<Vec<i64>>),
1109 U64(Option<Vec<u64>>),
1110 F32(Option<Vec<f32>>),
1111 F64(Option<Vec<f64>>),
1112 Str(Option<Vec<String>>),
1113}
1114
1115#[cfg(feature = "unstable-v2")]
1116impl MValue {
1117 #[must_use]
1118 pub fn is_null(&self) -> bool {
1119 self.count().is_none()
1120 }
1121}
1122
1123#[derive(Debug, Clone, Copy, PartialEq)]
1128pub enum PropValueRef<'a> {
1129 Bool(bool),
1130 I8(i8),
1131 U8(u8),
1132 I32(i32),
1133 U32(u32),
1134 I64(i64),
1135 U64(u64),
1136 F32(f32),
1137 F64(f64),
1138 Str(&'a str),
1139}
1140
1141impl From<bool> for PropValueRef<'_> {
1142 fn from(v: bool) -> Self {
1143 Self::Bool(v)
1144 }
1145}
1146impl From<i8> for PropValueRef<'_> {
1147 fn from(v: i8) -> Self {
1148 Self::I8(v)
1149 }
1150}
1151impl From<u8> for PropValueRef<'_> {
1152 fn from(v: u8) -> Self {
1153 Self::U8(v)
1154 }
1155}
1156impl From<i32> for PropValueRef<'_> {
1157 fn from(v: i32) -> Self {
1158 Self::I32(v)
1159 }
1160}
1161impl From<u32> for PropValueRef<'_> {
1162 fn from(v: u32) -> Self {
1163 Self::U32(v)
1164 }
1165}
1166impl From<i64> for PropValueRef<'_> {
1167 fn from(v: i64) -> Self {
1168 Self::I64(v)
1169 }
1170}
1171impl From<u64> for PropValueRef<'_> {
1172 fn from(v: u64) -> Self {
1173 Self::U64(v)
1174 }
1175}
1176impl From<f32> for PropValueRef<'_> {
1177 fn from(v: f32) -> Self {
1178 Self::F32(v)
1179 }
1180}
1181impl From<f64> for PropValueRef<'_> {
1182 fn from(v: f64) -> Self {
1183 Self::F64(v)
1184 }
1185}
1186
1187impl<'a> From<&'a str> for PropValueRef<'a> {
1188 fn from(v: &'a str) -> Self {
1189 Self::Str(v)
1190 }
1191}
1192
1193macro_rules! kind_mappings {
1194 (
1195 scalar { $($sv:ident),* $(,)? }
1196 string { $($gv:ident),* $(,)? }
1197 ) => {
1198 #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::IntoStaticStr)]
1200 #[strum(serialize_all = "lowercase")]
1201 pub enum PropKind {
1202 $($sv,)*
1203 $($gv,)*
1204 }
1205
1206 impl From<&PropValue> for PropKind {
1207 fn from(prop: &PropValue) -> Self {
1208 match prop {
1209 $(PropValue::$sv(_) => Self::$sv,)*
1210 $(PropValue::$gv(_) => Self::$gv,)*
1211 }
1212 }
1213 }
1214
1215 impl PropValue {
1216 #[must_use]
1217 pub fn is_null(&self) -> bool {
1218 match self {
1219 $(Self::$sv(v) => v.is_none(),)*
1220 $(Self::$gv(v) => v.is_none(),)*
1221 }
1222 }
1223
1224 #[must_use]
1226 pub fn null(kind: PropKind) -> Self {
1227 match kind {
1228 $(PropKind::$sv => Self::$sv(None),)*
1229 $(PropKind::$gv => Self::$gv(None),)*
1230 }
1231 }
1232
1233 #[inline]
1235 #[must_use]
1236 pub fn value_ref(&self) -> Option<PropValueRef<'_>> {
1237 match self {
1238 $(Self::$sv(v) => v.map(PropValueRef::$sv),)*
1239 $(Self::$gv(v) => v.as_deref().map(PropValueRef::$gv),)*
1240 }
1241 }
1242 }
1243
1244 impl PropValueRef<'_> {
1245 #[inline]
1246 pub(crate) fn kind(&self) -> PropKind {
1247 match self {
1248 $(Self::$sv(_) => PropKind::$sv,)*
1249 $(Self::$gv(_) => PropKind::$gv,)*
1250 }
1251 }
1252 }
1253
1254 #[cfg(feature = "unstable-v2")]
1255 impl MValue {
1256 #[must_use]
1257 pub fn kind(&self) -> PropKind {
1258 match self {
1259 $(Self::$sv(_) => PropKind::$sv,)*
1260 $(Self::$gv(_) => PropKind::$gv,)*
1261 }
1262 }
1263
1264 #[must_use]
1266 pub fn count(&self) -> Option<usize> {
1267 match self {
1268 $(Self::$sv(v) => v.as_ref().map(Vec::len),)*
1269 $(Self::$gv(v) => v.as_ref().map(Vec::len),)*
1270 }
1271 }
1272
1273 #[must_use]
1275 pub fn null(kind: PropKind) -> Self {
1276 match kind {
1277 $(PropKind::$sv => Self::$sv(None),)*
1278 $(PropKind::$gv => Self::$gv(None),)*
1279 }
1280 }
1281 }
1282 };
1283}
1284
1285with_kinds!(kind_mappings);
1286
1287pub(crate) fn stored_ring_len(ring: &LineString<i32>) -> usize {
1289 stored_len(&ring.0)
1290}
1291
1292pub(crate) fn stored_len(coords: &[Coord<i32>]) -> usize {
1294 if coords.len() > 1 && coords.last() == coords.first() {
1295 coords.len() - 1
1296 } else {
1297 coords.len()
1298 }
1299}
1300
1301#[cfg(feature = "unstable-v2")]
1304pub(crate) fn stored_vertex_count(geom: &Geometry<i32>) -> usize {
1305 let polygon = |poly: &geo_types::Polygon<i32>| {
1306 std::iter::once(poly.exterior())
1307 .chain(poly.interiors())
1308 .map(stored_ring_len)
1309 .sum::<usize>()
1310 };
1311 match geom {
1312 Geometry::Point(_) => 1,
1313 Geometry::Line(_) => 2,
1314 Geometry::LineString(ls) => ls.0.len(),
1315 Geometry::Polygon(p) => polygon(p),
1316 Geometry::MultiPoint(mp) => mp.0.len(),
1317 Geometry::MultiLineString(mls) => mls.iter().map(|ls| ls.0.len()).sum(),
1318 Geometry::MultiPolygon(mp) => mp.iter().map(polygon).sum(),
1319 Geometry::Triangle(t) => polygon(&t.to_polygon()),
1320 Geometry::Rect(r) => polygon(&r.to_polygon()),
1321 Geometry::GeometryCollection(gc) => gc.iter().map(stored_vertex_count).sum(),
1322 }
1323}
1324
1325#[cfg(feature = "unstable-v2")]
1328fn validate_nested_kind(name: &str, kind: &NestedKind) -> MltResult<()> {
1329 if matches!(kind, NestedKind::Leaf(_)) {
1330 return Err(MltError::NestedRootIsLeaf(name.to_string()));
1331 }
1332 if kind.has_empty_map() {
1333 return Err(MltError::EmptyStructNode);
1334 }
1335 let depth = kind.depth();
1336 if depth > MAX_NESTED_DEPTH {
1337 return Err(MltError::NestedTooDeep(depth));
1338 }
1339 Ok(())
1340}
1341
1342pub(crate) fn validate_layer_name(name: &str) -> MltResult<()> {
1343 if name.is_empty() {
1344 Err(MltError::MissingLayerName)
1345 } else {
1346 Ok(())
1347 }
1348}
1349
1350pub(crate) fn reject_taken_name<'a>(
1354 name: &str,
1355 role: ColumnRole,
1356 taken: impl IntoIterator<Item = (&'a str, ColumnRole)>,
1357) -> MltResult<()> {
1358 for (seen, taken_by) in taken {
1359 if seen == name {
1360 return Err(MltError::DuplicateColumnName {
1361 name: name.to_string(),
1362 role,
1363 taken_by,
1364 });
1365 }
1366 }
1367 Ok(())
1368}
1369
1370fn validate_unique_names(names: &[String], role: ColumnRole) -> MltResult<()> {
1372 for (i, name) in names.iter().enumerate() {
1375 reject_taken_name(name, role, names[..i].iter().map(|n| (n.as_str(), role)))?;
1376 }
1377 Ok(())
1378}
1379
1380trait FeatureColumn: Sized {
1382 fn of(feature: &TileFeature) -> &[Self];
1384 fn column_kind(&self) -> PropKind;
1385 fn count_mismatch(expected: usize, actual: usize) -> MltError;
1387 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError;
1389}
1390
1391impl FeatureColumn for PropValue {
1392 fn of(feature: &TileFeature) -> &[Self] {
1393 &feature.properties
1394 }
1395
1396 fn column_kind(&self) -> PropKind {
1397 PropKind::from(self)
1398 }
1399
1400 fn count_mismatch(expected: usize, actual: usize) -> MltError {
1401 MltError::PropertyLengthMismatch { expected, actual }
1402 }
1403
1404 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError {
1405 MltError::PropertyKindMismatch {
1406 index,
1407 expected,
1408 actual,
1409 }
1410 }
1411}
1412
1413#[cfg(feature = "unstable-v2")]
1414impl FeatureColumn for MValue {
1415 fn of(feature: &TileFeature) -> &[Self] {
1416 &feature.m_values
1417 }
1418
1419 fn column_kind(&self) -> PropKind {
1420 self.kind()
1421 }
1422
1423 fn count_mismatch(expected: usize, actual: usize) -> MltError {
1424 MltError::MValueColumnCountMismatch { expected, actual }
1425 }
1426
1427 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError {
1428 MltError::MValueKindMismatch {
1429 index,
1430 expected,
1431 actual,
1432 }
1433 }
1434}
1435
1436fn infer_kinds<T: FeatureColumn>(
1440 names: &[String],
1441 features: &[TileFeature],
1442) -> MltResult<Vec<PropKind>> {
1443 let mut kinds = vec![None; names.len()];
1444 for feature in features {
1445 let values = T::of(feature);
1446 if values.len() != names.len() {
1447 return Err(T::count_mismatch(names.len(), values.len()));
1448 }
1449 for (index, value) in values.iter().enumerate() {
1450 let actual = value.column_kind();
1451 match kinds[index] {
1452 Some(expected) if expected != actual => {
1453 return Err(T::kind_mismatch(index, expected, actual));
1454 }
1455 None => kinds[index] = Some(actual),
1456 _ => {}
1457 }
1458 }
1459 }
1460 Ok(kinds
1461 .into_iter()
1462 .map(|kind| kind.unwrap_or(PropKind::Str))
1463 .collect())
1464}
1465
1466fn validate_kinds<T: FeatureColumn>(kinds: &[PropKind], feature: &TileFeature) -> MltResult<()> {
1468 let values = T::of(feature);
1469 if values.len() != kinds.len() {
1470 return Err(T::count_mismatch(kinds.len(), values.len()));
1471 }
1472 for (index, (value, expected)) in values.iter().zip(kinds).enumerate() {
1473 let actual = value.column_kind();
1474 if actual != *expected {
1475 return Err(T::kind_mismatch(index, *expected, actual));
1476 }
1477 }
1478 Ok(())
1479}
1480
1481#[cfg(test)]
1482mod tests {
1483 use geo_types::{Geometry, Point};
1484
1485 use super::*;
1486
1487 fn point_feature(properties: Vec<PropValue>) -> TileFeature {
1488 TileFeature {
1489 id: None,
1490 geometry: Geometry::Point(Point::new(0, 0)),
1491 properties,
1492 #[cfg(feature = "unstable-v2")]
1493 m_values: Vec::new(),
1494 #[cfg(feature = "unstable-v2")]
1495 nested: Vec::new(),
1496 #[cfg(feature = "unstable-v2")]
1497 z: Vec::new(),
1498 }
1499 }
1500
1501 #[test]
1502 fn tile_layer_constructor_rejects_empty_name() {
1503 assert!(matches!(
1504 TileLayer::new("", 4096),
1505 Err(MltError::MissingLayerName)
1506 ));
1507 }
1508
1509 #[test]
1510 fn tile_layer_constructor_rejects_zero_extent() {
1511 assert!(matches!(
1512 TileLayer::new("layer", 0),
1513 Err(MltError::InvalidExtent(0))
1514 ));
1515 }
1516
1517 #[test]
1518 fn add_property_rejects_duplicate_names() {
1519 let mut layer = TileLayer::new("layer", 4096).unwrap();
1520 layer.add_property("name", PropKind::Str).unwrap();
1521 assert_eq!(
1522 layer
1523 .add_property("name", PropKind::Str)
1524 .unwrap_err()
1525 .to_string(),
1526 "duplicate column name name: the property column repeats the property column"
1527 );
1528 }
1529
1530 #[test]
1531 fn from_parts_allows_empty_property_name() {
1532 assert!(TileLayer::from_parts("layer", 4096, vec![String::new()], vec![]).is_ok());
1534 }
1535
1536 #[test]
1537 fn from_parts_rejects_duplicate_property_name() {
1538 assert_eq!(
1539 TileLayer::from_parts("layer", 4096, vec!["dup".into(), "dup".into()], vec![])
1540 .unwrap_err()
1541 .to_string(),
1542 "duplicate column name dup: the property column repeats the property column"
1543 );
1544 }
1545
1546 #[test]
1547 fn push_feature_validates_property_count() {
1548 let mut layer = TileLayer::new("layer", 4096).unwrap();
1549 layer.add_property("name", PropKind::Str).unwrap();
1550 assert!(matches!(
1551 layer.push_feature(point_feature(vec![])),
1552 Err(MltError::PropertyLengthMismatch {
1553 expected: 1,
1554 actual: 0
1555 })
1556 ));
1557 }
1558
1559 #[test]
1560 fn push_feature_validates_property_kind() {
1561 let mut layer = TileLayer::new("layer", 4096).unwrap();
1562 layer.add_property("flag", PropKind::Bool).unwrap();
1563 layer
1564 .push_feature(point_feature(vec![PropValue::Bool(Some(true))]))
1565 .unwrap();
1566 assert!(matches!(
1567 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
1568 Err(MltError::PropertyKindMismatch {
1569 index: 0,
1570 expected: PropKind::Bool,
1571 actual: PropKind::I32,
1572 })
1573 ));
1574 }
1575
1576 #[test]
1577 fn declared_property_kind_is_enforced_for_first_feature() {
1578 let mut layer = TileLayer::new("layer", 4096).unwrap();
1579 layer.add_property("flag", PropKind::Bool).unwrap();
1580 assert!(matches!(
1581 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
1582 Err(MltError::PropertyKindMismatch {
1583 index: 0,
1584 expected: PropKind::Bool,
1585 actual: PropKind::I32,
1586 })
1587 ));
1588 }
1589
1590 #[cfg(feature = "unstable-v2")]
1591 #[test]
1592 fn push_feature_validates_m_value_count() {
1593 let mut layer = TileLayer::new("layer", 4096).unwrap();
1594 layer.add_m_value("m", PropKind::I32).unwrap();
1595 assert!(matches!(
1596 layer.push_feature(point_feature(vec![])),
1597 Err(MltError::MValueColumnCountMismatch {
1598 expected: 1,
1599 actual: 0
1600 })
1601 ));
1602 }
1603
1604 #[test]
1605 fn with_id_is_new_with_that_id() {
1606 let geometry = Geometry::Point(Point::new(1, 2));
1607 let mut expected = TileFeature::new(geometry.clone());
1608 expected.id = Some(7);
1609 assert_eq!(TileFeature::with_id(geometry, 7), expected);
1610 }
1611
1612 #[cfg(feature = "unstable-v2")]
1613 #[test]
1614 fn push_feature_validates_one_value_per_vertex() {
1615 let mut layer = TileLayer::new("layer", 4096).unwrap();
1616 layer.add_m_value("m", PropKind::I32).unwrap();
1617 let mut feature = point_feature(vec![]);
1618 feature.m_values = vec![MValue::I32(Some(vec![1, 2]))];
1619 assert!(matches!(
1620 layer.push_feature(feature),
1621 Err(MltError::MValueVertexCountMismatch {
1622 index: 0,
1623 expected: 1,
1624 actual: 2,
1625 })
1626 ));
1627 }
1628
1629 #[cfg(feature = "unstable-v2")]
1630 #[test]
1631 fn a_polygon_does_not_count_its_closing_vertices() {
1632 let ring = |pts: &[(i32, i32)]| {
1633 let mut ls = LineString::new(pts.iter().map(|&(x, y)| Coord { x, y }).collect());
1634 ls.close();
1635 ls
1636 };
1637 let poly = geo_types::Polygon::new(
1638 ring(&[(0, 0), (0, 4), (4, 4), (4, 0)]),
1639 vec![ring(&[(1, 1), (1, 2), (2, 2)])],
1640 );
1641 let feature = TileFeature::new(Geometry::Polygon(poly));
1642 assert_eq!(feature.vertex_count(), 7);
1643 }
1644
1645 #[cfg(feature = "unstable-v2")]
1646 #[test]
1647 fn a_shape_counts_its_root_as_the_first_level() {
1648 let kind = NestedKind::list(NestedKind::map([("a", NestedKind::Leaf(PropKind::I32))]));
1649 assert_eq!(kind.depth(), 3);
1650 }
1651
1652 #[cfg(feature = "unstable-v2")]
1653 #[test]
1654 fn a_map_may_leave_out_a_field_but_not_add_one() {
1655 let kind = NestedKind::map([
1656 ("a", NestedKind::Leaf(PropKind::I32)),
1657 ("b", NestedKind::Leaf(PropKind::Str)),
1658 ]);
1659 assert!(kind.accepts(&NestedValue::map([(
1660 "a",
1661 NestedValue::Leaf(PropValue::I32(Some(1)))
1662 )])));
1663 assert!(!kind.accepts(&NestedValue::map([(
1664 "c",
1665 NestedValue::Leaf(PropValue::I32(Some(1)))
1666 )])));
1667 assert!(!kind.accepts(&NestedValue::map([(
1668 "a",
1669 NestedValue::Leaf(PropValue::Str(Some("x".into())))
1670 )])));
1671 }
1672
1673 #[cfg(feature = "unstable-v2")]
1674 fn list_kind() -> NestedKind {
1675 NestedKind::list(NestedKind::Leaf(PropKind::I32))
1676 }
1677
1678 #[cfg(feature = "unstable-v2")]
1679 #[test]
1680 fn add_m_value_rejects_a_name_a_property_has() {
1681 let mut layer = TileLayer::new("layer", 4096).unwrap();
1682 layer.add_property("n", PropKind::I32).unwrap();
1683 assert_eq!(
1684 layer
1685 .add_m_value("n", PropKind::I32)
1686 .unwrap_err()
1687 .to_string(),
1688 "duplicate column name n: the m-value column repeats the property column"
1689 );
1690 }
1691
1692 #[cfg(feature = "unstable-v2")]
1693 #[test]
1694 fn add_m_value_rejects_a_name_a_nested_column_has() {
1695 let mut layer = TileLayer::new("layer", 4096).unwrap();
1696 layer.add_nested("n", list_kind()).unwrap();
1697 assert_eq!(
1698 layer
1699 .add_m_value("n", PropKind::I32)
1700 .unwrap_err()
1701 .to_string(),
1702 "duplicate column name n: the m-value column repeats the nested column"
1703 );
1704 }
1705
1706 #[cfg(feature = "unstable-v2")]
1707 #[test]
1708 fn add_m_value_rejects_duplicate_names() {
1709 let mut layer = TileLayer::new("layer", 4096).unwrap();
1710 layer.add_m_value("n", PropKind::I32).unwrap();
1711 assert_eq!(
1712 layer
1713 .add_m_value("n", PropKind::I32)
1714 .unwrap_err()
1715 .to_string(),
1716 "duplicate column name n: the m-value column repeats the m-value column"
1717 );
1718 }
1719
1720 #[cfg(feature = "unstable-v2")]
1721 #[test]
1722 fn add_property_rejects_a_name_an_m_value_has() {
1723 let mut layer = TileLayer::new("layer", 4096).unwrap();
1724 layer.add_m_value("n", PropKind::I32).unwrap();
1725 assert_eq!(
1726 layer
1727 .add_property("n", PropKind::I32)
1728 .unwrap_err()
1729 .to_string(),
1730 "duplicate column name n: the property column repeats the m-value column"
1731 );
1732 }
1733
1734 #[cfg(feature = "unstable-v2")]
1735 #[test]
1736 fn add_property_rejects_a_name_a_nested_column_has() {
1737 let mut layer = TileLayer::new("layer", 4096).unwrap();
1738 layer.add_nested("n", list_kind()).unwrap();
1739 assert_eq!(
1740 layer
1741 .add_property("n", PropKind::I32)
1742 .unwrap_err()
1743 .to_string(),
1744 "duplicate column name n: the property column repeats the nested column"
1745 );
1746 }
1747
1748 #[cfg(feature = "unstable-v2")]
1749 #[test]
1750 fn add_nested_rejects_a_name_a_property_has() {
1751 let mut layer = TileLayer::new("layer", 4096).unwrap();
1752 layer.add_property("n", PropKind::I32).unwrap();
1753 assert_eq!(
1754 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1755 "duplicate column name n: the nested column repeats the property column"
1756 );
1757 }
1758
1759 #[cfg(feature = "unstable-v2")]
1760 #[test]
1761 fn add_nested_rejects_a_name_an_m_value_already_has() {
1762 let mut layer = TileLayer::new("layer", 4096).unwrap();
1763 layer.add_m_value("n", PropKind::I32).unwrap();
1764 assert_eq!(
1765 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1766 "duplicate column name n: the nested column repeats the m-value column"
1767 );
1768 }
1769
1770 #[cfg(feature = "unstable-v2")]
1771 #[test]
1772 fn add_nested_rejects_duplicate_names() {
1773 let mut layer = TileLayer::new("layer", 4096).unwrap();
1774 layer.add_nested("n", list_kind()).unwrap();
1775 assert_eq!(
1776 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1777 "duplicate column name n: the nested column repeats the nested column"
1778 );
1779 }
1780
1781 #[cfg(feature = "unstable-v2")]
1782 #[test]
1783 fn set_nested_rejects_a_value_of_another_shape() {
1784 let mut layer = TileLayer::new("layer", 4096).unwrap();
1785 let key = layer
1786 .add_nested("n", NestedKind::list(NestedKind::Leaf(PropKind::I32)))
1787 .unwrap();
1788 let mut feature = point_feature(vec![]);
1789 feature.nested = vec![NestedValue::List(None)];
1790 assert_eq!(
1791 feature
1792 .set_nested(key, NestedValue::Map(None))
1793 .unwrap_err()
1794 .to_string(),
1795 "nested column 0 was given a value of another shape"
1796 );
1797 }
1798
1799 #[test]
1800 fn builder_uses_declared_property_kind_for_defaults() {
1801 let mut builder = TileLayer::builder("layer", 4096).unwrap();
1802 let flag = builder.add_property("flag", PropKind::Bool).unwrap();
1803 let mut feature = builder.feature(Geometry::Point(Point::new(0, 0)));
1804 feature.property(flag, PropValue::Bool(Some(true))).unwrap();
1805 feature.finish().unwrap();
1806 let layer = builder.finish();
1807
1808 assert_eq!(
1809 layer.features()[0].properties()[0],
1810 PropValue::Bool(Some(true))
1811 );
1812 }
1813}