1#[cfg(feature = "unstable-v2")]
9use std::collections::BTreeMap;
10use std::num::NonZeroU32;
11
12use geo_types::{Geometry, LineString};
13
14use crate::{MltError, MltResult};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct Extent(NonZeroU32);
22
23impl Extent {
24 pub fn new(value: u32) -> MltResult<Self> {
25 NonZeroU32::new(value)
26 .map(Self)
27 .ok_or(MltError::InvalidExtent(value))
28 }
29
30 #[must_use]
31 pub fn get(self) -> u32 {
32 self.0.get()
33 }
34}
35
36impl From<Extent> for NonZeroU32 {
37 fn from(value: Extent) -> Self {
38 value.0
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display)]
44pub enum ColumnRole {
45 #[strum(serialize = "property")]
47 Property,
48 #[cfg(feature = "unstable-v2")]
50 #[strum(serialize = "m-value")]
51 MValue,
52 #[cfg(feature = "unstable-v2")]
54 #[strum(serialize = "nested")]
55 Nested,
56}
57
58#[derive(Debug, Clone, PartialEq)]
64pub struct TileLayer {
65 pub(crate) name: String,
66 pub(crate) extent: Extent,
67 pub(crate) property_names: Vec<String>,
69 pub(crate) property_kinds: Vec<PropKind>,
71 #[cfg(feature = "unstable-v2")]
73 pub(crate) m_value_names: Vec<String>,
74 #[cfg(feature = "unstable-v2")]
76 pub(crate) m_value_kinds: Vec<PropKind>,
77 #[cfg(feature = "unstable-v2")]
79 pub(crate) nested_names: Vec<String>,
80 #[cfg(feature = "unstable-v2")]
82 pub(crate) nested_kinds: Vec<NestedKind>,
83 pub(crate) features: Vec<TileFeature>,
84}
85
86#[derive(Debug, Clone, PartialEq)]
88pub struct TileFeature {
89 pub(crate) id: Option<u64>,
90 pub(crate) geometry: Geometry<i32>,
92 pub(crate) properties: Vec<PropValue>,
95 #[cfg(feature = "unstable-v2")]
99 pub(crate) m_values: Vec<MValue>,
100 #[cfg(feature = "unstable-v2")]
102 pub(crate) nested: Vec<NestedValue>,
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub struct PropertyKey(usize);
107
108impl PropertyKey {
109 #[must_use]
110 pub fn index(self) -> usize {
111 self.0
112 }
113}
114
115#[cfg(feature = "unstable-v2")]
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118pub struct MValueKey(usize);
119
120#[cfg(feature = "unstable-v2")]
121impl MValueKey {
122 #[must_use]
123 pub fn index(self) -> usize {
124 self.0
125 }
126}
127
128#[cfg(feature = "unstable-v2")]
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131pub struct NestedKey(usize);
132
133#[cfg(feature = "unstable-v2")]
134impl NestedKey {
135 #[must_use]
136 pub fn index(self) -> usize {
137 self.0
138 }
139}
140
141#[cfg(feature = "unstable-v2")]
143pub(crate) const MAX_NESTED_DEPTH: usize = 8;
144
145#[cfg(feature = "unstable-v2")]
147#[derive(Debug, Clone, PartialEq, Eq)]
148pub enum NestedKind {
149 Leaf(PropKind),
150 List(Box<Self>),
151 Map(BTreeMap<String, Self>),
153}
154
155#[cfg(feature = "unstable-v2")]
156impl NestedKind {
157 #[must_use]
159 pub fn map<K: Into<String>>(fields: impl IntoIterator<Item = (K, Self)>) -> Self {
160 Self::Map(fields.into_iter().map(|(k, v)| (k.into(), v)).collect())
161 }
162
163 #[must_use]
165 pub fn list(element: Self) -> Self {
166 Self::List(Box::new(element))
167 }
168
169 #[must_use]
171 pub fn depth(&self) -> usize {
172 1 + match self {
173 Self::Leaf(_) => 0,
174 Self::List(element) => element.depth(),
175 Self::Map(fields) => fields.values().map(Self::depth).max().unwrap_or(0),
176 }
177 }
178
179 #[must_use]
181 pub fn null_value(&self) -> NestedValue {
182 match self {
183 Self::Leaf(kind) => NestedValue::Leaf(PropValue::null(*kind)),
184 Self::List(_) => NestedValue::List(None),
185 Self::Map(_) => NestedValue::Map(None),
186 }
187 }
188
189 #[must_use]
193 pub fn accepts(&self, value: &NestedValue) -> bool {
194 match (self, value) {
195 (Self::Leaf(kind), NestedValue::Leaf(value)) => value.kind() == *kind,
196 (Self::List(_), NestedValue::List(None)) | (Self::Map(_), NestedValue::Map(None)) => {
197 true
198 }
199 (Self::List(element), NestedValue::List(Some(items))) => {
200 items.iter().all(|item| element.accepts(item))
201 }
202 (Self::Map(fields), NestedValue::Map(Some(entries))) => entries
203 .iter()
204 .all(|(key, value)| fields.get(key).is_some_and(|kind| kind.accepts(value))),
205 _ => false,
206 }
207 }
208
209 fn has_empty_map(&self) -> bool {
211 match self {
212 Self::Leaf(_) => false,
213 Self::List(element) => element.has_empty_map(),
214 Self::Map(fields) => fields.is_empty() || fields.values().any(Self::has_empty_map),
215 }
216 }
217}
218
219#[cfg(feature = "unstable-v2")]
223#[derive(Debug, Clone, PartialEq)]
224pub enum NestedValue {
225 Leaf(PropValue),
226 List(Option<Vec<Self>>),
227 Map(Option<BTreeMap<String, Self>>),
228}
229
230#[cfg(feature = "unstable-v2")]
231impl NestedValue {
232 #[must_use]
234 pub fn map<K: Into<String>>(entries: impl IntoIterator<Item = (K, Self)>) -> Self {
235 Self::Map(Some(
236 entries.into_iter().map(|(k, v)| (k.into(), v)).collect(),
237 ))
238 }
239
240 #[must_use]
242 pub fn list(items: impl IntoIterator<Item = Self>) -> Self {
243 Self::List(Some(items.into_iter().collect()))
244 }
245
246 #[must_use]
248 pub fn is_null(&self) -> bool {
249 match self {
250 Self::Leaf(value) => value.is_null(),
251 Self::List(items) => items.is_none(),
252 Self::Map(entries) => entries.is_none(),
253 }
254 }
255
256 #[must_use]
258 pub(crate) fn heap_bytes(&self) -> usize {
259 match self {
260 Self::Leaf(PropValue::Str(Some(value))) => value.len(),
261 Self::Leaf(_) => size_of::<PropValue>(),
262 Self::List(items) => items.iter().flatten().map(Self::heap_bytes).sum::<usize>(),
263 Self::Map(entries) => entries
264 .iter()
265 .flatten()
266 .map(|(key, value)| key.len() + value.heap_bytes())
267 .sum(),
268 }
269 }
270
271 fn same_shape(&self, other: &Self) -> bool {
274 matches!(
275 (self, other),
276 (Self::Leaf(_), Self::Leaf(_))
277 | (Self::List(_), Self::List(_))
278 | (Self::Map(_), Self::Map(_))
279 )
280 }
281}
282
283impl TileLayer {
284 pub fn new(name: impl Into<String>, extent: u32) -> MltResult<Self> {
285 Self::with_capacity(name, extent, 0)
286 }
287
288 pub fn with_capacity(name: impl Into<String>, extent: u32, features: usize) -> MltResult<Self> {
289 let name = name.into();
290 validate_layer_name(&name)?;
291 let extent = Extent::new(extent)?;
292 Ok(Self {
293 name,
294 extent,
295 property_names: Vec::new(),
296 property_kinds: Vec::new(),
297 #[cfg(feature = "unstable-v2")]
298 m_value_names: Vec::new(),
299 #[cfg(feature = "unstable-v2")]
300 m_value_kinds: Vec::new(),
301 #[cfg(feature = "unstable-v2")]
302 nested_names: Vec::new(),
303 #[cfg(feature = "unstable-v2")]
304 nested_kinds: Vec::new(),
305 features: Vec::with_capacity(features),
306 })
307 }
308
309 pub(crate) fn from_parts(
310 name: impl Into<String>,
311 extent: u32,
312 property_names: Vec<String>,
313 features: Vec<TileFeature>,
314 ) -> MltResult<Self> {
315 let name = name.into();
316 validate_layer_name(&name)?;
317 let extent = Extent::new(extent)?;
318 validate_unique_names(&property_names, ColumnRole::Property)?;
319 let property_kinds = infer_kinds::<PropValue>(&property_names, &features)?;
320 let layer = Self {
321 name,
322 extent,
323 property_names,
324 property_kinds,
325 #[cfg(feature = "unstable-v2")]
326 m_value_names: Vec::new(),
327 #[cfg(feature = "unstable-v2")]
328 m_value_kinds: Vec::new(),
329 #[cfg(feature = "unstable-v2")]
330 nested_names: Vec::new(),
331 #[cfg(feature = "unstable-v2")]
332 nested_kinds: Vec::new(),
333 features,
334 };
335 Ok(layer)
336 }
337
338 #[must_use]
339 pub fn name(&self) -> &str {
340 &self.name
341 }
342
343 #[must_use]
344 pub fn extent(&self) -> Extent {
345 self.extent
346 }
347
348 #[must_use]
349 pub fn property_names(&self) -> &[String] {
350 &self.property_names
351 }
352
353 #[must_use]
354 pub fn features(&self) -> &[TileFeature] {
355 &self.features
356 }
357
358 #[must_use]
359 pub(crate) fn features_mut(&mut self) -> &mut [TileFeature] {
360 &mut self.features
361 }
362
363 pub(crate) fn widen_8bit_ints(&mut self) {
365 for kind in &mut self.property_kinds {
366 if *kind == PropKind::I8 {
367 *kind = PropKind::I32;
368 } else if *kind == PropKind::U8 {
369 *kind = PropKind::U32;
370 }
371 }
372 for prop in self.features.iter_mut().flat_map(|f| &mut f.properties) {
373 if let PropValue::I8(v) = *prop {
374 *prop = PropValue::I32(v.map(i32::from));
375 } else if let PropValue::U8(v) = *prop {
376 *prop = PropValue::U32(v.map(u32::from));
377 }
378 }
379 }
380
381 #[must_use]
382 pub fn feature_count(&self) -> usize {
383 self.features.len()
384 }
385
386 fn reject_name_in_use(&self, name: &str, role: ColumnRole) -> MltResult<()> {
388 let taken = self
389 .property_names
390 .iter()
391 .map(|n| (n.as_str(), ColumnRole::Property));
392 #[cfg(feature = "unstable-v2")]
393 let taken = taken
394 .chain(
395 self.m_value_names
396 .iter()
397 .map(|n| (n.as_str(), ColumnRole::MValue)),
398 )
399 .chain(
400 self.nested_names
401 .iter()
402 .map(|n| (n.as_str(), ColumnRole::Nested)),
403 );
404 reject_taken_name(name, role, taken)
405 }
406
407 pub fn add_property(
408 &mut self,
409 name: impl Into<String>,
410 kind: PropKind,
411 ) -> MltResult<PropertyKey> {
412 let name = name.into();
413 self.reject_name_in_use(&name, ColumnRole::Property)?;
414 for feature in &mut self.features {
415 feature.properties.push(PropValue::null(kind));
416 }
417 self.property_names.push(name);
418 self.property_kinds.push(kind);
419 Ok(PropertyKey(self.property_names.len() - 1))
420 }
421
422 #[cfg(feature = "unstable-v2")]
423 #[must_use]
424 pub fn m_value_names(&self) -> &[String] {
425 &self.m_value_names
426 }
427
428 #[cfg(feature = "unstable-v2")]
429 #[must_use]
430 pub fn m_value_kinds(&self) -> &[PropKind] {
431 &self.m_value_kinds
432 }
433
434 #[cfg(feature = "unstable-v2")]
436 pub fn add_m_value(&mut self, name: impl Into<String>, kind: PropKind) -> MltResult<MValueKey> {
437 let name = name.into();
438 self.reject_name_in_use(&name, ColumnRole::MValue)?;
439 for feature in &mut self.features {
440 feature.m_values.push(MValue::null(kind));
441 }
442 self.m_value_names.push(name);
443 self.m_value_kinds.push(kind);
444 Ok(MValueKey(self.m_value_names.len() - 1))
445 }
446
447 #[cfg(feature = "unstable-v2")]
450 pub(crate) fn with_m_value_names(mut self, names: Vec<String>) -> MltResult<Self> {
451 validate_unique_names(&names, ColumnRole::MValue)?;
452 for name in &names {
453 self.reject_name_in_use(name, ColumnRole::MValue)?;
454 }
455 self.m_value_kinds = infer_kinds::<MValue>(&names, &self.features)?;
456 self.m_value_names = names;
457 for feature in &self.features {
458 self.validate_m_values(feature)?;
459 }
460 Ok(self)
461 }
462
463 #[cfg(feature = "unstable-v2")]
464 #[must_use]
465 pub fn nested_names(&self) -> &[String] {
466 &self.nested_names
467 }
468
469 #[cfg(feature = "unstable-v2")]
470 #[must_use]
471 pub fn nested_kinds(&self) -> &[NestedKind] {
472 &self.nested_kinds
473 }
474
475 #[cfg(feature = "unstable-v2")]
479 pub fn add_nested(
480 &mut self,
481 name: impl Into<String>,
482 kind: NestedKind,
483 ) -> MltResult<NestedKey> {
484 let name = name.into();
485 self.reject_name_in_use(&name, ColumnRole::Nested)?;
486 validate_nested_kind(&name, &kind)?;
487 for feature in &mut self.features {
488 feature.nested.push(kind.null_value());
489 }
490 self.nested_names.push(name);
491 self.nested_kinds.push(kind);
492 Ok(NestedKey(self.nested_names.len() - 1))
493 }
494
495 #[cfg(feature = "unstable-v2")]
498 pub(crate) fn with_nested(
499 mut self,
500 names: Vec<String>,
501 kinds: Vec<NestedKind>,
502 ) -> MltResult<Self> {
503 validate_unique_names(&names, ColumnRole::Nested)?;
504 for name in &names {
505 self.reject_name_in_use(name, ColumnRole::Nested)?;
506 }
507 for (name, kind) in names.iter().zip(&kinds) {
508 validate_nested_kind(name, kind)?;
509 }
510 self.nested_names = names;
511 self.nested_kinds = kinds;
512 for feature in &self.features {
513 self.validate_nested(feature)?;
514 }
515 Ok(self)
516 }
517
518 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
519 self.validate_feature(&feature)?;
520 self.features.push(feature);
521 Ok(())
522 }
523
524 pub fn builder(name: impl Into<String>, extent: u32) -> MltResult<TileLayerBuilder> {
525 Ok(TileLayerBuilder {
526 layer: Self::new(name, extent)?,
527 })
528 }
529
530 fn validate_feature(&self, feature: &TileFeature) -> MltResult<()> {
531 validate_kinds::<PropValue>(&self.property_kinds, feature)?;
532 #[cfg(feature = "unstable-v2")]
533 self.validate_m_values(feature)?;
534 #[cfg(feature = "unstable-v2")]
535 self.validate_nested(feature)?;
536 Ok(())
537 }
538
539 #[cfg(feature = "unstable-v2")]
542 fn validate_nested(&self, feature: &TileFeature) -> MltResult<()> {
543 if feature.nested.len() != self.nested_kinds.len() {
544 return Err(MltError::NestedColumnCountMismatch {
545 expected: self.nested_kinds.len(),
546 actual: feature.nested.len(),
547 });
548 }
549 for (index, (value, kind)) in feature.nested.iter().zip(&self.nested_kinds).enumerate() {
550 if !kind.accepts(value) {
551 return Err(MltError::NestedValueMismatch {
552 index,
553 name: self.nested_names[index].clone(),
554 });
555 }
556 }
557 Ok(())
558 }
559
560 #[cfg(feature = "unstable-v2")]
563 fn validate_m_values(&self, feature: &TileFeature) -> MltResult<()> {
564 validate_kinds::<MValue>(&self.m_value_kinds, feature)?;
565 let vertices = feature.vertex_count();
566 for (index, m_value) in feature.m_values.iter().enumerate() {
567 if let Some(len) = m_value.count()
568 && len != vertices
569 {
570 return Err(MltError::MValueVertexCountMismatch {
571 index,
572 expected: vertices,
573 actual: len,
574 });
575 }
576 }
577 Ok(())
578 }
579}
580
581impl TileFeature {
582 #[must_use]
583 pub fn new(geometry: Geometry<i32>) -> Self {
584 Self {
585 id: None,
586 geometry,
587 properties: Vec::new(),
588 #[cfg(feature = "unstable-v2")]
589 m_values: Vec::new(),
590 #[cfg(feature = "unstable-v2")]
591 nested: Vec::new(),
592 }
593 }
594
595 #[must_use]
596 pub fn with_id(geometry: Geometry<i32>, id: u64) -> Self {
597 Self {
598 id: Some(id),
599 geometry,
600 properties: Vec::new(),
601 #[cfg(feature = "unstable-v2")]
602 m_values: Vec::new(),
603 #[cfg(feature = "unstable-v2")]
604 nested: Vec::new(),
605 }
606 }
607
608 #[must_use]
609 pub fn id(&self) -> Option<u64> {
610 self.id
611 }
612
613 #[must_use]
614 pub fn geometry(&self) -> &Geometry<i32> {
615 &self.geometry
616 }
617
618 #[must_use]
619 pub fn properties(&self) -> &[PropValue] {
620 &self.properties
621 }
622
623 #[must_use]
624 pub(crate) fn properties_mut(&mut self) -> &mut [PropValue] {
625 &mut self.properties
626 }
627
628 #[cfg(feature = "unstable-v2")]
633 #[must_use]
634 pub fn vertex_count(&self) -> usize {
635 stored_vertex_count(&self.geometry)
636 }
637
638 #[cfg(feature = "unstable-v2")]
639 #[must_use]
640 pub fn m_values(&self) -> &[MValue] {
641 &self.m_values
642 }
643
644 #[cfg(feature = "unstable-v2")]
647 pub fn set_m_value(&mut self, key: MValueKey, value: MValue) -> MltResult<()> {
648 let vertices = self.vertex_count();
649 let Some(slot) = self.m_values.get_mut(key.index()) else {
650 return Err(MltError::UnknownMValueKey {
651 index: key.index(),
652 columns: self.m_values.len(),
653 });
654 };
655 let expected = slot.kind();
656 let actual = value.kind();
657 if actual != expected {
658 return Err(MltError::MValueKindMismatch {
659 index: key.index(),
660 expected,
661 actual,
662 });
663 }
664 if let Some(len) = value.count()
665 && len != vertices
666 {
667 return Err(MltError::MValueVertexCountMismatch {
668 index: key.index(),
669 expected: vertices,
670 actual: len,
671 });
672 }
673 *slot = value;
674 Ok(())
675 }
676
677 #[cfg(feature = "unstable-v2")]
678 #[must_use]
679 pub fn nested(&self) -> &[NestedValue] {
680 &self.nested
681 }
682
683 #[cfg(feature = "unstable-v2")]
689 pub fn set_nested(&mut self, key: NestedKey, value: NestedValue) -> MltResult<()> {
690 let columns = self.nested.len();
691 let Some(slot) = self.nested.get_mut(key.index()) else {
692 return Err(MltError::UnknownNestedKey {
693 index: key.index(),
694 columns,
695 });
696 };
697 if !slot.same_shape(&value) {
698 return Err(MltError::NestedShapeMismatch { index: key.index() });
699 }
700 *slot = value;
701 Ok(())
702 }
703
704 pub fn set_property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<()> {
705 let Some(prop) = self.properties.get_mut(key.index()) else {
706 return Err(MltError::PropertyLengthMismatch {
707 expected: key.index() + 1,
708 actual: self.properties.len(),
709 });
710 };
711 let expected = PropKind::from(&*prop);
712 let actual = PropKind::from(&value);
713 if actual != expected {
714 return Err(MltError::PropertyKindMismatch {
715 index: key.index(),
716 expected,
717 actual,
718 });
719 }
720 *prop = value;
721 Ok(())
722 }
723}
724
725pub struct TileLayerBuilder {
726 layer: TileLayer,
727}
728
729impl TileLayerBuilder {
730 pub fn add_property(
731 &mut self,
732 name: impl Into<String>,
733 kind: PropKind,
734 ) -> MltResult<PropertyKey> {
735 self.layer.add_property(name, kind)
736 }
737
738 #[cfg(feature = "unstable-v2")]
739 pub fn add_m_value(&mut self, name: impl Into<String>, kind: PropKind) -> MltResult<MValueKey> {
740 self.layer.add_m_value(name, kind)
741 }
742
743 #[cfg(feature = "unstable-v2")]
744 pub fn add_nested(
745 &mut self,
746 name: impl Into<String>,
747 kind: NestedKind,
748 ) -> MltResult<NestedKey> {
749 self.layer.add_nested(name, kind)
750 }
751
752 pub fn feature(&mut self, geometry: Geometry<i32>) -> TileFeatureBuilder<'_> {
753 let properties = self
754 .layer
755 .property_kinds
756 .iter()
757 .copied()
758 .map(PropValue::null)
759 .collect();
760 #[cfg(feature = "unstable-v2")]
761 let m_values = self
762 .layer
763 .m_value_kinds
764 .iter()
765 .copied()
766 .map(MValue::null)
767 .collect();
768 #[cfg(feature = "unstable-v2")]
769 let nested = self
770 .layer
771 .nested_kinds
772 .iter()
773 .map(NestedKind::null_value)
774 .collect();
775 TileFeatureBuilder {
776 layer: self,
777 feature: TileFeature {
778 id: None,
779 geometry,
780 properties,
781 #[cfg(feature = "unstable-v2")]
782 m_values,
783 #[cfg(feature = "unstable-v2")]
784 nested,
785 },
786 }
787 }
788
789 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
790 self.layer.push_feature(feature)
791 }
792
793 #[must_use]
794 pub fn finish(self) -> TileLayer {
795 self.layer
796 }
797}
798
799pub struct TileFeatureBuilder<'a> {
800 layer: &'a mut TileLayerBuilder,
801 feature: TileFeature,
802}
803
804impl TileFeatureBuilder<'_> {
805 pub fn id(&mut self, id: Option<u64>) -> &mut Self {
806 self.feature.id = id;
807 self
808 }
809
810 pub fn property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<&mut Self> {
811 self.feature.set_property(key, value)?;
812 Ok(self)
813 }
814
815 #[cfg(feature = "unstable-v2")]
816 pub fn m_value(&mut self, key: MValueKey, value: MValue) -> MltResult<&mut Self> {
817 self.feature.set_m_value(key, value)?;
818 Ok(self)
819 }
820
821 #[cfg(feature = "unstable-v2")]
822 pub fn nested(&mut self, key: NestedKey, value: NestedValue) -> MltResult<&mut Self> {
823 self.feature.set_nested(key, value)?;
824 Ok(self)
825 }
826
827 pub fn finish(self) -> MltResult<()> {
828 self.layer.push_feature(self.feature)
829 }
830}
831
832#[derive(Debug, Clone, PartialEq)]
840pub enum PropValue {
841 Bool(Option<bool>),
842 I8(Option<i8>),
843 U8(Option<u8>),
844 I32(Option<i32>),
845 U32(Option<u32>),
846 I64(Option<i64>),
847 U64(Option<u64>),
848 F32(Option<f32>),
849 F64(Option<f64>),
850 Str(Option<String>),
851}
852
853impl PropValue {
854 #[must_use]
855 pub fn kind(&self) -> PropKind {
856 self.into()
857 }
858}
859
860#[cfg(feature = "unstable-v2")]
865#[derive(Debug, Clone, PartialEq)]
866pub enum MValue {
867 Bool(Option<Vec<bool>>),
868 I8(Option<Vec<i8>>),
869 U8(Option<Vec<u8>>),
870 I32(Option<Vec<i32>>),
871 U32(Option<Vec<u32>>),
872 I64(Option<Vec<i64>>),
873 U64(Option<Vec<u64>>),
874 F32(Option<Vec<f32>>),
875 F64(Option<Vec<f64>>),
876 Str(Option<Vec<String>>),
877}
878
879#[cfg(feature = "unstable-v2")]
880impl MValue {
881 #[must_use]
882 pub fn is_null(&self) -> bool {
883 self.count().is_none()
884 }
885}
886
887macro_rules! kind_mappings {
888 (
889 scalar { $($sv:ident),* $(,)? }
890 string { $($gv:ident),* $(,)? }
891 ) => {
892 #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::IntoStaticStr)]
894 #[strum(serialize_all = "lowercase")]
895 pub enum PropKind {
896 $($sv,)*
897 $($gv,)*
898 }
899
900 impl From<&PropValue> for PropKind {
901 fn from(prop: &PropValue) -> Self {
902 match prop {
903 $(PropValue::$sv(_) => Self::$sv,)*
904 $(PropValue::$gv(_) => Self::$gv,)*
905 }
906 }
907 }
908
909 impl PropValue {
910 #[must_use]
911 pub fn is_null(&self) -> bool {
912 match self {
913 $(Self::$sv(v) => v.is_none(),)*
914 $(Self::$gv(v) => v.is_none(),)*
915 }
916 }
917
918 #[must_use]
920 pub fn null(kind: PropKind) -> Self {
921 match kind {
922 $(PropKind::$sv => Self::$sv(None),)*
923 $(PropKind::$gv => Self::$gv(None),)*
924 }
925 }
926 }
927
928 #[cfg(feature = "unstable-v2")]
929 impl MValue {
930 #[must_use]
931 pub fn kind(&self) -> PropKind {
932 match self {
933 $(Self::$sv(_) => PropKind::$sv,)*
934 $(Self::$gv(_) => PropKind::$gv,)*
935 }
936 }
937
938 #[must_use]
940 pub fn count(&self) -> Option<usize> {
941 match self {
942 $(Self::$sv(v) => v.as_ref().map(Vec::len),)*
943 $(Self::$gv(v) => v.as_ref().map(Vec::len),)*
944 }
945 }
946
947 #[must_use]
949 pub fn null(kind: PropKind) -> Self {
950 match kind {
951 $(PropKind::$sv => Self::$sv(None),)*
952 $(PropKind::$gv => Self::$gv(None),)*
953 }
954 }
955 }
956 };
957}
958
959with_kinds!(kind_mappings);
960
961pub(crate) fn stored_ring_len(ring: &LineString<i32>) -> usize {
963 let coords = &ring.0;
964 if coords.len() > 1 && coords.last() == coords.first() {
965 coords.len() - 1
966 } else {
967 coords.len()
968 }
969}
970
971#[cfg(feature = "unstable-v2")]
974pub(crate) fn stored_vertex_count(geom: &Geometry<i32>) -> usize {
975 let polygon = |poly: &geo_types::Polygon<i32>| {
976 std::iter::once(poly.exterior())
977 .chain(poly.interiors())
978 .map(stored_ring_len)
979 .sum::<usize>()
980 };
981 match geom {
982 Geometry::Point(_) => 1,
983 Geometry::Line(_) => 2,
984 Geometry::LineString(ls) => ls.0.len(),
985 Geometry::Polygon(p) => polygon(p),
986 Geometry::MultiPoint(mp) => mp.0.len(),
987 Geometry::MultiLineString(mls) => mls.iter().map(|ls| ls.0.len()).sum(),
988 Geometry::MultiPolygon(mp) => mp.iter().map(polygon).sum(),
989 Geometry::Triangle(t) => polygon(&t.to_polygon()),
990 Geometry::Rect(r) => polygon(&r.to_polygon()),
991 Geometry::GeometryCollection(gc) => gc.iter().map(stored_vertex_count).sum(),
992 }
993}
994
995#[cfg(feature = "unstable-v2")]
998fn validate_nested_kind(name: &str, kind: &NestedKind) -> MltResult<()> {
999 if matches!(kind, NestedKind::Leaf(_)) {
1000 return Err(MltError::NestedRootIsLeaf(name.to_string()));
1001 }
1002 if kind.has_empty_map() {
1003 return Err(MltError::EmptyStructNode);
1004 }
1005 let depth = kind.depth();
1006 if depth > MAX_NESTED_DEPTH {
1007 return Err(MltError::NestedTooDeep(depth));
1008 }
1009 Ok(())
1010}
1011
1012fn validate_layer_name(name: &str) -> MltResult<()> {
1013 if name.is_empty() {
1014 Err(MltError::MissingLayerName)
1015 } else {
1016 Ok(())
1017 }
1018}
1019
1020pub(crate) fn reject_taken_name<'a>(
1024 name: &str,
1025 role: ColumnRole,
1026 taken: impl IntoIterator<Item = (&'a str, ColumnRole)>,
1027) -> MltResult<()> {
1028 for (seen, taken_by) in taken {
1029 if seen == name {
1030 return Err(MltError::DuplicateColumnName {
1031 name: name.to_string(),
1032 role,
1033 taken_by,
1034 });
1035 }
1036 }
1037 Ok(())
1038}
1039
1040fn validate_unique_names(names: &[String], role: ColumnRole) -> MltResult<()> {
1042 for (i, name) in names.iter().enumerate() {
1045 reject_taken_name(name, role, names[..i].iter().map(|n| (n.as_str(), role)))?;
1046 }
1047 Ok(())
1048}
1049
1050trait FeatureColumn: Sized {
1052 fn of(feature: &TileFeature) -> &[Self];
1054 fn column_kind(&self) -> PropKind;
1055 fn count_mismatch(expected: usize, actual: usize) -> MltError;
1057 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError;
1059}
1060
1061impl FeatureColumn for PropValue {
1062 fn of(feature: &TileFeature) -> &[Self] {
1063 &feature.properties
1064 }
1065
1066 fn column_kind(&self) -> PropKind {
1067 PropKind::from(self)
1068 }
1069
1070 fn count_mismatch(expected: usize, actual: usize) -> MltError {
1071 MltError::PropertyLengthMismatch { expected, actual }
1072 }
1073
1074 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError {
1075 MltError::PropertyKindMismatch {
1076 index,
1077 expected,
1078 actual,
1079 }
1080 }
1081}
1082
1083#[cfg(feature = "unstable-v2")]
1084impl FeatureColumn for MValue {
1085 fn of(feature: &TileFeature) -> &[Self] {
1086 &feature.m_values
1087 }
1088
1089 fn column_kind(&self) -> PropKind {
1090 self.kind()
1091 }
1092
1093 fn count_mismatch(expected: usize, actual: usize) -> MltError {
1094 MltError::MValueColumnCountMismatch { expected, actual }
1095 }
1096
1097 fn kind_mismatch(index: usize, expected: PropKind, actual: PropKind) -> MltError {
1098 MltError::MValueKindMismatch {
1099 index,
1100 expected,
1101 actual,
1102 }
1103 }
1104}
1105
1106fn infer_kinds<T: FeatureColumn>(
1110 names: &[String],
1111 features: &[TileFeature],
1112) -> MltResult<Vec<PropKind>> {
1113 let mut kinds = vec![None; names.len()];
1114 for feature in features {
1115 let values = T::of(feature);
1116 if values.len() != names.len() {
1117 return Err(T::count_mismatch(names.len(), values.len()));
1118 }
1119 for (index, value) in values.iter().enumerate() {
1120 let actual = value.column_kind();
1121 match kinds[index] {
1122 Some(expected) if expected != actual => {
1123 return Err(T::kind_mismatch(index, expected, actual));
1124 }
1125 None => kinds[index] = Some(actual),
1126 _ => {}
1127 }
1128 }
1129 }
1130 Ok(kinds
1131 .into_iter()
1132 .map(|kind| kind.unwrap_or(PropKind::Str))
1133 .collect())
1134}
1135
1136fn validate_kinds<T: FeatureColumn>(kinds: &[PropKind], feature: &TileFeature) -> MltResult<()> {
1138 let values = T::of(feature);
1139 if values.len() != kinds.len() {
1140 return Err(T::count_mismatch(kinds.len(), values.len()));
1141 }
1142 for (index, (value, expected)) in values.iter().zip(kinds).enumerate() {
1143 let actual = value.column_kind();
1144 if actual != *expected {
1145 return Err(T::kind_mismatch(index, *expected, actual));
1146 }
1147 }
1148 Ok(())
1149}
1150
1151#[cfg(test)]
1152mod tests {
1153 use geo_types::{Geometry, Point};
1154
1155 use super::*;
1156
1157 fn point_feature(properties: Vec<PropValue>) -> TileFeature {
1158 TileFeature {
1159 id: None,
1160 geometry: Geometry::Point(Point::new(0, 0)),
1161 properties,
1162 #[cfg(feature = "unstable-v2")]
1163 m_values: Vec::new(),
1164 #[cfg(feature = "unstable-v2")]
1165 nested: Vec::new(),
1166 }
1167 }
1168
1169 #[test]
1170 fn tile_layer_constructor_rejects_empty_name() {
1171 assert!(matches!(
1172 TileLayer::new("", 4096),
1173 Err(MltError::MissingLayerName)
1174 ));
1175 }
1176
1177 #[test]
1178 fn tile_layer_constructor_rejects_zero_extent() {
1179 assert!(matches!(
1180 TileLayer::new("layer", 0),
1181 Err(MltError::InvalidExtent(0))
1182 ));
1183 }
1184
1185 #[test]
1186 fn add_property_rejects_duplicate_names() {
1187 let mut layer = TileLayer::new("layer", 4096).unwrap();
1188 layer.add_property("name", PropKind::Str).unwrap();
1189 assert_eq!(
1190 layer
1191 .add_property("name", PropKind::Str)
1192 .unwrap_err()
1193 .to_string(),
1194 "duplicate column name name: the property column repeats the property column"
1195 );
1196 }
1197
1198 #[test]
1199 fn from_parts_allows_empty_property_name() {
1200 assert!(TileLayer::from_parts("layer", 4096, vec![String::new()], vec![]).is_ok());
1202 }
1203
1204 #[test]
1205 fn from_parts_rejects_duplicate_property_name() {
1206 assert_eq!(
1207 TileLayer::from_parts("layer", 4096, vec!["dup".into(), "dup".into()], vec![])
1208 .unwrap_err()
1209 .to_string(),
1210 "duplicate column name dup: the property column repeats the property column"
1211 );
1212 }
1213
1214 #[test]
1215 fn push_feature_validates_property_count() {
1216 let mut layer = TileLayer::new("layer", 4096).unwrap();
1217 layer.add_property("name", PropKind::Str).unwrap();
1218 assert!(matches!(
1219 layer.push_feature(point_feature(vec![])),
1220 Err(MltError::PropertyLengthMismatch {
1221 expected: 1,
1222 actual: 0
1223 })
1224 ));
1225 }
1226
1227 #[test]
1228 fn push_feature_validates_property_kind() {
1229 let mut layer = TileLayer::new("layer", 4096).unwrap();
1230 layer.add_property("flag", PropKind::Bool).unwrap();
1231 layer
1232 .push_feature(point_feature(vec![PropValue::Bool(Some(true))]))
1233 .unwrap();
1234 assert!(matches!(
1235 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
1236 Err(MltError::PropertyKindMismatch {
1237 index: 0,
1238 expected: PropKind::Bool,
1239 actual: PropKind::I32,
1240 })
1241 ));
1242 }
1243
1244 #[test]
1245 fn declared_property_kind_is_enforced_for_first_feature() {
1246 let mut layer = TileLayer::new("layer", 4096).unwrap();
1247 layer.add_property("flag", PropKind::Bool).unwrap();
1248 assert!(matches!(
1249 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
1250 Err(MltError::PropertyKindMismatch {
1251 index: 0,
1252 expected: PropKind::Bool,
1253 actual: PropKind::I32,
1254 })
1255 ));
1256 }
1257
1258 #[cfg(feature = "unstable-v2")]
1259 #[test]
1260 fn push_feature_validates_m_value_count() {
1261 let mut layer = TileLayer::new("layer", 4096).unwrap();
1262 layer.add_m_value("m", PropKind::I32).unwrap();
1263 assert!(matches!(
1264 layer.push_feature(point_feature(vec![])),
1265 Err(MltError::MValueColumnCountMismatch {
1266 expected: 1,
1267 actual: 0
1268 })
1269 ));
1270 }
1271
1272 #[cfg(feature = "unstable-v2")]
1273 #[test]
1274 fn push_feature_validates_one_value_per_vertex() {
1275 let mut layer = TileLayer::new("layer", 4096).unwrap();
1276 layer.add_m_value("m", PropKind::I32).unwrap();
1277 let mut feature = point_feature(vec![]);
1278 feature.m_values = vec![MValue::I32(Some(vec![1, 2]))];
1279 assert!(matches!(
1280 layer.push_feature(feature),
1281 Err(MltError::MValueVertexCountMismatch {
1282 index: 0,
1283 expected: 1,
1284 actual: 2,
1285 })
1286 ));
1287 }
1288
1289 #[cfg(feature = "unstable-v2")]
1290 #[test]
1291 fn a_polygon_does_not_count_its_closing_vertices() {
1292 let ring = |pts: &[(i32, i32)]| {
1293 let mut ls = LineString::new(
1294 pts.iter()
1295 .map(|&(x, y)| geo_types::Coord { x, y })
1296 .collect(),
1297 );
1298 ls.close();
1299 ls
1300 };
1301 let poly = geo_types::Polygon::new(
1302 ring(&[(0, 0), (0, 4), (4, 4), (4, 0)]),
1303 vec![ring(&[(1, 1), (1, 2), (2, 2)])],
1304 );
1305 let feature = TileFeature::new(Geometry::Polygon(poly));
1306 assert_eq!(feature.vertex_count(), 7);
1307 }
1308
1309 #[cfg(feature = "unstable-v2")]
1310 #[test]
1311 fn a_shape_counts_its_root_as_the_first_level() {
1312 let kind = NestedKind::list(NestedKind::map([("a", NestedKind::Leaf(PropKind::I32))]));
1313 assert_eq!(kind.depth(), 3);
1314 }
1315
1316 #[cfg(feature = "unstable-v2")]
1317 #[test]
1318 fn a_map_may_leave_out_a_field_but_not_add_one() {
1319 let kind = NestedKind::map([
1320 ("a", NestedKind::Leaf(PropKind::I32)),
1321 ("b", NestedKind::Leaf(PropKind::Str)),
1322 ]);
1323 assert!(kind.accepts(&NestedValue::map([(
1324 "a",
1325 NestedValue::Leaf(PropValue::I32(Some(1)))
1326 )])));
1327 assert!(!kind.accepts(&NestedValue::map([(
1328 "c",
1329 NestedValue::Leaf(PropValue::I32(Some(1)))
1330 )])));
1331 assert!(!kind.accepts(&NestedValue::map([(
1332 "a",
1333 NestedValue::Leaf(PropValue::Str(Some("x".into())))
1334 )])));
1335 }
1336
1337 #[cfg(feature = "unstable-v2")]
1338 fn list_kind() -> NestedKind {
1339 NestedKind::list(NestedKind::Leaf(PropKind::I32))
1340 }
1341
1342 #[cfg(feature = "unstable-v2")]
1343 #[test]
1344 fn add_m_value_rejects_a_name_a_property_has() {
1345 let mut layer = TileLayer::new("layer", 4096).unwrap();
1346 layer.add_property("n", PropKind::I32).unwrap();
1347 assert_eq!(
1348 layer
1349 .add_m_value("n", PropKind::I32)
1350 .unwrap_err()
1351 .to_string(),
1352 "duplicate column name n: the m-value column repeats the property column"
1353 );
1354 }
1355
1356 #[cfg(feature = "unstable-v2")]
1357 #[test]
1358 fn add_m_value_rejects_a_name_a_nested_column_has() {
1359 let mut layer = TileLayer::new("layer", 4096).unwrap();
1360 layer.add_nested("n", list_kind()).unwrap();
1361 assert_eq!(
1362 layer
1363 .add_m_value("n", PropKind::I32)
1364 .unwrap_err()
1365 .to_string(),
1366 "duplicate column name n: the m-value column repeats the nested column"
1367 );
1368 }
1369
1370 #[cfg(feature = "unstable-v2")]
1371 #[test]
1372 fn add_m_value_rejects_duplicate_names() {
1373 let mut layer = TileLayer::new("layer", 4096).unwrap();
1374 layer.add_m_value("n", PropKind::I32).unwrap();
1375 assert_eq!(
1376 layer
1377 .add_m_value("n", PropKind::I32)
1378 .unwrap_err()
1379 .to_string(),
1380 "duplicate column name n: the m-value column repeats the m-value column"
1381 );
1382 }
1383
1384 #[cfg(feature = "unstable-v2")]
1385 #[test]
1386 fn add_property_rejects_a_name_an_m_value_has() {
1387 let mut layer = TileLayer::new("layer", 4096).unwrap();
1388 layer.add_m_value("n", PropKind::I32).unwrap();
1389 assert_eq!(
1390 layer
1391 .add_property("n", PropKind::I32)
1392 .unwrap_err()
1393 .to_string(),
1394 "duplicate column name n: the property column repeats the m-value column"
1395 );
1396 }
1397
1398 #[cfg(feature = "unstable-v2")]
1399 #[test]
1400 fn add_property_rejects_a_name_a_nested_column_has() {
1401 let mut layer = TileLayer::new("layer", 4096).unwrap();
1402 layer.add_nested("n", list_kind()).unwrap();
1403 assert_eq!(
1404 layer
1405 .add_property("n", PropKind::I32)
1406 .unwrap_err()
1407 .to_string(),
1408 "duplicate column name n: the property column repeats the nested column"
1409 );
1410 }
1411
1412 #[cfg(feature = "unstable-v2")]
1413 #[test]
1414 fn add_nested_rejects_a_name_a_property_has() {
1415 let mut layer = TileLayer::new("layer", 4096).unwrap();
1416 layer.add_property("n", PropKind::I32).unwrap();
1417 assert_eq!(
1418 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1419 "duplicate column name n: the nested column repeats the property column"
1420 );
1421 }
1422
1423 #[cfg(feature = "unstable-v2")]
1424 #[test]
1425 fn add_nested_rejects_a_name_an_m_value_already_has() {
1426 let mut layer = TileLayer::new("layer", 4096).unwrap();
1427 layer.add_m_value("n", PropKind::I32).unwrap();
1428 assert_eq!(
1429 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1430 "duplicate column name n: the nested column repeats the m-value column"
1431 );
1432 }
1433
1434 #[cfg(feature = "unstable-v2")]
1435 #[test]
1436 fn add_nested_rejects_duplicate_names() {
1437 let mut layer = TileLayer::new("layer", 4096).unwrap();
1438 layer.add_nested("n", list_kind()).unwrap();
1439 assert_eq!(
1440 layer.add_nested("n", list_kind()).unwrap_err().to_string(),
1441 "duplicate column name n: the nested column repeats the nested column"
1442 );
1443 }
1444
1445 #[cfg(feature = "unstable-v2")]
1446 #[test]
1447 fn set_nested_rejects_a_value_of_another_shape() {
1448 let mut layer = TileLayer::new("layer", 4096).unwrap();
1449 let key = layer
1450 .add_nested("n", NestedKind::list(NestedKind::Leaf(PropKind::I32)))
1451 .unwrap();
1452 let mut feature = point_feature(vec![]);
1453 feature.nested = vec![NestedValue::List(None)];
1454 assert_eq!(
1455 feature
1456 .set_nested(key, NestedValue::Map(None))
1457 .unwrap_err()
1458 .to_string(),
1459 "nested column 0 was given a value of another shape"
1460 );
1461 }
1462
1463 #[test]
1464 fn builder_uses_declared_property_kind_for_defaults() {
1465 let mut builder = TileLayer::builder("layer", 4096).unwrap();
1466 let flag = builder.add_property("flag", PropKind::Bool).unwrap();
1467 let mut feature = builder.feature(Geometry::Point(Point::new(0, 0)));
1468 feature.property(flag, PropValue::Bool(Some(true))).unwrap();
1469 feature.finish().unwrap();
1470 let layer = builder.finish();
1471
1472 assert_eq!(
1473 layer.features()[0].properties()[0],
1474 PropValue::Bool(Some(true))
1475 );
1476 }
1477}