1use std::fmt;
2use std::num::NonZeroU32;
3
4use num_enum::TryFromPrimitive;
5
6use crate::decoder::{Geometry, Id, Property};
7use crate::{DecodeState, Lazy, MltError, MltResult, Parsed};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct Extent(NonZeroU32);
15
16impl Extent {
17 pub fn new(value: u32) -> MltResult<Self> {
18 NonZeroU32::new(value)
19 .map(Self)
20 .ok_or(MltError::InvalidExtent(value))
21 }
22
23 #[must_use]
24 pub fn get(self) -> u32 {
25 self.0.get()
26 }
27}
28
29impl From<Extent> for NonZeroU32 {
30 fn from(value: Extent) -> Self {
31 value.0
32 }
33}
34
35#[non_exhaustive]
41pub enum Layer<'a, S: DecodeState = Lazy> {
42 Tag01(Layer01<'a, S>),
44 Unknown(Unknown<'a>),
46}
47pub type ParsedLayer<'a> = Layer<'a, Parsed>;
48
49impl<'a, S: DecodeState> fmt::Debug for Layer<'a, S>
50where
51 Layer01<'a, S>: fmt::Debug,
52{
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::Tag01(l) => f.debug_tuple("Tag01").field(l).finish(),
56 Self::Unknown(u) => f.debug_tuple("Unknown").field(u).finish(),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Default, PartialEq)]
67pub struct Unknown<'a> {
68 pub(crate) tag: u8,
69 pub(crate) value: &'a [u8],
70}
71
72impl<'a> Unknown<'a> {
73 #[must_use]
75 pub fn tag(&self) -> u32 {
76 u32::from(self.tag)
77 }
78
79 #[must_use]
81 pub fn data(&self) -> &'a [u8] {
82 self.value
83 }
84}
85
86#[derive(Debug, PartialEq)]
88pub struct Column<'a> {
89 pub(crate) typ: ColumnType,
90 pub(crate) name: Option<&'a str>,
91 pub(crate) children: Vec<Self>,
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
96#[repr(u8)]
97pub enum ColumnType {
98 Id = 0,
99 OptId = 1,
100 LongId = 2,
101 OptLongId = 3,
102 Geometry = 4,
103 Bool = 10,
104 OptBool = 11,
105 I8 = 12,
106 OptI8 = 13,
107 U8 = 14,
108 OptU8 = 15,
109 I32 = 16,
110 OptI32 = 17,
111 U32 = 18,
112 OptU32 = 19,
113 I64 = 20,
114 OptI64 = 21,
115 U64 = 22,
116 OptU64 = 23,
117 F32 = 24,
118 OptF32 = 25,
119 F64 = 26,
120 OptF64 = 27,
121 Str = 28,
122 OptStr = 29,
123 SharedDict = 30,
124}
125
126pub struct Layer01<'a, S: DecodeState = Lazy> {
137 pub(crate) name: &'a str,
138 pub(crate) extent: Extent,
139 pub(crate) id: Option<Id<'a, S>>,
140 pub(crate) geometry: Geometry<'a, S>,
141 pub(crate) properties: Vec<Property<'a, S>>,
142 #[cfg(fuzzing)]
143 pub(crate) layer_order: Vec<crate::decoder::fuzzing::LayerOrdering>,
144}
145
146pub type ParsedLayer01<'a> = Layer01<'a, Parsed>;
147
148impl<'a, S: DecodeState> Layer01<'a, S> {
149 #[must_use]
150 pub fn name(&self) -> &'a str {
151 self.name
152 }
153
154 #[must_use]
155 pub fn extent(&self) -> Extent {
156 self.extent
157 }
158}
159
160impl<'a, S> fmt::Debug for Layer01<'a, S>
161where
162 S: DecodeState,
163 Option<Id<'a, S>>: fmt::Debug,
164 Geometry<'a, S>: fmt::Debug,
165 Vec<Property<'a, S>>: fmt::Debug,
166{
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 let mut s = f.debug_struct("Layer01");
169 s.field("name", &self.name)
170 .field("extent", &self.extent)
171 .field("id", &self.id)
172 .field("geometry", &self.geometry)
173 .field("properties", &self.properties);
174 #[cfg(fuzzing)]
175 s.field("layer_order", &self.layer_order);
176 s.finish()
177 }
178}
179
180impl<'a, S> Clone for Layer01<'a, S>
181where
182 S: DecodeState,
183 Option<Id<'a, S>>: Clone,
184 Geometry<'a, S>: Clone,
185 Vec<Property<'a, S>>: Clone,
186{
187 fn clone(&self) -> Self {
188 Self {
189 name: self.name,
190 extent: self.extent,
191 id: self.id.clone(),
192 geometry: self.geometry.clone(),
193 properties: self.properties.clone(),
194 #[cfg(fuzzing)]
195 layer_order: self.layer_order.clone(),
196 }
197 }
198}
199
200#[derive(Debug, Clone, PartialEq)]
206pub struct TileLayer {
207 pub(crate) name: String,
208 pub(crate) extent: Extent,
209 pub(crate) property_names: Vec<String>,
211 pub(crate) property_kinds: Vec<PropKind>,
213 pub(crate) features: Vec<TileFeature>,
214}
215
216#[derive(Debug, Clone, PartialEq)]
218pub struct TileFeature {
219 pub(crate) id: Option<u64>,
220 pub(crate) geometry: geo_types::Geometry<i32>,
222 pub(crate) properties: Vec<PropValue>,
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub struct PropertyKey(usize);
229
230impl PropertyKey {
231 #[must_use]
232 pub fn index(self) -> usize {
233 self.0
234 }
235}
236
237impl TileLayer {
238 pub fn new(name: impl Into<String>, extent: u32) -> MltResult<Self> {
239 Self::with_capacity(name, extent, 0)
240 }
241
242 pub fn with_capacity(name: impl Into<String>, extent: u32, features: usize) -> MltResult<Self> {
243 let name = name.into();
244 validate_layer_name(&name)?;
245 let extent = Extent::new(extent)?;
246 Ok(Self {
247 name,
248 extent,
249 property_names: Vec::new(),
250 property_kinds: Vec::new(),
251 features: Vec::with_capacity(features),
252 })
253 }
254
255 pub(crate) fn from_parts(
256 name: impl Into<String>,
257 extent: u32,
258 property_names: Vec<String>,
259 features: Vec<TileFeature>,
260 ) -> MltResult<Self> {
261 let name = name.into();
262 validate_layer_name(&name)?;
263 let extent = Extent::new(extent)?;
264 validate_property_names(&property_names)?;
265 let property_kinds = infer_property_kinds(&property_names, &features)?;
266 let layer = Self {
267 name,
268 extent,
269 property_names,
270 property_kinds,
271 features,
272 };
273 Ok(layer)
274 }
275
276 #[must_use]
277 pub fn name(&self) -> &str {
278 &self.name
279 }
280
281 #[must_use]
282 pub fn extent(&self) -> Extent {
283 self.extent
284 }
285
286 #[must_use]
287 pub fn property_names(&self) -> &[String] {
288 &self.property_names
289 }
290
291 #[must_use]
292 pub fn features(&self) -> &[TileFeature] {
293 &self.features
294 }
295
296 #[must_use]
297 pub(crate) fn features_mut(&mut self) -> &mut [TileFeature] {
298 &mut self.features
299 }
300
301 #[must_use]
302 pub fn feature_count(&self) -> usize {
303 self.features.len()
304 }
305
306 pub fn add_property(
307 &mut self,
308 name: impl Into<String>,
309 kind: PropKind,
310 ) -> MltResult<PropertyKey> {
311 let name = name.into();
312 if self.property_names.contains(&name) {
313 return Err(MltError::DuplicatePropertyName(name));
314 }
315 for feature in &mut self.features {
316 feature.properties.push(PropValue::null(kind));
317 }
318 self.property_names.push(name);
319 self.property_kinds.push(kind);
320 Ok(PropertyKey(self.property_names.len() - 1))
321 }
322
323 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
324 self.validate_feature(&feature)?;
325 self.features.push(feature);
326 Ok(())
327 }
328
329 pub fn builder(name: impl Into<String>, extent: u32) -> MltResult<TileLayerBuilder> {
330 Ok(TileLayerBuilder {
331 layer: Self::new(name, extent)?,
332 })
333 }
334
335 fn validate_feature(&self, feature: &TileFeature) -> MltResult<()> {
336 let expected = self.property_names.len();
337 let actual = feature.properties.len();
338 if actual != expected {
339 return Err(MltError::PropertyLengthMismatch { expected, actual });
340 }
341 for (idx, prop) in feature.properties.iter().enumerate() {
342 let expected = self.property_kinds[idx];
343 let actual = PropKind::from(prop);
344 if actual != expected {
345 return Err(MltError::PropertyKindMismatch {
346 index: idx,
347 expected,
348 actual,
349 });
350 }
351 }
352 Ok(())
353 }
354}
355
356impl TileFeature {
357 #[must_use]
358 pub fn new(geometry: geo_types::Geometry<i32>) -> Self {
359 Self {
360 id: None,
361 geometry,
362 properties: Vec::new(),
363 }
364 }
365
366 #[must_use]
367 pub fn with_id(geometry: geo_types::Geometry<i32>, id: u64) -> Self {
368 Self {
369 id: Some(id),
370 geometry,
371 properties: Vec::new(),
372 }
373 }
374
375 #[must_use]
376 pub fn id(&self) -> Option<u64> {
377 self.id
378 }
379
380 #[must_use]
381 pub fn geometry(&self) -> &geo_types::Geometry<i32> {
382 &self.geometry
383 }
384
385 #[must_use]
386 pub fn properties(&self) -> &[PropValue] {
387 &self.properties
388 }
389
390 #[must_use]
391 pub(crate) fn properties_mut(&mut self) -> &mut [PropValue] {
392 &mut self.properties
393 }
394
395 pub fn set_property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<()> {
396 let Some(prop) = self.properties.get_mut(key.index()) else {
397 return Err(MltError::PropertyLengthMismatch {
398 expected: key.index() + 1,
399 actual: self.properties.len(),
400 });
401 };
402 let expected = PropKind::from(&*prop);
403 let actual = PropKind::from(&value);
404 if actual != expected {
405 return Err(MltError::PropertyKindMismatch {
406 index: key.index(),
407 expected,
408 actual,
409 });
410 }
411 *prop = value;
412 Ok(())
413 }
414}
415
416pub struct TileLayerBuilder {
417 layer: TileLayer,
418}
419
420impl TileLayerBuilder {
421 pub fn add_property(
422 &mut self,
423 name: impl Into<String>,
424 kind: PropKind,
425 ) -> MltResult<PropertyKey> {
426 self.layer.add_property(name, kind)
427 }
428
429 pub fn feature(&mut self, geometry: geo_types::Geometry<i32>) -> TileFeatureBuilder<'_> {
430 let properties = self
431 .layer
432 .property_kinds
433 .iter()
434 .copied()
435 .map(PropValue::null)
436 .collect();
437 TileFeatureBuilder {
438 layer: self,
439 feature: TileFeature {
440 id: None,
441 geometry,
442 properties,
443 },
444 }
445 }
446
447 pub fn push_feature(&mut self, feature: TileFeature) -> MltResult<()> {
448 self.layer.push_feature(feature)
449 }
450
451 #[must_use]
452 pub fn finish(self) -> TileLayer {
453 self.layer
454 }
455}
456
457pub struct TileFeatureBuilder<'a> {
458 layer: &'a mut TileLayerBuilder,
459 feature: TileFeature,
460}
461
462impl TileFeatureBuilder<'_> {
463 pub fn id(&mut self, id: Option<u64>) -> &mut Self {
464 self.feature.id = id;
465 self
466 }
467
468 pub fn property(&mut self, key: PropertyKey, value: PropValue) -> MltResult<&mut Self> {
469 self.feature.set_property(key, value)?;
470 Ok(self)
471 }
472
473 pub fn finish(self) -> MltResult<()> {
474 self.layer.push_feature(self.feature)
475 }
476}
477
478#[derive(Debug, Clone, PartialEq)]
486pub enum PropValue {
487 Bool(Option<bool>),
488 I8(Option<i8>),
489 U8(Option<u8>),
490 I32(Option<i32>),
491 U32(Option<u32>),
492 I64(Option<i64>),
493 U64(Option<u64>),
494 F32(Option<f32>),
495 F64(Option<f64>),
496 Str(Option<String>),
497}
498
499impl PropValue {
500 #[must_use]
501 pub fn kind(&self) -> PropKind {
502 self.into()
503 }
504
505 #[must_use]
506 pub fn is_null(&self) -> bool {
507 match self {
508 Self::Bool(v) => v.is_none(),
509 Self::I8(v) => v.is_none(),
510 Self::U8(v) => v.is_none(),
511 Self::I32(v) => v.is_none(),
512 Self::U32(v) => v.is_none(),
513 Self::I64(v) => v.is_none(),
514 Self::U64(v) => v.is_none(),
515 Self::F32(v) => v.is_none(),
516 Self::F64(v) => v.is_none(),
517 Self::Str(v) => v.is_none(),
518 }
519 }
520
521 #[must_use]
522 pub fn null(kind: PropKind) -> Self {
523 match kind {
524 PropKind::Bool => Self::Bool(None),
525 PropKind::I8 => Self::I8(None),
526 PropKind::U8 => Self::U8(None),
527 PropKind::I32 => Self::I32(None),
528 PropKind::U32 => Self::U32(None),
529 PropKind::I64 => Self::I64(None),
530 PropKind::U64 => Self::U64(None),
531 PropKind::F32 => Self::F32(None),
532 PropKind::F64 => Self::F64(None),
533 PropKind::Str => Self::Str(None),
534 }
535 }
536}
537
538#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::IntoStaticStr)]
539#[strum(serialize_all = "lowercase")]
540pub enum PropKind {
541 Bool,
542 I8,
543 U8,
544 I32,
545 U32,
546 I64,
547 U64,
548 F32,
549 F64,
550 Str,
551}
552
553fn validate_layer_name(name: &str) -> MltResult<()> {
554 if name.is_empty() {
555 Err(MltError::MissingLayerName)
556 } else {
557 Ok(())
558 }
559}
560
561fn validate_property_names(names: &[String]) -> MltResult<()> {
562 for (i, name) in names.iter().enumerate() {
565 if names[..i].iter().any(|n| n == name) {
566 return Err(MltError::DuplicatePropertyName(name.clone()));
567 }
568 }
569 Ok(())
570}
571
572fn infer_property_kinds(names: &[String], features: &[TileFeature]) -> MltResult<Vec<PropKind>> {
573 let mut kinds = vec![None; names.len()];
574 for feature in features {
575 let expected = names.len();
576 let actual = feature.properties.len();
577 if actual != expected {
578 return Err(MltError::PropertyLengthMismatch { expected, actual });
579 }
580 for (idx, prop) in feature.properties.iter().enumerate() {
581 let actual = PropKind::from(prop);
582 match kinds[idx] {
583 Some(expected) if expected != actual => {
584 return Err(MltError::PropertyKindMismatch {
585 index: idx,
586 expected,
587 actual,
588 });
589 }
590 None => kinds[idx] = Some(actual),
591 _ => {}
592 }
593 }
594 }
595 Ok(kinds
596 .into_iter()
597 .map(|kind| kind.unwrap_or(PropKind::Str))
598 .collect())
599}
600impl From<&PropValue> for PropKind {
601 fn from(prop: &PropValue) -> Self {
602 match prop {
603 PropValue::Bool(_) => Self::Bool,
604 PropValue::I8(_) => Self::I8,
605 PropValue::U8(_) => Self::U8,
606 PropValue::I32(_) => Self::I32,
607 PropValue::U32(_) => Self::U32,
608 PropValue::I64(_) => Self::I64,
609 PropValue::U64(_) => Self::U64,
610 PropValue::F32(_) => Self::F32,
611 PropValue::F64(_) => Self::F64,
612 PropValue::Str(_) => Self::Str,
613 }
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use geo_types::{Geometry, Point};
620
621 use super::*;
622
623 fn point_feature(properties: Vec<PropValue>) -> TileFeature {
624 TileFeature {
625 id: None,
626 geometry: Geometry::Point(Point::new(0, 0)),
627 properties,
628 }
629 }
630
631 #[test]
632 fn tile_layer_constructor_rejects_empty_name() {
633 assert!(matches!(
634 TileLayer::new("", 4096),
635 Err(MltError::MissingLayerName)
636 ));
637 }
638
639 #[test]
640 fn tile_layer_constructor_rejects_zero_extent() {
641 assert!(matches!(
642 TileLayer::new("layer", 0),
643 Err(MltError::InvalidExtent(0))
644 ));
645 }
646
647 #[test]
648 fn add_property_rejects_duplicate_names() {
649 let mut layer = TileLayer::new("layer", 4096).unwrap();
650 layer.add_property("name", PropKind::Str).unwrap();
651 assert!(matches!(
652 layer.add_property("name", PropKind::Str),
653 Err(MltError::DuplicatePropertyName(name)) if name == "name"
654 ));
655 }
656
657 #[test]
658 fn from_parts_allows_empty_property_name() {
659 assert!(TileLayer::from_parts("layer", 4096, vec![String::new()], vec![]).is_ok());
661 }
662
663 #[test]
664 fn from_parts_rejects_duplicate_property_name() {
665 assert!(matches!(
666 TileLayer::from_parts("layer", 4096, vec!["dup".into(), "dup".into()], vec![]),
667 Err(MltError::DuplicatePropertyName(name)) if name == "dup"
668 ));
669 }
670
671 #[test]
672 fn push_feature_validates_property_count() {
673 let mut layer = TileLayer::new("layer", 4096).unwrap();
674 layer.add_property("name", PropKind::Str).unwrap();
675 assert!(matches!(
676 layer.push_feature(point_feature(vec![])),
677 Err(MltError::PropertyLengthMismatch {
678 expected: 1,
679 actual: 0
680 })
681 ));
682 }
683
684 #[test]
685 fn push_feature_validates_property_kind() {
686 let mut layer = TileLayer::new("layer", 4096).unwrap();
687 layer.add_property("flag", PropKind::Bool).unwrap();
688 layer
689 .push_feature(point_feature(vec![PropValue::Bool(Some(true))]))
690 .unwrap();
691 assert!(matches!(
692 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
693 Err(MltError::PropertyKindMismatch {
694 index: 0,
695 expected: PropKind::Bool,
696 actual: PropKind::I32,
697 })
698 ));
699 }
700
701 #[test]
702 fn declared_property_kind_is_enforced_for_first_feature() {
703 let mut layer = TileLayer::new("layer", 4096).unwrap();
704 layer.add_property("flag", PropKind::Bool).unwrap();
705 assert!(matches!(
706 layer.push_feature(point_feature(vec![PropValue::I32(Some(1))])),
707 Err(MltError::PropertyKindMismatch {
708 index: 0,
709 expected: PropKind::Bool,
710 actual: PropKind::I32,
711 })
712 ));
713 }
714
715 #[test]
716 fn builder_uses_declared_property_kind_for_defaults() {
717 let mut builder = TileLayer::builder("layer", 4096).unwrap();
718 let flag = builder.add_property("flag", PropKind::Bool).unwrap();
719 let mut feature = builder.feature(Geometry::Point(Point::new(0, 0)));
720 feature.property(flag, PropValue::Bool(Some(true))).unwrap();
721 feature.finish().unwrap();
722 let layer = builder.finish();
723
724 assert_eq!(
725 layer.features()[0].properties()[0],
726 PropValue::Bool(Some(true))
727 );
728 }
729}