1use buffa::Message as _;
2use dup_indexer::{DupIndexer, DupIndexerRefs, PtrRead};
3use usize_cast::IntoUsize;
4
5use crate::generated::vector_tile::Tile;
6use crate::generated::vector_tile::tile::{Feature, Layer, Value};
7use crate::geom_writer::encode_geometry;
8use crate::{DEFAULT_EXTENT, MvtError, MvtExtent, MvtGeometry, MvtResult, MvtTile, MvtValue};
9
10#[derive(Debug, Default)]
11pub struct MvtTileBuilder(Tile);
12
13impl MvtTileBuilder {
14 #[must_use]
15 pub fn new() -> Self {
16 Self::default()
17 }
18
19 #[must_use]
20 pub fn with_capacity(layers: usize) -> Self {
21 Self(Tile {
22 layers: Vec::with_capacity(layers),
23 })
24 }
25
26 pub fn layer(self, name: impl Into<String>) -> MvtResult<MvtLayerBuilder> {
27 self.layer_with_capacity(name, 0)
28 }
29
30 pub fn layer_with_capacity(
31 self,
32 name: impl Into<String>,
33 features: usize,
34 ) -> MvtResult<MvtLayerBuilder> {
35 let name = name.into();
36 if name.is_empty() {
37 return Err(MvtError::MissingLayerName);
38 }
39 Ok(MvtLayerBuilder::with_tile(self, name, features))
40 }
41
42 #[must_use]
43 pub fn encode(self) -> Vec<u8> {
44 self.0.encode_to_vec()
45 }
46
47 #[must_use]
48 pub fn encoded_len(&self) -> usize {
49 self.0.encoded_len().into_usize()
50 }
51
52 fn push_layer(mut self, layer: Layer) -> Self {
53 self.0.layers.push(layer);
54 self
55 }
56}
57
58pub(crate) fn encode_tile(tile: MvtTile) -> MvtResult<Vec<u8>> {
59 let mut tile_bld = MvtTileBuilder::with_capacity(tile.layers.len());
60 for layer in tile.layers {
61 let mut layer_bld = tile_bld.layer_with_capacity(layer.name, layer.features.len())?;
62 layer_bld.extent(layer.extent);
63 for feature in layer.features {
64 let mut feature_bld = layer_bld.feature(&feature.geometry)?;
65 feature_bld.id(feature.id);
66 for (key, value) in feature.properties {
67 feature_bld.tag(key, value)?;
68 }
69 layer_bld = feature_bld.end();
70 }
71 tile_bld = layer_bld.end();
72 }
73 Ok(tile_bld.encode())
74}
75
76pub(crate) fn encode_tile_ref(tile: &MvtTile) -> MvtResult<Vec<u8>> {
77 let mut tile_bld = MvtTileBuilder::with_capacity(tile.layers.len());
78 for layer in &tile.layers {
79 let mut layer_bld =
80 tile_bld.layer_with_capacity(layer.name.clone(), layer.features.len())?;
81 layer_bld.extent(layer.extent);
82 for feature in &layer.features {
83 let mut feature_bld = layer_bld.feature(&feature.geometry)?;
84 feature_bld.id(feature.id);
85 for (key, value) in &feature.properties {
86 feature_bld.tag(key, value.clone())?;
87 }
88 layer_bld = feature_bld.end();
89 }
90 tile_bld = layer_bld.end();
91 }
92 Ok(tile_bld.encode())
93}
94
95#[derive(Debug)]
96pub struct MvtLayerBuilder {
97 tile: MvtTileBuilder,
98 layer: Layer,
99 keys: DupIndexerRefs<String>,
100 values: DupIndexer<MvtValue>,
101}
102
103impl MvtLayerBuilder {
104 pub fn new(name: impl Into<String>) -> MvtResult<Self> {
115 MvtTileBuilder::new().layer(name)
116 }
117
118 pub fn with_capacity(name: impl Into<String>, features: usize) -> MvtResult<Self> {
120 MvtTileBuilder::new().layer_with_capacity(name, features)
121 }
122
123 fn with_tile(tile: MvtTileBuilder, name: String, features: usize) -> Self {
124 Self {
125 tile,
126 layer: Layer {
127 version: 2,
128 name,
129 features: Vec::with_capacity(features),
130 keys: Vec::new(),
131 values: Vec::new(),
132 extent: Some(DEFAULT_EXTENT.get()),
133 },
134 keys: DupIndexerRefs::new(),
135 values: DupIndexer::new(),
136 }
137 }
138
139 pub fn extent(&mut self, extent: MvtExtent) -> &mut Self {
140 self.layer.extent = Some(extent.get());
141 self
142 }
143
144 #[must_use]
145 pub fn name(&self) -> &str {
146 &self.layer.name
147 }
148
149 #[must_use]
150 pub fn num_features(&self) -> usize {
151 self.layer.features.len()
152 }
153
154 pub fn feature(self, geometry: &MvtGeometry) -> MvtResult<MvtFeatureBuilder> {
155 let (geom_type, geometry) = encode_geometry(geometry)?;
156 Ok(MvtFeatureBuilder {
157 layer: self,
158 feature: Feature {
159 id: None,
160 tags: Vec::new(),
161 r#type: Some(geom_type),
162 geometry,
163 },
164 })
165 }
166
167 #[must_use]
168 pub fn end(self) -> MvtTileBuilder {
169 let Self {
170 tile,
171 mut layer,
172 keys,
173 values,
174 } = self;
175 layer.keys = keys.into_vec();
176 layer.values = values.into_iter().map(value_to_proto).collect();
177 tile.push_layer(layer)
178 }
179
180 pub fn layer(self, name: impl Into<String>) -> MvtResult<Self> {
186 self.end().layer(name)
187 }
188
189 #[must_use]
198 pub fn encode(self) -> Vec<u8> {
199 self.end().encode()
200 }
201}
202
203#[derive(Debug)]
204#[must_use = "call .end() to commit the feature to the layer"]
205pub struct MvtFeatureBuilder {
206 layer: MvtLayerBuilder,
207 feature: Feature,
208}
209
210impl MvtFeatureBuilder {
211 pub fn id(&mut self, id: Option<u64>) -> &mut Self {
212 self.feature.id = id;
213 self
214 }
215
216 pub fn tag(
217 &mut self,
218 key: impl AsRef<str>,
219 value: impl Into<MvtValue>,
220 ) -> MvtResult<&mut Self> {
221 let value = value.into();
222 if value != MvtValue::Null {
223 let key_idx = u32_index(self.layer.keys.insert_ref(key.as_ref()))?;
224 let value_idx = u32_index(self.layer.values.insert(value))?;
225 self.feature.tags.push(key_idx);
226 self.feature.tags.push(value_idx);
227 }
228 Ok(self)
229 }
230
231 pub fn tag_string(
232 &mut self,
233 key: impl AsRef<str>,
234 value: impl Into<String>,
235 ) -> MvtResult<&mut Self> {
236 self.tag(key, MvtValue::String(value.into()))
237 }
238
239 pub fn tag_float(&mut self, key: impl AsRef<str>, value: f32) -> MvtResult<&mut Self> {
240 self.tag(key, MvtValue::Float(value))
241 }
242
243 pub fn tag_double(&mut self, key: impl AsRef<str>, value: f64) -> MvtResult<&mut Self> {
244 self.tag(key, MvtValue::Double(value))
245 }
246
247 pub fn tag_int(&mut self, key: impl AsRef<str>, value: i64) -> MvtResult<&mut Self> {
248 self.tag(key, MvtValue::Int(value))
249 }
250
251 pub fn tag_uint(&mut self, key: impl AsRef<str>, value: u64) -> MvtResult<&mut Self> {
252 self.tag(key, MvtValue::UInt(value))
253 }
254
255 pub fn tag_sint(&mut self, key: impl AsRef<str>, value: i64) -> MvtResult<&mut Self> {
256 self.tag(key, MvtValue::SInt(value))
257 }
258
259 pub fn tag_auto_int(
263 &mut self,
264 key: impl AsRef<str>,
265 value: impl Into<i64>,
266 ) -> MvtResult<&mut Self> {
267 self.tag(key, MvtValue::auto_int(value))
268 }
269
270 pub fn tag_bool(&mut self, key: impl AsRef<str>, value: bool) -> MvtResult<&mut Self> {
271 self.tag(key, MvtValue::Bool(value))
272 }
273
274 #[must_use]
275 pub fn num_tags(&self) -> usize {
276 self.feature.tags.len() / 2
277 }
278
279 #[must_use]
280 pub fn end(mut self) -> MvtLayerBuilder {
281 self.layer.layer.features.push(self.feature);
282 self.layer
283 }
284}
285
286unsafe impl PtrRead for MvtValue {}
289
290fn value_to_proto(value: MvtValue) -> Value {
291 match value {
292 MvtValue::String(v) => Value::default().with_string_value(v),
293 MvtValue::Float(v) => Value::default().with_float_value(v),
294 MvtValue::Double(v) => Value::default().with_double_value(v),
295 MvtValue::Int(v) => Value::default().with_int_value(v),
296 MvtValue::UInt(v) => Value::default().with_uint_value(v),
297 MvtValue::SInt(v) => Value::default().with_sint_value(v),
298 MvtValue::Bool(v) => Value::default().with_bool_value(v),
299 MvtValue::Null => Value::default(),
300 }
301}
302
303fn u32_index(value: usize) -> MvtResult<u32> {
304 u32::try_from(value).map_err(|_| MvtError::IndexOverflow(value))
305}
306
307#[cfg(test)]
308mod tests {
309 #![expect(clippy::panic_in_result_fn)]
310
311 use geo_types::point;
312
313 use super::*;
314 use crate::MvtGeometry;
315
316 #[test]
317 fn layer_builder_deduplicates_keys_and_values() {
318 let layer = MvtTileBuilder::new().layer("layer").unwrap();
319 let mut feature = layer
320 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))
321 .unwrap();
322 feature.tag("foo", MvtValue::String("bar".into())).unwrap();
323 feature.tag("foo", MvtValue::String("baz".into())).unwrap();
324 feature.tag("bar", MvtValue::String("bar".into())).unwrap();
325 feature.tag("n", MvtValue::Int(1)).unwrap();
326 feature.tag("n", MvtValue::SInt(1)).unwrap();
327 feature.tag("f", MvtValue::Float(f32::NAN)).unwrap();
328 feature.tag("f", MvtValue::Float(f32::NAN)).unwrap();
329
330 assert_eq!(
331 feature.feature.tags,
332 vec![0, 0, 0, 1, 1, 0, 2, 2, 2, 3, 3, 4, 3, 4]
333 );
334 }
335
336 #[test]
337 fn encode_appends_and_validates_tile_metadata() {
338 let tile = MvtTileBuilder::new();
339 let layer = tile.layer("layer").unwrap();
340 let mut feature = layer
341 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))
342 .unwrap();
343 feature.id(Some(1));
344 feature.tag("skip", MvtValue::Null).unwrap();
345 let layer = feature.end();
346 let bytes = layer.end().encode();
347 let proto = Tile::decode_from_slice(&bytes).unwrap();
348 assert!(proto.layers[0].keys.is_empty());
349 assert!(proto.layers[0].features[0].tags.is_empty());
350
351 let tile = MvtTileBuilder::new();
352 let layer = tile.layer("layer").unwrap();
353 let mut feature = layer
354 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))
355 .unwrap();
356 feature.id(Some(1));
357 let layer = feature.end();
358 let tile = layer.end();
359 let mut out = vec![0xaa];
360 out.extend_from_slice(&tile.encode());
361 assert_eq!(out[0], 0xaa);
362
363 let tile = MvtTileBuilder::new();
364 let tile = tile.layer("same").unwrap().end();
365 let tile = tile.layer("same").unwrap().end();
366 assert!(!tile.encode().is_empty());
367 }
368
369 #[test]
370 fn encode_ref_matches_owned_encode() {
371 let mut feature = crate::MvtFeature::new(MvtGeometry::Point(point! { x: 1, y: 2 }));
372 feature.set_id(7);
373 feature.add_tag_string("name", "Example");
374 feature.add_tag_bool("visible", true);
375
376 let mut layer = crate::MvtLayer::new("places", DEFAULT_EXTENT);
377 layer.add_feature(feature);
378
379 let mut tile = MvtTile::new();
380 tile.add_layer(layer);
381
382 assert_eq!(
383 encode_tile(tile.clone()).unwrap(),
384 encode_tile_ref(&tile).unwrap()
385 );
386 }
387
388 #[test]
389 #[cfg(feature = "reader")]
390 fn standalone_layer_encode_matches_tile_path_and_concatenates() {
391 use crate::reader::MvtReaderRef;
392
393 let build = |name| -> MvtResult<Vec<u8>> {
394 let mut feature =
395 MvtLayerBuilder::new(name)?.feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))?;
396 feature.tag("k", MvtValue::UInt(1))?;
397 Ok(feature.end().encode())
398 };
399
400 let via_tile = MvtTileBuilder::new()
402 .layer("roads")
403 .unwrap()
404 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))
405 .unwrap();
406 let mut via_tile = via_tile;
407 via_tile.tag("k", MvtValue::UInt(1)).unwrap();
408 let via_tile = via_tile.end().end().encode();
409 assert_eq!(build("roads").unwrap(), via_tile);
410
411 let tile = [build("roads").unwrap(), build("water").unwrap()].concat();
413 let reader = MvtReaderRef::new(&tile).unwrap();
414 let names: Vec<_> = reader.layers().map(|l| l.name().to_string()).collect();
415 assert_eq!(names, ["roads", "water"]);
416 }
417
418 #[test]
419 #[cfg(feature = "reader")]
420 fn layer_builder_chains_to_next_layer() -> MvtResult<()> {
421 use crate::reader::MvtReaderRef;
422
423 let chained = MvtLayerBuilder::new("roads")?
426 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))?
427 .end()
428 .layer("water")?
429 .feature(&MvtGeometry::Point(point! { x: 3, y: 4 }))?
430 .end()
431 .encode();
432
433 let reader = MvtReaderRef::new(&chained)?;
434 let names: Vec<_> = reader.layers().map(|l| l.name().to_string()).collect();
435 assert_eq!(names, ["roads", "water"]);
436 Ok(())
437 }
438
439 #[test]
440 fn layer_builder_chain_rejects_empty_name() {
441 let layer = MvtLayerBuilder::new("roads").unwrap();
442 assert!(matches!(layer.layer(""), Err(MvtError::MissingLayerName)));
443 }
444
445 #[test]
446 fn standalone_layer_builder_rejects_empty_name() {
447 assert!(matches!(
448 MvtLayerBuilder::new(""),
449 Err(MvtError::MissingLayerName)
450 ));
451 assert!(matches!(
452 MvtLayerBuilder::with_capacity("", 1),
453 Err(MvtError::MissingLayerName)
454 ));
455 }
456
457 #[test]
458 fn layer_builder_rejects_empty_name() {
459 assert!(matches!(
460 MvtTileBuilder::new().layer(""),
461 Err(MvtError::MissingLayerName)
462 ));
463 assert!(matches!(
464 MvtTileBuilder::new().layer_with_capacity("", 1),
465 Err(MvtError::MissingLayerName)
466 ));
467 }
468
469 #[test]
470 fn builder_encoded_len_matches_encoded_bytes() {
471 let builder = MvtTileBuilder::new()
472 .layer("l")
473 .unwrap()
474 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))
475 .unwrap()
476 .end()
477 .end();
478 let len = builder.encoded_len();
479 assert_eq!(len, builder.encode().len());
480 }
481
482 #[test]
483 fn layer_builder_accepts_feature_capacity() {
484 let layer = MvtTileBuilder::new()
485 .layer_with_capacity("layer", 2)
486 .unwrap();
487 assert_eq!(layer.layer.features.capacity(), 2);
488 }
489
490 #[test]
491 #[cfg(feature = "reader")]
492 fn tag_auto_int_round_trips_through_reader() {
493 use crate::reader::{MvtReaderRef, MvtValueRef};
494
495 let tile = MvtTileBuilder::new();
496 let layer = tile.layer("l").unwrap();
497 let mut feature = layer
498 .feature(&MvtGeometry::Point(point! { x: 1, y: 2 }))
499 .unwrap();
500 feature.tag_auto_int("pos", 100_i32).unwrap();
501 feature.tag_auto_int("neg", -100_i16).unwrap();
502 feature.tag_auto_int("zero", 0_i64).unwrap();
503 let bytes = feature.end().end().encode();
504
505 let reader = MvtReaderRef::new(&bytes).unwrap();
506 let layer = reader.layers().next().unwrap();
507 let feature = layer.features().next().unwrap();
508 let props = feature.properties_vec().unwrap();
509
510 assert_eq!(props[0].0, "pos");
512 assert_eq!(props[0].1, MvtValueRef::UInt(100));
513 assert_eq!(props[1].0, "neg");
514 assert_eq!(props[1].1, MvtValueRef::SInt(-100));
515 assert_eq!(props[2].0, "zero");
516 assert_eq!(props[2].1, MvtValueRef::UInt(0));
517 }
518
519 #[test]
520 fn auto_int_is_never_larger_than_int_or_sint() {
521 for v in [
522 0_i64,
523 1,
524 63,
525 64,
526 127,
527 128,
528 -1,
529 -64,
530 -100,
531 i64::MIN,
532 i64::MAX,
533 ] {
534 let auto = value_to_proto(MvtValue::auto_int(v)).encoded_len();
535 let int = value_to_proto(MvtValue::Int(v)).encoded_len();
536 let sint = value_to_proto(MvtValue::SInt(v)).encoded_len();
537 assert!(auto <= int, "v={v}: auto {auto} > int {int}");
538 assert!(auto <= sint, "v={v}: auto {auto} > sint {sint}");
539 }
540 }
541
542 #[test]
543 fn value_to_proto_handles_all_variants() {
544 assert_eq!(
545 value_to_proto(MvtValue::String("x".into()))
546 .string_value
547 .as_deref(),
548 Some("x")
549 );
550 assert_eq!(value_to_proto(MvtValue::Float(1.0)).float_value, Some(1.0));
551 assert_eq!(
552 value_to_proto(MvtValue::Double(2.0)).double_value,
553 Some(2.0)
554 );
555 assert_eq!(value_to_proto(MvtValue::Int(-3)).int_value, Some(-3));
556 assert_eq!(value_to_proto(MvtValue::UInt(4)).uint_value, Some(4));
557 assert_eq!(value_to_proto(MvtValue::SInt(-5)).sint_value, Some(-5));
558 assert_eq!(value_to_proto(MvtValue::Bool(true)).bool_value, Some(true));
559 assert_eq!(value_to_proto(MvtValue::Null), Value::default());
560 }
561}