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