1use std::collections::{BTreeMap, HashMap};
4
5use fast_mvt::{MvtLayer, MvtLayerRef, MvtReaderRef, MvtValue, MvtValueRef};
6use serde_json::Value;
7
8use crate::geojson::{Feature, FeatureCollection};
9use crate::tile::{PropValue, TileFeature, TileLayer};
10use crate::{MltError, MltResult};
11
12fn read_mvt_layers(data: &[u8]) -> MltResult<Vec<MvtLayer>> {
14 let layers = MvtReaderRef::new(data)?.to_tile()?.layers;
15 if layers.iter().any(|layer| layer.name.is_empty()) {
16 return Err(MltError::MissingLayerName);
17 }
18 Ok(layers)
19}
20
21pub fn mvt_to_feature_collection(data: impl AsRef<[u8]>) -> MltResult<FeatureCollection> {
23 let mut features = Vec::new();
24
25 for layer in read_mvt_layers(data.as_ref())? {
26 for feat in layer.features {
27 let mut properties = feat
28 .properties
29 .into_iter()
30 .map(|(k, v)| Ok((k, Value::try_from(v)?)))
31 .collect::<MltResult<BTreeMap<_, _>>>()?;
32 properties.insert("_layer".into(), Value::String(layer.name.clone()));
33 properties.insert("_extent".into(), Value::Number(layer.extent.get().into()));
34 features.push(Feature {
35 geometry: feat.geometry,
36 id: feat.id,
37 properties,
38 ty: "Feature".into(),
39 });
40 }
41 }
42
43 Ok(FeatureCollection {
44 features,
45 ty: "FeatureCollection".into(),
46 })
47}
48
49pub fn mvt_to_tile_layers(data: impl AsRef<[u8]>) -> MltResult<Vec<TileLayer>> {
56 MvtReaderRef::new(data.as_ref())?
57 .layers()
58 .map(tile_layer_from_ref)
59 .collect()
60}
61
62fn tile_layer_from_ref(layer: MvtLayerRef<'_>) -> MltResult<TileLayer> {
64 let name = layer.name();
65 if name.is_empty() {
66 return Err(MltError::MissingLayerName);
67 }
68
69 let mut col_names: Vec<String> = Vec::new();
71 let mut col_index: HashMap<&str, usize> = HashMap::new();
72 let mut col_types: Vec<InferredType> = Vec::new();
73 let mut values: Vec<(usize, MvtValueRef<'_>)> = Vec::new();
75 let mut feature_ends: Vec<usize> = Vec::with_capacity(layer.feature_count());
76
77 for feat in layer.features() {
78 for prop in feat.properties() {
79 let (key, value) = prop?;
80 let idx = if let Some(&idx) = col_index.get(key) {
81 idx
82 } else {
83 let idx = col_names.len();
84 col_names.push(key.to_string());
85 col_index.insert(key, idx);
86 col_types.push(InferredType::Unknown);
87 idx
88 };
89 let slot = &mut col_types[idx];
91 *slot = slot.merge(InferredType::from_mvt(value));
92 values.push((idx, value));
93 }
94 feature_ends.push(values.len());
95 }
96
97 for t in &mut col_types {
99 if *t == InferredType::Unknown {
100 *t = InferredType::Str;
101 }
102 }
103
104 let mut tile_features = Vec::with_capacity(layer.feature_count());
106 let mut start = 0;
107 for (feat, &end) in layer.features().zip(&feature_ends) {
108 let mut properties: Vec<PropValue> = col_types.iter().map(|t| t.typed_null()).collect();
110 for &(idx, value) in &values[start..end] {
111 if !matches!(value, MvtValueRef::Null) {
112 properties[idx] = col_types[idx].convert(value.into_owned());
113 }
114 }
115 start = end;
116 tile_features.push(TileFeature {
117 id: feat.id(),
118 geometry: feat.geometry()?,
119 properties,
120 #[cfg(feature = "unstable-v2")]
121 m_values: Vec::new(),
122 #[cfg(feature = "unstable-v2")]
123 nested: Vec::new(),
124 });
125 }
126
127 TileLayer::from_parts(name, layer.extent(), col_names, tile_features)
128}
129
130impl TryFrom<MvtLayer> for TileLayer {
131 type Error = MltError;
132
133 fn try_from(layer: MvtLayer) -> Result<Self, Self::Error> {
134 if layer.name.is_empty() {
135 return Err(MltError::MissingLayerName);
136 }
137
138 let mut col_names: Vec<String> = Vec::new();
140 let mut col_index: HashMap<String, usize> = HashMap::new();
141 let mut col_types: Vec<InferredType> = Vec::new();
142
143 for feat in &layer.features {
144 for (key, val) in &feat.properties {
145 let idx = *col_index.entry(key.clone()).or_insert_with(|| {
146 let i = col_names.len();
147 col_names.push(key.clone());
148 col_types.push(InferredType::Unknown);
149 i
150 });
151 let slot = &mut col_types[idx];
152 *slot = slot.merge(InferredType::from_mvt(as_value_ref(val)));
153 }
154 }
155
156 for t in &mut col_types {
158 if *t == InferredType::Unknown {
159 *t = InferredType::Str;
160 }
161 }
162
163 let mut tile_features = Vec::with_capacity(layer.features.len());
165 for feat in layer.features {
166 let mut properties: Vec<PropValue> = col_types.iter().map(|t| t.typed_null()).collect();
168 for (key, val) in feat.properties {
169 if let Some(&idx) = col_index.get(&key)
170 && !matches!(val, MvtValue::Null)
171 {
172 properties[idx] = col_types[idx].convert(val);
173 }
174 }
175 tile_features.push(TileFeature {
176 id: feat.id,
177 geometry: feat.geometry,
178 properties,
179 #[cfg(feature = "unstable-v2")]
180 m_values: Vec::new(),
181 #[cfg(feature = "unstable-v2")]
182 nested: Vec::new(),
183 });
184 }
185
186 Self::from_parts(layer.name, layer.extent.get(), col_names, tile_features)
187 }
188}
189
190fn as_value_ref(value: &MvtValue) -> MvtValueRef<'_> {
192 match value {
193 MvtValue::String(s) => MvtValueRef::String(s),
194 MvtValue::Float(f) => MvtValueRef::Float(*f),
195 MvtValue::Double(f) => MvtValueRef::Double(*f),
196 MvtValue::Int(i) => MvtValueRef::Int(*i),
197 MvtValue::UInt(u) => MvtValueRef::UInt(*u),
198 MvtValue::SInt(i) => MvtValueRef::SInt(*i),
199 MvtValue::Bool(b) => MvtValueRef::Bool(*b),
200 MvtValue::Null => MvtValueRef::Null,
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
206enum InferredType {
207 Unknown,
208 Bool,
209 I64,
210 U64,
211 F32,
212 F64,
213 Str,
214}
215
216impl InferredType {
217 fn from_mvt(val: MvtValueRef<'_>) -> Self {
218 match val {
219 MvtValueRef::Bool(_) => Self::Bool,
220 MvtValueRef::Int(_) | MvtValueRef::SInt(_) => Self::I64,
221 MvtValueRef::UInt(_) => Self::U64,
222 MvtValueRef::Float(_) => Self::F32,
223 MvtValueRef::Double(_) => Self::F64,
224 MvtValueRef::String(_) => Self::Str,
225 MvtValueRef::Null => Self::Unknown,
226 }
227 }
228
229 fn merge(self, other: Self) -> Self {
231 if self == Self::Unknown {
232 return other;
233 }
234 if other == Self::Unknown || self == other {
235 return self;
236 }
237 if matches!(
238 (self, other),
239 (Self::I64, Self::U64) | (Self::U64, Self::I64)
240 ) {
241 return Self::I64;
242 }
243 if matches!(
244 (self, other),
245 (Self::F32, Self::F64) | (Self::F64, Self::F32)
246 ) {
247 return Self::F64;
248 }
249 Self::Str
250 }
251
252 fn typed_null(self) -> PropValue {
253 match self {
254 Self::Unknown | Self::Str => PropValue::Str(None),
255 Self::Bool => PropValue::Bool(None),
256 Self::I64 => PropValue::I64(None),
257 Self::U64 => PropValue::U64(None),
258 Self::F32 => PropValue::F32(None),
259 Self::F64 => PropValue::F64(None),
260 }
261 }
262
263 fn convert(self, val: MvtValue) -> PropValue {
265 match (self, val) {
266 (_, MvtValue::Null) => self.typed_null(),
267 (Self::Bool, MvtValue::Bool(b)) => PropValue::Bool(Some(b)),
268 (Self::I64, MvtValue::Int(i) | MvtValue::SInt(i)) => PropValue::I64(Some(i)),
269 (Self::I64, MvtValue::UInt(u)) if i64::try_from(u).is_ok() => {
270 #[expect(clippy::cast_possible_wrap, reason = "checked above")]
272 PropValue::I64(Some(u as i64))
273 }
274 (Self::U64, MvtValue::UInt(u)) => PropValue::U64(Some(u)),
275 (Self::F32, MvtValue::Float(f)) => PropValue::F32(Some(f)),
276 (Self::F64, MvtValue::Double(f)) => PropValue::F64(Some(f)),
277 (Self::F64, MvtValue::Float(f)) => PropValue::F64(Some(f64::from(f))),
278 (_, MvtValue::String(s)) => PropValue::Str(Some(s)),
279 (_, MvtValue::Bool(b)) => PropValue::Str(Some(b.to_string())),
281 (_, MvtValue::Int(i) | MvtValue::SInt(i)) => PropValue::Str(Some(i.to_string())),
282 (_, MvtValue::UInt(u)) => PropValue::Str(Some(u.to_string())),
283 (_, MvtValue::Float(f)) => PropValue::Str(Some(f.to_string())),
284 (_, MvtValue::Double(f)) => PropValue::Str(Some(f.to_string())),
285 }
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use std::num::NonZeroU32;
292
293 use rstest::rstest;
294
295 use super::*;
296
297 const POINT_AT_1_1: &[u64] = &[9, 2, 2];
298
299 #[rstest]
300 #[case::key_index_past_the_key_list(vec![5, 0], "MVT error: invalid key index 5")]
301 #[case::value_index_past_the_value_list(vec![0, 9], "MVT error: invalid value index 9")]
302 #[case::odd_tag_count(vec![0], "MVT error: invalid feature tags length: 1")]
303 fn malformed_tags_are_reported(#[case] tags: Vec<u32>, #[case] expected: &str) {
304 assert_eq!(
305 mvt_to_tile_layers(mvt_with_tags(&tags))
306 .expect_err("malformed tags must error")
307 .to_string(),
308 expected
309 );
310 }
311
312 #[rstest]
313 #[case::signed_then_unsigned(
314 vec![MvtValue::SInt(-1), MvtValue::UInt(7)],
315 vec![PropValue::I64(Some(-1)), PropValue::I64(Some(7))],
316 )]
317 #[case::unsigned_then_signed(
318 vec![MvtValue::UInt(7), MvtValue::SInt(-1)],
319 vec![PropValue::I64(Some(7)), PropValue::I64(Some(-1))],
320 )]
321 #[case::int_then_sint(
322 vec![MvtValue::Int(i64::MIN), MvtValue::SInt(3)],
323 vec![PropValue::I64(Some(i64::MIN)), PropValue::I64(Some(3))],
324 )]
325 #[case::unsigned_only(
326 vec![MvtValue::UInt(7), MvtValue::UInt(u64::MAX)],
327 vec![PropValue::U64(Some(7)), PropValue::U64(Some(u64::MAX))],
328 )]
329 #[case::float_only(
330 vec![MvtValue::Float(1.5)],
331 vec![PropValue::F32(Some(1.5))],
332 )]
333 #[case::float_then_double(
334 vec![MvtValue::Float(1.5), MvtValue::Double(2.5)],
335 vec![PropValue::F64(Some(1.5)), PropValue::F64(Some(2.5))],
336 )]
337 #[case::double_then_float(
338 vec![MvtValue::Double(2.5), MvtValue::Float(1.5)],
339 vec![PropValue::F64(Some(2.5)), PropValue::F64(Some(1.5))],
340 )]
341 #[case::bool_only(
342 vec![MvtValue::Bool(true), MvtValue::Bool(false)],
343 vec![PropValue::Bool(Some(true)), PropValue::Bool(Some(false))],
344 )]
345 #[case::string_only(
346 vec![MvtValue::String("x".into())],
347 vec![PropValue::Str(Some("x".into()))],
348 )]
349 #[case::bool_then_int(
350 vec![MvtValue::Bool(true), MvtValue::Int(5)],
351 vec![PropValue::Str(Some("true".into())), PropValue::Str(Some("5".into()))],
352 )]
353 #[case::double_then_string(
354 vec![MvtValue::Double(1.5), MvtValue::String("x".into())],
355 vec![PropValue::Str(Some("1.5".into())), PropValue::Str(Some("x".into()))],
356 )]
357 #[case::null_between_bools(
358 vec![MvtValue::Bool(true), MvtValue::Null, MvtValue::Bool(false)],
359 vec![
360 PropValue::Bool(Some(true)),
361 PropValue::Bool(None),
362 PropValue::Bool(Some(false)),
363 ],
364 )]
365 #[case::null_only(
366 vec![MvtValue::Null],
367 vec![PropValue::Str(None)],
368 )]
369 fn a_column_takes_the_type_that_holds_every_value(
370 #[case] values: Vec<MvtValue>,
371 #[case] expected: Vec<PropValue>,
372 ) {
373 assert_eq!(single_column(&values), expected);
374 }
375
376 #[test]
377 fn an_unsigned_value_past_i64_max_clashes_with_its_signed_column() {
378 let data = mvt_with_values(&[MvtValue::SInt(-1), MvtValue::UInt(u64::MAX)]);
379 assert_eq!(
380 mvt_to_tile_layers(&data)
381 .expect_err("the string fallback leaves the column mixed")
382 .to_string(),
383 "property 0 kind mismatch: expected I64, got Str"
384 );
385 }
386
387 #[test]
388 fn missing_properties_become_typed_nulls() {
389 let messages: Vec<Vec<u8>> = [
390 MvtValue::Int(1),
391 MvtValue::UInt(2),
392 MvtValue::Float(1.5),
393 MvtValue::Double(2.5),
394 MvtValue::Bool(true),
395 MvtValue::String("x".into()),
396 ]
397 .iter()
398 .map(value_message)
399 .collect();
400 let every_key: Vec<u32> = (0..6).flat_map(|i| [i, i]).collect();
401 let data = mvt_tile(&[layer_body(
402 b"l",
403 4096,
404 &[
405 b"i".as_slice(),
406 b"u".as_slice(),
407 b"f".as_slice(),
408 b"d".as_slice(),
409 b"b".as_slice(),
410 b"s".as_slice(),
411 ],
412 &messages,
413 &[(None, &every_key, POINT_AT_1_1), (None, &[], POINT_AT_1_1)],
414 )]);
415
416 let layers = both_paths(&data);
417 let [layer] = &layers[..] else {
418 panic!("expected one layer, got {}", layers.len())
419 };
420 assert_eq!(layer.property_names(), ["i", "u", "f", "d", "b", "s"]);
421 assert_eq!(
422 layer.features()[0].properties(),
423 [
424 PropValue::I64(Some(1)),
425 PropValue::U64(Some(2)),
426 PropValue::F32(Some(1.5)),
427 PropValue::F64(Some(2.5)),
428 PropValue::Bool(Some(true)),
429 PropValue::Str(Some("x".into())),
430 ]
431 );
432 assert_eq!(
433 layer.features()[1].properties(),
434 [
435 PropValue::I64(None),
436 PropValue::U64(None),
437 PropValue::F32(None),
438 PropValue::F64(None),
439 PropValue::Bool(None),
440 PropValue::Str(None),
441 ]
442 );
443 }
444
445 #[test]
446 fn column_order_follows_first_use_not_the_key_list() {
447 let messages: Vec<Vec<u8>> = [
448 MvtValue::String("1".into()),
449 MvtValue::String("2".into()),
450 MvtValue::String("3".into()),
451 ]
452 .iter()
453 .map(value_message)
454 .collect();
455 let data = mvt_tile(&[layer_body(
456 b"l",
457 4096,
458 &[b"b".as_slice(), b"a".as_slice(), b"c".as_slice()],
459 &messages,
460 &[
461 (None, &[2, 2, 0, 0], POINT_AT_1_1),
462 (None, &[1, 1], POINT_AT_1_1),
463 ],
464 )]);
465
466 let layers = both_paths(&data);
467 let [layer] = &layers[..] else {
468 panic!("expected one layer, got {}", layers.len())
469 };
470 assert_eq!(layer.property_names(), ["c", "b", "a"]);
471 assert_eq!(
472 layer.features()[0].properties(),
473 [
474 PropValue::Str(Some("3".into())),
475 PropValue::Str(Some("1".into())),
476 PropValue::Str(None),
477 ]
478 );
479 assert_eq!(
480 layer.features()[1].properties(),
481 [
482 PropValue::Str(None),
483 PropValue::Str(None),
484 PropValue::Str(Some("2".into())),
485 ]
486 );
487 }
488
489 #[test]
490 fn each_layer_keeps_its_own_name_extent_and_columns() {
491 let layers = both_paths(&two_layer_tile());
492 assert_eq!(
493 layers
494 .iter()
495 .map(|layer| (
496 layer.name(),
497 layer.extent().get(),
498 layer.property_names().to_vec()
499 ))
500 .collect::<Vec<_>>(),
501 [
502 ("roads", 4096, vec!["n".to_string()]),
503 ("water", 512, vec!["z".to_string()]),
504 ]
505 );
506 assert_eq!(
507 layers[0].features()[0].properties(),
508 [PropValue::Str(Some("a".into()))]
509 );
510 assert_eq!(
511 layers[1].features()[0].properties(),
512 [PropValue::I64(Some(3))]
513 );
514 }
515
516 #[test]
517 fn a_layer_without_features_has_no_columns() {
518 let data = mvt_tile(&[layer_body(b"l", 4096, &[], &[], &[])]);
519 let layers = both_paths(&data);
520 let [layer] = &layers[..] else {
521 panic!("expected one layer, got {}", layers.len())
522 };
523 let no_names: [&str; 0] = [];
524 assert_eq!(layer.property_names(), no_names);
525 assert_eq!(layer.feature_count(), 0);
526 }
527
528 #[test]
529 fn feature_ids_survive_both_conversions() {
530 let data = mvt_tile(&[layer_body(
531 b"l",
532 4096,
533 &[],
534 &[],
535 &[(Some(7), &[], POINT_AT_1_1), (None, &[], POINT_AT_1_1)],
536 )]);
537 let layers = both_paths(&data);
538 assert_eq!(
539 layers[0]
540 .features()
541 .iter()
542 .map(TileFeature::id)
543 .collect::<Vec<_>>(),
544 [Some(7), None]
545 );
546 }
547
548 #[test]
549 fn a_zero_extent_is_rejected() {
550 let data = mvt_tile(&[layer_body(b"l", 0, &[], &[], &[])]);
551 assert_eq!(
552 mvt_to_tile_layers(&data)
553 .expect_err("zero extent must error")
554 .to_string(),
555 "invalid extent: 0"
556 );
557 }
558
559 #[test]
560 fn a_truncated_geometry_is_reported() {
561 let data = mvt_tile(&[layer_body(b"l", 4096, &[], &[], &[(None, &[], &[9])])]);
562 assert_eq!(
563 mvt_to_tile_layers(&data)
564 .expect_err("truncated geometry must error")
565 .to_string(),
566 "MVT error: invalid geometry command stream"
567 );
568 }
569
570 #[test]
571 fn a_layer_without_a_name_is_rejected() {
572 let unnamed = mvt_layer(b"", &[vec![]], b"k", &[]);
573 assert_eq!(
574 mvt_to_tile_layers(&unnamed)
575 .expect_err("borrowed conversion must error")
576 .to_string(),
577 "MVT error: missing required layer name"
578 );
579 assert_eq!(
580 mvt_to_feature_collection(&unnamed)
581 .expect_err("feature collection must error")
582 .to_string(),
583 "MVT error: missing required layer name"
584 );
585
586 let hand_built = MvtLayer {
587 name: String::new(),
588 extent: NonZeroU32::new(4096).expect("non-zero"),
589 features: Vec::new(),
590 };
591 assert_eq!(
592 TileLayer::try_from(hand_built)
593 .expect_err("owned conversion must error")
594 .to_string(),
595 "missing layer name"
596 );
597 }
598
599 #[test]
600 fn unreadable_tile_bytes_are_reported() {
601 assert!(matches!(
602 mvt_to_tile_layers([0xff_u8]),
603 Err(MltError::Mvt(_))
604 ));
605 assert!(matches!(
606 mvt_to_feature_collection([0xff_u8]),
607 Err(MltError::Mvt(_))
608 ));
609 }
610
611 #[test]
612 fn an_empty_tile_holds_no_layers_and_no_features() {
613 assert_eq!(
614 mvt_to_tile_layers([0_u8; 0]).expect("convert"),
615 Vec::<TileLayer>::new()
616 );
617 insta::assert_snapshot!(
618 serde_json::to_string(&mvt_to_feature_collection([0_u8; 0]).expect("convert"))
619 .expect("serialize"),
620 @r#"{"type":"FeatureCollection","features":[]}"#
621 );
622 }
623
624 #[test]
625 fn every_feature_carries_its_own_layer_name_and_extent() {
626 insta::assert_snapshot!(
627 serde_json::to_string(&mvt_to_feature_collection(two_layer_tile()).expect("convert"))
628 .expect("serialize"),
629 @r#"{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"_extent":4096,"_layer":"roads","n":"a"},"geometry":{"type":"Point","coordinates":[1,1]}},{"type":"Feature","properties":{"_extent":512,"_layer":"water","z":3},"geometry":{"type":"Point","coordinates":[1,1]}}]}"#
630 );
631 }
632
633 #[test]
634 fn a_non_finite_double_cannot_become_geojson() {
635 assert_eq!(
636 mvt_to_feature_collection(mvt_with_values(&[MvtValue::Double(f64::NAN)]))
637 .expect_err("NaN must error")
638 .to_string(),
639 "MVT JSON value error: non-finite float cannot be represented as JSON"
640 );
641 }
642
643 fn single_column(values: &[MvtValue]) -> Vec<PropValue> {
645 let data = mvt_with_values(values);
646 let layers = both_paths(&data);
647 let [layer] = &layers[..] else {
648 panic!("expected one layer, got {}", layers.len())
649 };
650 assert_eq!(layer.property_names(), ["k"]);
651 layer
652 .features()
653 .iter()
654 .map(|feat| feat.properties()[0].clone())
655 .collect()
656 }
657
658 fn both_paths(data: &[u8]) -> Vec<TileLayer> {
660 let from_ref = mvt_to_tile_layers(data).expect("borrowed conversion");
661 let owned: Vec<TileLayer> = MvtReaderRef::new(data)
662 .expect("read")
663 .to_tile()
664 .expect("to_tile")
665 .layers
666 .into_iter()
667 .map(TileLayer::try_from)
668 .collect::<MltResult<_>>()
669 .expect("owned conversion");
670 assert_eq!(from_ref, owned);
671 from_ref
672 }
673
674 fn two_layer_tile() -> Vec<u8> {
676 mvt_tile(&[
677 layer_body(
678 b"roads",
679 4096,
680 &[b"n".as_slice()],
681 &[value_message(&MvtValue::String("a".into()))],
682 &[(None, &[0, 0], POINT_AT_1_1)],
683 ),
684 layer_body(
685 b"water",
686 512,
687 &[b"z".as_slice()],
688 &[value_message(&MvtValue::Int(3))],
689 &[(None, &[0, 0], POINT_AT_1_1)],
690 ),
691 ])
692 }
693
694 fn field(number: u32, wire: u32) -> u8 {
695 u8::try_from((number << 3) | wire).expect("small field number")
696 }
697
698 fn varint(mut value: u64, out: &mut Vec<u8>) {
699 loop {
700 let byte = u8::try_from(value & 0x7f).expect("masked");
701 value >>= 7;
702 if value == 0 {
703 out.push(byte);
704 return;
705 }
706 out.push(byte | 0x80);
707 }
708 }
709
710 fn packed(number: u32, values: &[u64], out: &mut Vec<u8>) {
711 let mut body = Vec::new();
712 for value in values {
713 varint(*value, &mut body);
714 }
715 out.push(field(number, 2));
716 varint(u64::try_from(body.len()).expect("small"), out);
717 out.extend(&body);
718 }
719
720 fn bytes(number: u32, body: &[u8], out: &mut Vec<u8>) {
721 out.push(field(number, 2));
722 varint(u64::try_from(body.len()).expect("small"), out);
723 out.extend(body);
724 }
725
726 fn value_message(value: &MvtValue) -> Vec<u8> {
728 let mut out = Vec::new();
729 match value {
730 MvtValue::String(s) => bytes(1, s.as_bytes(), &mut out),
731 MvtValue::Float(f) => {
732 out.push(field(2, 5));
733 out.extend(f.to_le_bytes());
734 }
735 MvtValue::Double(f) => {
736 out.push(field(3, 1));
737 out.extend(f.to_le_bytes());
738 }
739 MvtValue::Int(i) => {
740 out.push(field(4, 0));
741 varint(i.cast_unsigned(), &mut out);
742 }
743 MvtValue::UInt(u) => {
744 out.push(field(5, 0));
745 varint(*u, &mut out);
746 }
747 MvtValue::SInt(i) => {
748 out.push(field(6, 0));
749 varint(zigzag::ZigZag::encode(*i), &mut out);
750 }
751 MvtValue::Bool(b) => {
752 out.push(field(7, 0));
753 varint(u64::from(*b), &mut out);
754 }
755 MvtValue::Null => {}
757 }
758 out
759 }
760
761 fn mvt_with_values(values: &[MvtValue]) -> Vec<u8> {
763 let tags: Vec<Vec<u32>> = (0..values.len())
764 .map(|i| vec![0, u32::try_from(i).expect("small")])
765 .collect();
766 let messages: Vec<Vec<u8>> = values.iter().map(value_message).collect();
767 mvt_layer(b"l", &tags, b"k", &messages)
768 }
769
770 fn mvt_with_tags(tags: &[u32]) -> Vec<u8> {
772 mvt_layer(b"l", &[tags.to_vec()], b"k", &[])
773 }
774
775 fn mvt_layer(
777 name: &[u8],
778 feature_tags: &[Vec<u32>],
779 key: &[u8],
780 values: &[Vec<u8>],
781 ) -> Vec<u8> {
782 let features: Vec<(Option<u64>, &[u32], &[u64])> = feature_tags
783 .iter()
784 .map(|tags| (None, tags.as_slice(), POINT_AT_1_1))
785 .collect();
786 mvt_tile(&[layer_body(name, 4096, &[key], values, &features)])
787 }
788
789 fn mvt_tile(layers: &[Vec<u8>]) -> Vec<u8> {
790 let mut tile = Vec::new();
791 for layer in layers {
792 bytes(3, layer, &mut tile);
793 }
794 tile
795 }
796
797 fn layer_body(
799 name: &[u8],
800 extent: u32,
801 keys: &[&[u8]],
802 values: &[Vec<u8>],
803 features: &[(Option<u64>, &[u32], &[u64])],
804 ) -> Vec<u8> {
805 let mut layer = Vec::new();
806 layer.push(field(15, 0));
807 varint(2, &mut layer); bytes(1, name, &mut layer);
809 for (id, tags, geometry) in features {
810 let mut feat = Vec::new();
811 if let Some(id) = id {
812 feat.push(field(1, 0));
813 varint(*id, &mut feat);
814 }
815 packed(
816 2,
817 &tags.iter().copied().map(u64::from).collect::<Vec<_>>(),
818 &mut feat,
819 );
820 feat.push(field(3, 0));
821 varint(1, &mut feat); packed(4, geometry, &mut feat);
823 bytes(2, &feat, &mut layer);
824 }
825 for key in keys {
826 bytes(3, key, &mut layer);
827 }
828 for value in values {
829 bytes(4, value, &mut layer);
830 }
831 layer.push(field(5, 0));
832 varint(u64::from(extent), &mut layer);
833 layer
834 }
835}