1#[cfg(feature = "unstable-v2")]
9use std::collections::BTreeMap;
10use std::num::NonZeroU32;
11
12use geo_types::{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 #[must_use]
219 pub fn index(self) -> usize {
220 self.0
221 }
222}
223
224#[cfg(feature = "unstable-v2")]
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
227pub struct MValueKey(usize);
228
229#[cfg(feature = "unstable-v2")]
230impl MValueKey {
231 #[must_use]
232 pub fn index(self) -> usize {
233 self.0
234 }
235}
236
237#[cfg(feature = "unstable-v2")]
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
240pub struct NestedKey(usize);
241
242#[cfg(feature = "unstable-v2")]
243impl NestedKey {
244 #[must_use]
245 pub fn index(self) -> usize {
246 self.0
247 }
248}
249
250#[cfg(feature = "unstable-v2")]
252pub(crate) const MAX_NESTED_DEPTH: usize = 8;
253
254#[cfg(feature = "unstable-v2")]
256#[derive(Debug, Clone, PartialEq, Eq)]
257pub enum NestedKind {
258 Leaf(PropKind),
259 List(Box<Self>),
260 Map(BTreeMap<String, Self>),
262}
263
264#[cfg(feature = "unstable-v2")]
265impl NestedKind {
266 #[must_use]
268 pub fn map<K: Into<String>>(fields: impl IntoIterator<Item = (K, Self)>) -> Self {
269 Self::Map(fields.into_iter().map(|(k, v)| (k.into(), v)).collect())
270 }
271
272 #[must_use]
274 pub fn list(element: Self) -> Self {
275 Self::List(Box::new(element))
276 }
277
278 #[must_use]
280 pub fn depth(&self) -> usize {
281 1 + match self {
282 Self::Leaf(_) => 0,
283 Self::List(element) => element.depth(),
284 Self::Map(fields) => fields.values().map(Self::depth).max().unwrap_or(0),
285 }
286 }
287
288 #[must_use]
290 pub fn null_value(&self) -> NestedValue {
291 match self {
292 Self::Leaf(kind) => NestedValue::Leaf(PropValue::null(*kind)),
293 Self::List(_) => NestedValue::List(None),
294 Self::Map(_) => NestedValue::Map(None),
295 }
296 }
297
298 #[must_use]
302 pub fn accepts(&self, value: &NestedValue) -> bool {
303 match (self, value) {
304 (Self::Leaf(kind), NestedValue::Leaf(value)) => value.kind() == *kind,
305 (Self::List(_), NestedValue::List(None)) | (Self::Map(_), NestedValue::Map(None)) => {
306 true
307 }
308 (Self::List(element), NestedValue::List(Some(items))) => {
309 items.iter().all(|item| element.accepts(item))
310 }
311 (Self::Map(fields), NestedValue::Map(Some(entries))) => entries
312 .iter()
313 .all(|(key, value)| fields.get(key).is_some_and(|kind| kind.accepts(value))),
314 _ => false,
315 }
316 }
317
318 fn has_empty_map(&self) -> bool {
320 match self {
321 Self::Leaf(_) => false,
322 Self::List(element) => element.has_empty_map(),
323 Self::Map(fields) => fields.is_empty() || fields.values().any(Self::has_empty_map),
324 }
325 }
326}
327
328#[cfg(feature = "unstable-v2")]
332#[derive(Debug, Clone, PartialEq)]
333pub enum NestedValue {
334 Leaf(PropValue),
335 List(Option<Vec<Self>>),
336 Map(Option<BTreeMap<String, Self>>),
337}
338
339#[cfg(feature = "unstable-v2")]
340impl NestedValue {
341 #[must_use]
343 pub fn map<K: Into<String>>(entries: impl IntoIterator<Item = (K, Self)>) -> Self {
344 Self::Map(Some(
345 entries.into_iter().map(|(k, v)| (k.into(), v)).collect(),
346 ))
347 }
348
349 #[must_use]
351 pub fn list(items: impl IntoIterator<Item = Self>) -> Self {
352 Self::List(Some(items.into_iter().collect()))
353 }
354
355 #[must_use]
357 pub fn is_null(&self) -> bool {
358 match self {
359 Self::Leaf(value) => value.is_null(),
360 Self::List(items) => items.is_none(),
361 Self::Map(entries) => entries.is_none(),
362 }
363 }
364
365 #[must_use]
367 pub(crate) fn heap_bytes(&self) -> usize {
368 match self {
369 Self::Leaf(PropValue::Str(Some(value))) => value.len(),
370 Self::Leaf(_) => size_of::<PropValue>(),
371 Self::List(items) => items.iter().flatten().map(Self::heap_bytes).sum::<usize>(),
372 Self::Map(entries) => entries
373 .iter()
374 .flatten()
375 .map(|(key, value)| key.len() + value.heap_bytes())
376 .sum(),
377 }
378 }
379
380 fn same_shape(&self, other: &Self) -> bool {
383 matches!(
384 (self, other),
385 (Self::Leaf(_), Self::Leaf(_))
386 | (Self::List(_), Self::List(_))
387 | (Self::Map(_), Self::Map(_))
388 )
389 }
390}
391
392impl TileLayer {
393 pub fn new(name: impl Into<String>, extent: u32) -> MltResult<Self> {
394 Self::with_capacity(name, extent, 0)
395 }
396
397 pub fn with_capacity(name: impl Into<String>, extent: u32, features: usize) -> MltResult<Self> {
398 let name = name.into();
399 validate_layer_name(&name)?;
400 let extent = Extent::new(extent)?;
401 Ok(Self {
402 name,
403 extent,
404 property_names: Vec::new(),
405 property_kinds: Vec::new(),
406 #[cfg(feature = "unstable-v2")]
407 m_value_names: Vec::new(),
408 #[cfg(feature = "unstable-v2")]
409 m_value_kinds: Vec::new(),
410 #[cfg(feature = "unstable-v2")]
411 nested_names: Vec::new(),
412 #[cfg(feature = "unstable-v2")]
413 nested_kinds: Vec::new(),
414 #[cfg(feature = "unstable-v2")]
415 z_step: None,
416 features: Vec::with_capacity(features),
417 })
418 }
419
420 pub(crate) fn from_parts(
421 name: impl Into<String>,
422 extent: u32,
423 property_names: Vec<String>,
424 features: Vec<TileFeature>,
425 ) -> MltResult<Self> {
426 let name = name.into();
427 validate_layer_name(&name)?;
428 let extent = Extent::new(extent)?;
429 validate_unique_names(&property_names, ColumnRole::Property)?;
430 let property_kinds = infer_kinds::<PropValue>(&property_names, &features)?;
431 let layer = Self {
432 name,
433 extent,
434 property_names,
435 property_kinds,
436 #[cfg(feature = "unstable-v2")]
437 m_value_names: Vec::new(),
438 #[cfg(feature = "unstable-v2")]
439 m_value_kinds: Vec::new(),
440 #[cfg(feature = "unstable-v2")]
441 nested_names: Vec::new(),
442 #[cfg(feature = "unstable-v2")]
443 nested_kinds: Vec::new(),
444 #[cfg(feature = "unstable-v2")]
445 z_step: None,
446 features,
447 };
448 Ok(layer)
449 }
450
451 #[must_use]
452 pub fn name(&self) -> &str {
453 &self.name
454 }
455
456 #[must_use]
457 pub fn extent(&self) -> Extent {
458 self.extent
459 }
460
461 #[must_use]
462 pub fn property_names(&self) -> &[String] {
463 &self.property_names
464 }
465
466 #[must_use]
467 pub fn property_kinds(&self) -> &[PropKind] {
468 &self.property_kinds
469 }
470
471 #[must_use]
472 pub fn features(&self) -> &[TileFeature] {
473 &self.features
474 }
475
476 #[must_use]
477 pub(crate) fn features_mut(&mut self) -> &mut [TileFeature] {
478 &mut self.features
479 }
480
481 pub(crate) fn widen_8bit_ints(&mut self) {
483 for kind in &mut self.property_kinds {
484 if *kind == PropKind::I8 {
485 *kind = PropKind::I32;
486 } else if *kind == PropKind::U8 {
487 *kind = PropKind::U32;
488 }
489 }
490 for prop in self.features.iter_mut().flat_map(|f| &mut f.properties) {
491 if let PropValue::I8(v) = *prop {
492 *prop = PropValue::I32(v.map(i32::from));
493 } else if let PropValue::U8(v) = *prop {
494 *prop = PropValue::U32(v.map(u32::from));
495 }
496 }
497 }
498
499 #[must_use]
500 pub fn feature_count(&self) -> usize {
501 self.features.len()
502 }
503
504 fn reject_name_in_use(&self, name: &str, role: ColumnRole) -> MltResult<()> {
506 let taken = self
507 .property_names
508 .iter()
509 .map(|n| (n.as_str(), ColumnRole::Property));
510 #[cfg(feature = "unstable-v2")]
511 let taken = taken
512 .chain(
513 self.m_value_names
514 .iter()
515 .map(|n| (n.as_str(), ColumnRole::MValue)),
516 )
517 .chain(
518 self.nested_names
519 .iter()
520 .map(|n| (n.as_str(), ColumnRole::Nested)),
521 );
522 reject_taken_name(name, role, taken)
523 }
524
525 pub fn add_property(
526 &mut self,
527 name: impl Into<String>,
528 kind: PropKind,
529 ) -> MltResult<PropertyKey> {
530 let name = name.into();
531 self.reject_name_in_use(&name, ColumnRole::Property)?;
532 for feature in &mut self.features {
533 feature.properties.push(PropValue::null(kind));
534 }
535 self.property_names.push(name);
536 self.property_kinds.push(kind);
537 Ok(PropertyKey(self.property_names.len() - 1))
538 }
539
540 #[cfg(feature = "unstable-v2")]
541 #[must_use]
542 pub fn m_value_names(&self) -> &[String] {
543 &self.m_value_names
544 }
545
546 #[cfg(feature = "unstable-v2")]
547 #[must_use]
548 pub fn m_value_kinds(&self) -> &[PropKind] {
549 &self.m_value_kinds
550 }
551
552 #[cfg(feature = "unstable-v2")]
554 pub fn add_m_value(&mut self, name: impl Into<String>, kind: PropKind) -> MltResult<MValueKey> {
555 let name = name.into();
556 self.reject_name_in_use(&name, ColumnRole::MValue)?;
557 for feature in &mut self.features {
558 feature.m_values.push(MValue::null(kind));
559 }
560 self.m_value_names.push(name);
561 self.m_value_kinds.push(kind);
562 Ok(MValueKey(self.m_value_names.len() - 1))
563 }
564
565 #[cfg(feature = "unstable-v2")]
568 pub(crate) fn with_m_value_names(mut self, names: Vec<String>) -> MltResult<Self> {
569 validate_unique_names(&names, ColumnRole::MValue)?;
570 for name in &names {
571 self.reject_name_in_use(name, ColumnRole::MValue)?;
572 }
573 self.m_value_kinds = infer_kinds::<MValue>(&names, &self.features)?;
574 self.m_value_names = names;
575 for feature in &self.features {
576 self.validate_m_values(feature)?;
577 }
578 Ok(self)
579 }
580
581 #[cfg(feature = "unstable-v2")]
582 #[must_use]
583 pub fn nested_names(&self) -> &[String] {
584 &self.nested_names
585 }
586
587 #[cfg(feature = "unstable-v2")]
588 #[must_use]
589 pub fn nested_kinds(&self) -> &[NestedKind] {
590 &self.nested_kinds
591 }
592
593 #[cfg(feature = "unstable-v2")]
595 #[must_use]
596 pub fn z_step(&self) -> Option<ZStep> {
597 self.z_step
598 }
599
600 #[cfg(feature = "unstable-v2")]
604 pub fn set_z_step(&mut self, step: ZStep) -> MltResult<()> {
605 if !self.features.is_empty() {
606 return Err(MltError::ZStepOnNonEmptyLayer(self.name.clone()));
607 }
608 self.z_step = Some(step);
609 Ok(())
610 }
611
612 #[cfg(feature = "unstable-v2")]
614 pub(crate) fn with_z_step(mut self, step: Option<ZStep>) -> MltResult<Self> {
615 self.z_step = step;
616 for feature in &self.features {
617 self.validate_z(feature)?;
618 }
619 Ok(self)
620 }
621
622 #[cfg(feature = "unstable-v2")]
626 pub fn add_nested(
627 &mut self,
628 name: impl Into<String>,
629 kind: NestedKind,
630 ) -> MltResult<NestedKey> {
631 let name = name.into();
632 self.reject_name_in_use(&name, ColumnRole::Nested)?;
633 validate_nested_kind(&name, &kind)?;
634 for feature in &mut self.features {
635 feature.nested.push(kind.null_value());
636 }
637 self.nested_names.push(name);
638 self.nested_kinds.push(kind);
639 Ok(NestedKey(self.nested_names.len() - 1))
640 }
641
642 #[cfg(feature = "unstable-v2")]
645 pub(crate) fn with_nested(
646 mut self,
647 names: Vec<String>,
648 kinds: Vec<NestedKind>,
649 ) -> MltResult<Self> {
650 validate_unique_names(&names, ColumnRole::Nested)?;
651 for name in &names {
652 self.reject_name_in_use(name, ColumnRole::Nested)?;
653 }
654 for (name, kind) in names.iter().zip(&kinds) {
655 validate_nested_kind(name, kind)?;
656 }
657 self.nested_names = names;
658 self.nested_kinds = kinds;
659 for feature in &self.features {
660 self.validate_nested(feature)?;
661 }
662 Ok(self)
663 }
664
665 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
666 self.validate_feature(&feature)?;
667 self.features.push(feature);
668 Ok(())
669 }
670
671 pub fn builder(name: impl Into<String>, extent: u32) -> MltResult<TileLayerBuilder> {
672 Ok(TileLayerBuilder {
673 layer: Self::new(name, extent)?,
674 })
675 }
676
677 #[must_use]
679 pub fn builder_like(&self) -> TileLayerBuilder {
680 let layer = Self {
681 name: self.name.clone(),
682 extent: self.extent,
683 property_names: Vec::new(),
684 property_kinds: Vec::new(),
685 #[cfg(feature = "unstable-v2")]
686 m_value_names: Vec::new(),
687 #[cfg(feature = "unstable-v2")]
688 m_value_kinds: Vec::new(),
689 #[cfg(feature = "unstable-v2")]
690 nested_names: Vec::new(),
691 #[cfg(feature = "unstable-v2")]
692 nested_kinds: Vec::new(),
693 #[cfg(feature = "unstable-v2")]
694 z_step: self.z_step,
695 features: Vec::new(),
696 };
697 TileLayerBuilder { layer }
698 }
699
700 fn validate_feature(&self, feature: &TileFeature) -> MltResult<()> {
701 validate_kinds::<PropValue>(&self.property_kinds, feature)?;
702 #[cfg(feature = "unstable-v2")]
703 self.validate_m_values(feature)?;
704 #[cfg(feature = "unstable-v2")]
705 self.validate_nested(feature)?;
706 #[cfg(feature = "unstable-v2")]
707 self.validate_z(feature)?;
708 Ok(())
709 }
710
711 #[cfg(feature = "unstable-v2")]
713 fn validate_z(&self, feature: &TileFeature) -> MltResult<()> {
714 let expected = if self.z_step.is_some() {
715 feature.vertex_count()
716 } else {
717 0
718 };
719 if feature.z.len() == expected {
720 Ok(())
721 } else {
722 Err(MltError::ZVertexCountMismatch {
723 expected,
724 actual: feature.z.len(),
725 })
726 }
727 }
728
729 #[cfg(feature = "unstable-v2")]
732 fn validate_nested(&self, feature: &TileFeature) -> MltResult<()> {
733 if feature.nested.len() != self.nested_kinds.len() {
734 return Err(MltError::NestedColumnCountMismatch {
735 expected: self.nested_kinds.len(),
736 actual: feature.nested.len(),
737 });
738 }
739 for (index, (value, kind)) in feature.nested.iter().zip(&self.nested_kinds).enumerate() {
740 if !kind.accepts(value) {
741 return Err(MltError::NestedValueMismatch {
742 index,
743 name: self.nested_names[index].clone(),
744 });
745 }
746 }
747 Ok(())
748 }
749
750 #[cfg(feature = "unstable-v2")]
753 fn validate_m_values(&self, feature: &TileFeature) -> MltResult<()> {
754 validate_kinds::<MValue>(&self.m_value_kinds, feature)?;
755 let vertices = feature.vertex_count();
756 for (index, m_value) in feature.m_values.iter().enumerate() {
757 if let Some(len) = m_value.count()
758 && len != vertices
759 {
760 return Err(MltError::MValueVertexCountMismatch {
761 index,
762 expected: vertices,
763 actual: len,
764 });
765 }
766 }
767 Ok(())
768 }
769}
770
771impl TileFeature {
772 #[must_use]
773 pub fn new(geometry: Geometry<i32>) -> Self {
774 Self {
775 id: None,
776 geometry,
777 properties: Vec::new(),
778 #[cfg(feature = "unstable-v2")]
779 m_values: Vec::new(),
780 #[cfg(feature = "unstable-v2")]
781 nested: Vec::new(),
782 #[cfg(feature = "unstable-v2")]
783 z: Vec::new(),
784 }
785 }
786
787 #[must_use]
788 pub fn with_id(geometry: Geometry<i32>, id: u64) -> Self {
789 Self {
790 id: Some(id),
791 geometry,
792 properties: Vec::new(),
793 #[cfg(feature = "unstable-v2")]
794 m_values: Vec::new(),
795 #[cfg(feature = "unstable-v2")]
796 nested: Vec::new(),
797 #[cfg(feature = "unstable-v2")]
798 z: Vec::new(),
799 }
800 }
801
802 #[must_use]
803 pub fn id(&self) -> Option<u64> {
804 self.id
805 }
806
807 #[must_use]
808 pub fn geometry(&self) -> &Geometry<i32> {
809 &self.geometry
810 }
811
812 #[must_use]
813 pub fn properties(&self) -> &[PropValue] {
814 &self.properties
815 }
816
817 #[must_use]
818 pub(crate) fn properties_mut(&mut self) -> &mut [PropValue] {
819 &mut self.properties
820 }
821
822 #[cfg(feature = "unstable-v2")]
827 #[must_use]
828 pub fn vertex_count(&self) -> usize {
829 stored_vertex_count(&self.geometry)
830 }
831
832 #[cfg(feature = "unstable-v2")]
833 #[must_use]
834 pub fn m_values(&self) -> &[MValue] {
835 &self.m_values
836 }
837
838 #[cfg(feature = "unstable-v2")]
840 #[must_use]
841 pub fn z(&self) -> &[i32] {
842 &self.z
843 }
844
845 #[cfg(feature = "unstable-v2")]
847 pub fn set_z(&mut self, z: Vec<i32>) -> MltResult<()> {
848 let expected = self.vertex_count();
849 if z.len() != expected {
850 return Err(MltError::ZVertexCountMismatch {
851 expected,
852 actual: z.len(),
853 });
854 }
855 self.z = z;
856 Ok(())
857 }
858
859 #[cfg(feature = "unstable-v2")]
862 pub fn set_m_value(&mut self, key: MValueKey, value: MValue) -> MltResult<()> {
863 let vertices = self.vertex_count();
864 let Some(slot) = self.m_values.get_mut(key.index()) else {
865 return Err(MltError::UnknownMValueKey {
866 index: key.index(),
867 columns: self.m_values.len(),
868 });
869 };
870 let expected = slot.kind();
871 let actual = value.kind();
872 if actual != expected {
873 return Err(MltError::MValueKindMismatch {
874 index: key.index(),
875 expected,
876 actual,
877 });
878 }
879 if let Some(len) = value.count()
880 && len != vertices
881 {
882 return Err(MltError::MValueVertexCountMismatch {
883 index: key.index(),
884 expected: vertices,
885 actual: len,
886 });
887 }
888 *slot = value;
889 Ok(())
890 }
891
892 #[cfg(feature = "unstable-v2")]
893 #[must_use]
894 pub fn nested(&self) -> &[NestedValue] {
895 &self.nested
896 }
897
898 #[cfg(feature = "unstable-v2")]
904 pub fn set_nested(&mut self, key: NestedKey, value: NestedValue) -> MltResult<()> {
905 let columns = self.nested.len();
906 let Some(slot) = self.nested.get_mut(key.index()) else {
907 return Err(MltError::UnknownNestedKey {
908 index: key.index(),
909 columns,
910 });
911 };
912 if !slot.same_shape(&value) {
913 return Err(MltError::NestedShapeMismatch { index: key.index() });
914 }
915 *slot = value;
916 Ok(())
917 }
918
919 pub fn set_property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<()> {
920 let Some(prop) = self.properties.get_mut(key.index()) else {
921 return Err(MltError::PropertyLengthMismatch {
922 expected: key.index() + 1,
923 actual: self.properties.len(),
924 });
925 };
926 let expected = PropKind::from(&*prop);
927 let actual = PropKind::from(&value);
928 if actual != expected {
929 return Err(MltError::PropertyKindMismatch {
930 index: key.index(),
931 expected,
932 actual,
933 });
934 }
935 *prop = value;
936 Ok(())
937 }
938}
939
940pub struct TileLayerBuilder {
941 layer: TileLayer,
942}
943
944impl TileLayerBuilder {
945 pub fn add_property(
946 &mut self,
947 name: impl Into<String>,
948 kind: PropKind,
949 ) -> MltResult<PropertyKey> {
950 self.layer.add_property(name, kind)
951 }
952
953 #[cfg(feature = "unstable-v2")]
954 pub fn add_m_value(&mut self, name: impl Into<String>, kind: PropKind) -> MltResult<MValueKey> {
955 self.layer.add_m_value(name, kind)
956 }
957
958 #[cfg(feature = "unstable-v2")]
959 pub fn add_nested(
960 &mut self,
961 name: impl Into<String>,
962 kind: NestedKind,
963 ) -> MltResult<NestedKey> {
964 self.layer.add_nested(name, kind)
965 }
966
967 #[cfg(feature = "unstable-v2")]
968 pub fn set_z_step(&mut self, step: ZStep) -> MltResult<()> {
969 self.layer.set_z_step(step)
970 }
971
972 pub fn feature(&mut self, geometry: Geometry<i32>) -> TileFeatureBuilder<'_> {
973 let properties = self
974 .layer
975 .property_kinds
976 .iter()
977 .copied()
978 .map(PropValue::null)
979 .collect();
980 #[cfg(feature = "unstable-v2")]
981 let m_values = self
982 .layer
983 .m_value_kinds
984 .iter()
985 .copied()
986 .map(MValue::null)
987 .collect();
988 #[cfg(feature = "unstable-v2")]
989 let nested = self
990 .layer
991 .nested_kinds
992 .iter()
993 .map(NestedKind::null_value)
994 .collect();
995 TileFeatureBuilder {
996 layer: self,
997 feature: TileFeature {
998 id: None,
999 geometry,
1000 properties,
1001 #[cfg(feature = "unstable-v2")]
1002 m_values,
1003 #[cfg(feature = "unstable-v2")]
1004 nested,
1005 #[cfg(feature = "unstable-v2")]
1006 z: Vec::new(),
1007 },
1008 }
1009 }
1010
1011 pub fn add_properties_like(&mut self, layer: &TileLayer) -> MltResult<Vec<PropertyKey>> {
1013 (layer.property_names.iter().zip(&layer.property_kinds))
1014 .map(|(name, &kind)| self.add_property(name, kind))
1015 .collect()
1016 }
1017
1018 #[cfg(feature = "unstable-v2")]
1020 pub fn add_m_values_like(&mut self, layer: &TileLayer) -> MltResult<Vec<MValueKey>> {
1021 (layer.m_value_names.iter().zip(&layer.m_value_kinds))
1022 .map(|(name, &kind)| self.add_m_value(name, kind))
1023 .collect()
1024 }
1025
1026 #[cfg(feature = "unstable-v2")]
1028 pub fn add_nested_like(&mut self, layer: &TileLayer) -> MltResult<Vec<NestedKey>> {
1029 (layer.nested_names.iter().zip(&layer.nested_kinds))
1030 .map(|(name, kind)| self.add_nested(name, kind.clone()))
1031 .collect()
1032 }
1033
1034 pub fn feature_like(&mut self, feature: &TileFeature) -> TileFeatureBuilder<'_> {
1036 let mut row = self.feature(feature.geometry.clone());
1037 row.feature.id = feature.id;
1038 #[cfg(feature = "unstable-v2")]
1039 row.feature.z.clone_from(&feature.z);
1040 row
1041 }
1042
1043 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
1044 self.layer.push_feature(feature)
1045 }
1046
1047 #[must_use]
1048 pub fn finish(self) -> TileLayer {
1049 self.layer
1050 }
1051}
1052
1053pub struct TileFeatureBuilder<'a> {
1054 layer: &'a mut TileLayerBuilder,
1055 feature: TileFeature,
1056}
1057
1058impl TileFeatureBuilder<'_> {
1059 pub fn id(&mut self, id: Option<u64>) -> &mut Self {
1060 self.feature.id = id;
1061 self
1062 }
1063
1064 pub fn property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<&mut Self> {
1065 self.feature.set_property(key, value)?;
1066 Ok(self)
1067 }
1068
1069 #[cfg(feature = "unstable-v2")]
1070 pub fn m_value(&mut self, key: MValueKey, value: MValue) -> MltResult<&mut Self> {
1071 self.feature.set_m_value(key, value)?;
1072 Ok(self)
1073 }
1074
1075 #[cfg(feature = "unstable-v2")]
1076 pub fn nested(&mut self, key: NestedKey, value: NestedValue) -> MltResult<&mut Self> {
1077 self.feature.set_nested(key, value)?;
1078 Ok(self)
1079 }
1080
1081 #[cfg(feature = "unstable-v2")]
1082 pub fn z(&mut self, z: Vec<i32>) -> MltResult<&mut Self> {
1083 self.feature.set_z(z)?;
1084 Ok(self)
1085 }
1086
1087 pub fn finish(self) -> MltResult<()> {
1088 self.layer.push_feature(self.feature)
1089 }
1090}
1091
1092#[derive(Debug, Clone, PartialEq)]
1100pub enum PropValue {
1101 Bool(Option<bool>),
1102 I8(Option<i8>),
1103 U8(Option<u8>),
1104 I32(Option<i32>),
1105 U32(Option<u32>),
1106 I64(Option<i64>),
1107 U64(Option<u64>),
1108 F32(Option<f32>),
1109 F64(Option<f64>),
1110 Str(Option<String>),
1111}
1112
1113impl PropValue {
1114 #[must_use]
1115 pub fn kind(&self) -> PropKind {
1116 self.into()
1117 }
1118}
1119
1120#[cfg(feature = "unstable-v2")]
1125#[derive(Debug, Clone, PartialEq)]
1126pub enum MValue {
1127 Bool(Option<Vec<bool>>),
1128 I8(Option<Vec<i8>>),
1129 U8(Option<Vec<u8>>),
1130 I32(Option<Vec<i32>>),
1131 U32(Option<Vec<u32>>),
1132 I64(Option<Vec<i64>>),
1133 U64(Option<Vec<u64>>),
1134 F32(Option<Vec<f32>>),
1135 F64(Option<Vec<f64>>),
1136 Str(Option<Vec<String>>),
1137}
1138
1139#[cfg(feature = "unstable-v2")]
1140impl MValue {
1141 #[must_use]
1142 pub fn is_null(&self) -> bool {
1143 self.count().is_none()
1144 }
1145}
1146
1147macro_rules! kind_mappings {
1148 (
1149 scalar { $($sv:ident),* $(,)? }
1150 string { $($gv:ident),* $(,)? }
1151 ) => {
1152 #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::IntoStaticStr)]
1154 #[strum(serialize_all = "lowercase")]
1155 pub enum PropKind {
1156 $($sv,)*
1157 $($gv,)*
1158 }
1159
1160 impl From<&PropValue> for PropKind {
1161 fn from(prop: &PropValue) -> Self {
1162 match prop {
1163 $(PropValue::$sv(_) => Self::$sv,)*
1164 $(PropValue::$gv(_) => Self::$gv,)*
1165 }
1166 }
1167 }
1168
1169 impl PropValue {
1170 #[must_use]
1171 pub fn is_null(&self) -> bool {
1172 match self {
1173 $(Self::$sv(v) => v.is_none(),)*
1174 $(Self::$gv(v) => v.is_none(),)*
1175 }
1176 }
1177
1178 #[must_use]
1180 pub fn null(kind: PropKind) -> Self {
1181 match kind {
1182 $(PropKind::$sv => Self::$sv(None),)*
1183 $(PropKind::$gv => Self::$gv(None),)*
1184 }
1185 }
1186 }
1187
1188 #[cfg(feature = "unstable-v2")]
1189 impl MValue {
1190 #[must_use]
1191 pub fn kind(&self) -> PropKind {
1192 match self {
1193 $(Self::$sv(_) => PropKind::$sv,)*
1194 $(Self::$gv(_) => PropKind::$gv,)*
1195 }
1196 }
1197
1198 #[must_use]
1200 pub fn count(&self) -> Option<usize> {
1201 match self {
1202 $(Self::$sv(v) => v.as_ref().map(Vec::len),)*
1203 $(Self::$gv(v) => v.as_ref().map(Vec::len),)*
1204 }
1205 }
1206
1207 #[must_use]
1209 pub fn null(kind: PropKind) -> Self {
1210 match kind {
1211 $(PropKind::$sv => Self::$sv(None),)*
1212 $(PropKind::$gv => Self::$gv(None),)*
1213 }
1214 }
1215 }
1216 };
1217}
1218
1219with_kinds!(kind_mappings);
1220
1221pub(crate) fn stored_ring_len(ring: &LineString<i32>) -> usize {
1223 let coords = &ring.0;
1224 if coords.len() > 1 && coords.last() == coords.first() {
1225 coords.len() - 1
1226 } else {
1227 coords.len()
1228 }
1229}
1230
1231#[cfg(feature = "unstable-v2")]
1234pub(crate) fn stored_vertex_count(geom: &Geometry<i32>) -> usize {
1235 let polygon = |poly: &geo_types::Polygon<i32>| {
1236 std::iter::once(poly.exterior())
1237 .chain(poly.interiors())
1238 .map(stored_ring_len)
1239 .sum::<usize>()
1240 };
1241 match geom {
1242 Geometry::Point(_) => 1,
1243 Geometry::Line(_) => 2,
1244 Geometry::LineString(ls) => ls.0.len(),
1245 Geometry::Polygon(p) => polygon(p),
1246 Geometry::MultiPoint(mp) => mp.0.len(),
1247 Geometry::MultiLineString(mls) => mls.iter().map(|ls| ls.0.len()).sum(),
1248 Geometry::MultiPolygon(mp) => mp.iter().map(polygon).sum(),
1249 Geometry::Triangle(t) => polygon(&t.to_polygon()),
1250 Geometry::Rect(r) => polygon(&r.to_polygon()),
1251 Geometry::GeometryCollection(gc) => gc.iter().map(stored_vertex_count).sum(),
1252 }
1253}
1254
1255#[cfg(feature = "unstable-v2")]
1258fn validate_nested_kind(name: &str, kind: &NestedKind) -> MltResult<()> {
1259 if matches!(kind, NestedKind::Leaf(_)) {
1260 return Err(MltError::NestedRootIsLeaf(name.to_string()));
1261 }
1262 if kind.has_empty_map() {
1263 return Err(MltError::EmptyStructNode);
1264 }
1265 let depth = kind.depth();
1266 if depth > MAX_NESTED_DEPTH {
1267 return Err(MltError::NestedTooDeep(depth));
1268 }
1269 Ok(())
1270}
1271
1272fn validate_layer_name(name: &str) -> MltResult<()> {
1273 if name.is_empty() {
1274 Err(MltError::MissingLayerName)
1275 } else {
1276 Ok(())
1277 }
1278}
1279
1280pub(crate) fn reject_taken_name<'a>(
1284 name: &str,
1285 role: ColumnRole,
1286 taken: impl IntoIterator<Item = (&'a str, ColumnRole)>,
1287) -> MltResult<()> {
1288 for (seen, taken_by) in taken {
1289 if seen == name {
1290 return Err(MltError::DuplicateColumnName {
1291 name: name.to_string(),
1292 role,
1293 taken_by,
1294 });
1295 }
1296 }
1297 Ok(())
1298}
1299
1300fn validate_unique_names(names: &[String], role: ColumnRole) -> MltResult<()> {
1302 for (i, name) in names.iter().enumerate() {
1305 reject_taken_name(name, role, names[..i].iter().map(|n| (n.as_str(), role)))?;
1306 }
1307 Ok(())
1308}
1309
1310trait FeatureColumn: Sized {
1312 fn of(feature: &TileFeature) -> &[Self];
1314 fn column_kind(&self) -> PropKind;
1315 fn count_mismatch(expected: usize, actual: usize) -> MltError;
1317 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError;
1319}
1320
1321impl FeatureColumn for PropValue {
1322 fn of(feature: &TileFeature) -> &[Self] {
1323 &feature.properties
1324 }
1325
1326 fn column_kind(&self) -> PropKind {
1327 PropKind::from(self)
1328 }
1329
1330 fn count_mismatch(expected: usize, actual: usize) -> MltError {
1331 MltError::PropertyLengthMismatch { expected, actual }
1332 }
1333
1334 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError {
1335 MltError::PropertyKindMismatch {
1336 index,
1337 expected,
1338 actual,
1339 }
1340 }
1341}
1342
1343#[cfg(feature = "unstable-v2")]
1344impl FeatureColumn for MValue {
1345 fn of(feature: &TileFeature) -> &[Self] {
1346 &feature.m_values
1347 }
1348
1349 fn column_kind(&self) -> PropKind {
1350 self.kind()
1351 }
1352
1353 fn count_mismatch(expected: usize, actual: usize) -> MltError {
1354 MltError::MValueColumnCountMismatch { expected, actual }
1355 }
1356
1357 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError {
1358 MltError::MValueKindMismatch {
1359 index,
1360 expected,
1361 actual,
1362 }
1363 }
1364}
1365
1366fn infer_kinds<T: FeatureColumn>(
1370 names: &[String],
1371 features: &[TileFeature],
1372) -> MltResult<Vec<PropKind>> {
1373 let mut kinds = vec![None; names.len()];
1374 for feature in features {
1375 let values = T::of(feature);
1376 if values.len() != names.len() {
1377 return Err(T::count_mismatch(names.len(), values.len()));
1378 }
1379 for (index, value) in values.iter().enumerate() {
1380 let actual = value.column_kind();
1381 match kinds[index] {
1382 Some(expected) if expected != actual => {
1383 return Err(T::kind_mismatch(index, expected, actual));
1384 }
1385 None => kinds[index] = Some(actual),
1386 _ => {}
1387 }
1388 }
1389 }
1390 Ok(kinds
1391 .into_iter()
1392 .map(|kind| kind.unwrap_or(PropKind::Str))
1393 .collect())
1394}
1395
1396fn validate_kinds<T: FeatureColumn>(kinds: &[PropKind], feature: &TileFeature) -> MltResult<()> {
1398 let values = T::of(feature);
1399 if values.len() != kinds.len() {
1400 return Err(T::count_mismatch(kinds.len(), values.len()));
1401 }
1402 for (index, (value, expected)) in values.iter().zip(kinds).enumerate() {
1403 let actual = value.column_kind();
1404 if actual != *expected {
1405 return Err(T::kind_mismatch(index, *expected, actual));
1406 }
1407 }
1408 Ok(())
1409}
1410
1411#[cfg(test)]
1412mod tests {
1413 use geo_types::{Geometry, Point};
1414
1415 use super::*;
1416
1417 fn point_feature(properties: Vec<PropValue>) -> TileFeature {
1418 TileFeature {
1419 id: None,
1420 geometry: Geometry::Point(Point::new(0, 0)),
1421 properties,
1422 #[cfg(feature = "unstable-v2")]
1423 m_values: Vec::new(),
1424 #[cfg(feature = "unstable-v2")]
1425 nested: Vec::new(),
1426 #[cfg(feature = "unstable-v2")]
1427 z: Vec::new(),
1428 }
1429 }
1430
1431 #[test]
1432 fn tile_layer_constructor_rejects_empty_name() {
1433 assert!(matches!(
1434 TileLayer::new("", 4096),
1435 Err(MltError::MissingLayerName)
1436 ));
1437 }
1438
1439 #[test]
1440 fn tile_layer_constructor_rejects_zero_extent() {
1441 assert!(matches!(
1442 TileLayer::new("layer", 0),
1443 Err(MltError::InvalidExtent(0))
1444 ));
1445 }
1446
1447 #[test]
1448 fn add_property_rejects_duplicate_names() {
1449 let mut layer = TileLayer::new("layer", 4096).unwrap();
1450 layer.add_property("name", PropKind::Str).unwrap();
1451 assert_eq!(
1452 layer
1453 .add_property("name", PropKind::Str)
1454 .unwrap_err()
1455 .to_string(),
1456 "duplicate column name name: the property column repeats the property column"
1457 );
1458 }
1459
1460 #[test]
1461 fn from_parts_allows_empty_property_name() {
1462 assert!(TileLayer::from_parts("layer", 4096, vec![String::new()], vec![]).is_ok());
1464 }
1465
1466 #[test]
1467 fn from_parts_rejects_duplicate_property_name() {
1468 assert_eq!(
1469 TileLayer::from_parts("layer", 4096, vec!["dup".into(), "dup".into()], vec![])
1470 .unwrap_err()
1471 .to_string(),
1472 "duplicate column name dup: the property column repeats the property column"
1473 );
1474 }
1475
1476 #[test]
1477 fn push_feature_validates_property_count() {
1478 let mut layer = TileLayer::new("layer", 4096).unwrap();
1479 layer.add_property("name", PropKind::Str).unwrap();
1480 assert!(matches!(
1481 layer.push_feature(point_feature(vec![])),
1482 Err(MltError::PropertyLengthMismatch {
1483 expected: 1,
1484 actual: 0
1485 })
1486 ));
1487 }
1488
1489 #[test]
1490 fn push_feature_validates_property_kind() {
1491 let mut layer = TileLayer::new("layer", 4096).unwrap();
1492 layer.add_property("flag", PropKind::Bool).unwrap();
1493 layer
1494 .push_feature(point_feature(vec![PropValue::Bool(Some(true))]))
1495 .unwrap();
1496 assert!(matches!(
1497 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
1498 Err(MltError::PropertyKindMismatch {
1499 index: 0,
1500 expected: PropKind::Bool,
1501 actual: PropKind::I32,
1502 })
1503 ));
1504 }
1505
1506 #[test]
1507 fn declared_property_kind_is_enforced_for_first_feature() {
1508 let mut layer = TileLayer::new("layer", 4096).unwrap();
1509 layer.add_property("flag", PropKind::Bool).unwrap();
1510 assert!(matches!(
1511 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
1512 Err(MltError::PropertyKindMismatch {
1513 index: 0,
1514 expected: PropKind::Bool,
1515 actual: PropKind::I32,
1516 })
1517 ));
1518 }
1519
1520 #[cfg(feature = "unstable-v2")]
1521 #[test]
1522 fn push_feature_validates_m_value_count() {
1523 let mut layer = TileLayer::new("layer", 4096).unwrap();
1524 layer.add_m_value("m", PropKind::I32).unwrap();
1525 assert!(matches!(
1526 layer.push_feature(point_feature(vec![])),
1527 Err(MltError::MValueColumnCountMismatch {
1528 expected: 1,
1529 actual: 0
1530 })
1531 ));
1532 }
1533
1534 #[test]
1535 fn with_id_is_new_with_that_id() {
1536 let geometry = Geometry::Point(Point::new(1, 2));
1537 let mut expected = TileFeature::new(geometry.clone());
1538 expected.id = Some(7);
1539 assert_eq!(TileFeature::with_id(geometry, 7), expected);
1540 }
1541
1542 #[cfg(feature = "unstable-v2")]
1543 #[test]
1544 fn push_feature_validates_one_value_per_vertex() {
1545 let mut layer = TileLayer::new("layer", 4096).unwrap();
1546 layer.add_m_value("m", PropKind::I32).unwrap();
1547 let mut feature = point_feature(vec![]);
1548 feature.m_values = vec![MValue::I32(Some(vec![1, 2]))];
1549 assert!(matches!(
1550 layer.push_feature(feature),
1551 Err(MltError::MValueVertexCountMismatch {
1552 index: 0,
1553 expected: 1,
1554 actual: 2,
1555 })
1556 ));
1557 }
1558
1559 #[cfg(feature = "unstable-v2")]
1560 #[test]
1561 fn a_polygon_does_not_count_its_closing_vertices() {
1562 let ring = |pts: &[(i32, i32)]| {
1563 let mut ls = LineString::new(
1564 pts.iter()
1565 .map(|&(x, y)| geo_types::Coord { x, y })
1566 .collect(),
1567 );
1568 ls.close();
1569 ls
1570 };
1571 let poly = geo_types::Polygon::new(
1572 ring(&[(0, 0), (0, 4), (4, 4), (4, 0)]),
1573 vec![ring(&[(1, 1), (1, 2), (2, 2)])],
1574 );
1575 let feature = TileFeature::new(Geometry::Polygon(poly));
1576 assert_eq!(feature.vertex_count(), 7);
1577 }
1578
1579 #[cfg(feature = "unstable-v2")]
1580 #[test]
1581 fn a_shape_counts_its_root_as_the_first_level() {
1582 let kind = NestedKind::list(NestedKind::map([("a", NestedKind::Leaf(PropKind::I32))]));
1583 assert_eq!(kind.depth(), 3);
1584 }
1585
1586 #[cfg(feature = "unstable-v2")]
1587 #[test]
1588 fn a_map_may_leave_out_a_field_but_not_add_one() {
1589 let kind = NestedKind::map([
1590 ("a", NestedKind::Leaf(PropKind::I32)),
1591 ("b", NestedKind::Leaf(PropKind::Str)),
1592 ]);
1593 assert!(kind.accepts(&NestedValue::map([(
1594 "a",
1595 NestedValue::Leaf(PropValue::I32(Some(1)))
1596 )])));
1597 assert!(!kind.accepts(&NestedValue::map([(
1598 "c",
1599 NestedValue::Leaf(PropValue::I32(Some(1)))
1600 )])));
1601 assert!(!kind.accepts(&NestedValue::map([(
1602 "a",
1603 NestedValue::Leaf(PropValue::Str(Some("x".into())))
1604 )])));
1605 }
1606
1607 #[cfg(feature = "unstable-v2")]
1608 fn list_kind() -> NestedKind {
1609 NestedKind::list(NestedKind::Leaf(PropKind::I32))
1610 }
1611
1612 #[cfg(feature = "unstable-v2")]
1613 #[test]
1614 fn add_m_value_rejects_a_name_a_property_has() {
1615 let mut layer = TileLayer::new("layer", 4096).unwrap();
1616 layer.add_property("n", PropKind::I32).unwrap();
1617 assert_eq!(
1618 layer
1619 .add_m_value("n", PropKind::I32)
1620 .unwrap_err()
1621 .to_string(),
1622 "duplicate column name n: the m-value column repeats the property column"
1623 );
1624 }
1625
1626 #[cfg(feature = "unstable-v2")]
1627 #[test]
1628 fn add_m_value_rejects_a_name_a_nested_column_has() {
1629 let mut layer = TileLayer::new("layer", 4096).unwrap();
1630 layer.add_nested("n", list_kind()).unwrap();
1631 assert_eq!(
1632 layer
1633 .add_m_value("n", PropKind::I32)
1634 .unwrap_err()
1635 .to_string(),
1636 "duplicate column name n: the m-value column repeats the nested column"
1637 );
1638 }
1639
1640 #[cfg(feature = "unstable-v2")]
1641 #[test]
1642 fn add_m_value_rejects_duplicate_names() {
1643 let mut layer = TileLayer::new("layer", 4096).unwrap();
1644 layer.add_m_value("n", PropKind::I32).unwrap();
1645 assert_eq!(
1646 layer
1647 .add_m_value("n", PropKind::I32)
1648 .unwrap_err()
1649 .to_string(),
1650 "duplicate column name n: the m-value column repeats the m-value column"
1651 );
1652 }
1653
1654 #[cfg(feature = "unstable-v2")]
1655 #[test]
1656 fn add_property_rejects_a_name_an_m_value_has() {
1657 let mut layer = TileLayer::new("layer", 4096).unwrap();
1658 layer.add_m_value("n", PropKind::I32).unwrap();
1659 assert_eq!(
1660 layer
1661 .add_property("n", PropKind::I32)
1662 .unwrap_err()
1663 .to_string(),
1664 "duplicate column name n: the property column repeats the m-value column"
1665 );
1666 }
1667
1668 #[cfg(feature = "unstable-v2")]
1669 #[test]
1670 fn add_property_rejects_a_name_a_nested_column_has() {
1671 let mut layer = TileLayer::new("layer", 4096).unwrap();
1672 layer.add_nested("n", list_kind()).unwrap();
1673 assert_eq!(
1674 layer
1675 .add_property("n", PropKind::I32)
1676 .unwrap_err()
1677 .to_string(),
1678 "duplicate column name n: the property column repeats the nested column"
1679 );
1680 }
1681
1682 #[cfg(feature = "unstable-v2")]
1683 #[test]
1684 fn add_nested_rejects_a_name_a_property_has() {
1685 let mut layer = TileLayer::new("layer", 4096).unwrap();
1686 layer.add_property("n", PropKind::I32).unwrap();
1687 assert_eq!(
1688 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1689 "duplicate column name n: the nested column repeats the property column"
1690 );
1691 }
1692
1693 #[cfg(feature = "unstable-v2")]
1694 #[test]
1695 fn add_nested_rejects_a_name_an_m_value_already_has() {
1696 let mut layer = TileLayer::new("layer", 4096).unwrap();
1697 layer.add_m_value("n", PropKind::I32).unwrap();
1698 assert_eq!(
1699 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1700 "duplicate column name n: the nested column repeats the m-value column"
1701 );
1702 }
1703
1704 #[cfg(feature = "unstable-v2")]
1705 #[test]
1706 fn add_nested_rejects_duplicate_names() {
1707 let mut layer = TileLayer::new("layer", 4096).unwrap();
1708 layer.add_nested("n", list_kind()).unwrap();
1709 assert_eq!(
1710 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1711 "duplicate column name n: the nested column repeats the nested column"
1712 );
1713 }
1714
1715 #[cfg(feature = "unstable-v2")]
1716 #[test]
1717 fn set_nested_rejects_a_value_of_another_shape() {
1718 let mut layer = TileLayer::new("layer", 4096).unwrap();
1719 let key = layer
1720 .add_nested("n", NestedKind::list(NestedKind::Leaf(PropKind::I32)))
1721 .unwrap();
1722 let mut feature = point_feature(vec![]);
1723 feature.nested = vec![NestedValue::List(None)];
1724 assert_eq!(
1725 feature
1726 .set_nested(key, NestedValue::Map(None))
1727 .unwrap_err()
1728 .to_string(),
1729 "nested column 0 was given a value of another shape"
1730 );
1731 }
1732
1733 #[test]
1734 fn builder_uses_declared_property_kind_for_defaults() {
1735 let mut builder = TileLayer::builder("layer", 4096).unwrap();
1736 let flag = builder.add_property("flag", PropKind::Bool).unwrap();
1737 let mut feature = builder.feature(Geometry::Point(Point::new(0, 0)));
1738 feature.property(flag, PropValue::Bool(Some(true))).unwrap();
1739 feature.finish().unwrap();
1740 let layer = builder.finish();
1741
1742 assert_eq!(
1743 layer.features()[0].properties()[0],
1744 PropValue::Bool(Some(true))
1745 );
1746 }
1747}