1use std::borrow::Cow;
2use std::num::NonZeroU32;
3
4use geo_types::{
5 Coord, Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
6};
7
8#[cfg(feature = "writer")]
9use crate::MvtResult;
10
11pub type MvtExtent = NonZeroU32;
12pub type MvtCoord = Coord<i32>;
13pub type MvtPoint = Point<i32>;
14pub type MvtLineString = LineString<i32>;
15pub type MvtPolygon = Polygon<i32>;
16pub type MvtMultiPoint = MultiPoint<i32>;
17pub type MvtMultiLineString = MultiLineString<i32>;
18pub type MvtMultiPolygon = MultiPolygon<i32>;
19pub type MvtGeometry = Geometry<i32>;
20
21pub const DEFAULT_EXTENT: MvtExtent = MvtExtent::new(4096).unwrap();
22
23#[derive(Debug, Clone, Default, PartialEq)]
24pub struct MvtTile {
25 pub layers: Vec<MvtLayer>,
26}
27
28#[derive(Debug, Clone, PartialEq)]
29pub struct MvtLayer {
30 pub name: String,
31 pub extent: NonZeroU32,
32 pub features: Vec<MvtFeature>,
33}
34
35#[derive(Debug, Clone, PartialEq)]
36pub struct MvtFeature {
37 pub id: Option<u64>,
38 pub geometry: MvtGeometry,
39 pub properties: Vec<(String, MvtValue)>,
40}
41
42impl MvtTile {
43 #[must_use]
44 pub fn new() -> Self {
45 Self::default()
46 }
47
48 pub fn add_layer(&mut self, layer: MvtLayer) {
49 self.layers.push(layer);
50 }
51
52 #[cfg(feature = "writer")]
53 pub fn encode(self) -> MvtResult<Vec<u8>> {
54 crate::writer::encode_tile(self)
55 }
56
57 #[cfg(feature = "writer")]
58 pub fn encode_ref(&self) -> MvtResult<Vec<u8>> {
59 crate::writer::encode_tile_ref(self)
60 }
61}
62
63impl MvtLayer {
64 #[must_use]
65 pub fn new(name: impl Into<String>, extent: MvtExtent) -> Self {
66 Self {
67 name: name.into(),
68 extent,
69 features: Vec::new(),
70 }
71 }
72
73 #[must_use]
74 pub fn name(&self) -> &str {
75 &self.name
76 }
77
78 #[must_use]
79 pub fn num_features(&self) -> usize {
80 self.features.len()
81 }
82
83 pub fn add_feature(&mut self, feature: MvtFeature) {
84 self.features.push(feature);
85 }
86}
87
88impl MvtFeature {
89 #[must_use]
90 pub fn new(geometry: MvtGeometry) -> Self {
91 Self {
92 id: None,
93 geometry,
94 properties: Vec::new(),
95 }
96 }
97
98 pub fn set_id(&mut self, id: u64) {
99 self.id = Some(id);
100 }
101
102 #[must_use]
103 pub fn num_tags(&self) -> usize {
104 self.properties.len()
105 }
106
107 pub fn add_tag(&mut self, key: impl Into<String>, value: MvtValue) {
108 self.properties.push((key.into(), value));
109 }
110
111 pub fn add_tag_string(&mut self, key: impl Into<String>, value: impl Into<String>) {
112 self.add_tag(key, MvtValue::String(value.into()));
113 }
114
115 pub fn add_tag_float(&mut self, key: impl Into<String>, value: f32) {
116 self.add_tag(key, MvtValue::Float(value));
117 }
118
119 pub fn add_tag_double(&mut self, key: impl Into<String>, value: f64) {
120 self.add_tag(key, MvtValue::Double(value));
121 }
122
123 pub fn add_tag_int(&mut self, key: impl Into<String>, value: i64) {
124 self.add_tag(key, MvtValue::Int(value));
125 }
126
127 pub fn add_tag_uint(&mut self, key: impl Into<String>, value: u64) {
128 self.add_tag(key, MvtValue::UInt(value));
129 }
130
131 pub fn add_tag_sint(&mut self, key: impl Into<String>, value: i64) {
132 self.add_tag(key, MvtValue::SInt(value));
133 }
134
135 pub fn add_tag_auto_int(&mut self, key: impl Into<String>, value: impl Into<i64>) {
139 self.add_tag(key, MvtValue::auto_int(value));
140 }
141
142 pub fn add_tag_bool(&mut self, key: impl Into<String>, value: bool) {
143 self.add_tag(key, MvtValue::Bool(value));
144 }
145}
146
147#[derive(Debug, Clone)]
148pub enum MvtValue {
149 String(String),
150 Float(f32),
151 Double(f64),
152 Int(i64),
153 UInt(u64),
154 SInt(i64),
155 Bool(bool),
156 Null,
157}
158
159impl MvtValue {
160 #[must_use]
169 pub fn auto_int(value: impl Into<i64>) -> Self {
170 let value = value.into();
171 if value >= 0 {
172 Self::UInt(value.cast_unsigned())
173 } else {
174 Self::SInt(value)
175 }
176 }
177}
178
179impl From<String> for MvtValue {
180 fn from(value: String) -> Self {
181 Self::String(value)
182 }
183}
184
185impl From<&str> for MvtValue {
186 fn from(value: &str) -> Self {
187 Self::String(value.to_string())
188 }
189}
190
191impl From<Cow<'_, str>> for MvtValue {
192 fn from(value: Cow<'_, str>) -> Self {
193 Self::String(value.into_owned())
194 }
195}
196
197impl From<f32> for MvtValue {
198 fn from(value: f32) -> Self {
199 Self::Float(value)
200 }
201}
202
203impl From<f64> for MvtValue {
204 fn from(value: f64) -> Self {
205 Self::Double(value)
206 }
207}
208
209impl From<i64> for MvtValue {
210 fn from(value: i64) -> Self {
211 Self::Int(value)
212 }
213}
214
215impl From<i32> for MvtValue {
216 fn from(value: i32) -> Self {
217 Self::Int(i64::from(value))
218 }
219}
220
221impl From<i16> for MvtValue {
222 fn from(value: i16) -> Self {
223 Self::Int(i64::from(value))
224 }
225}
226
227impl From<i8> for MvtValue {
228 fn from(value: i8) -> Self {
229 Self::Int(i64::from(value))
230 }
231}
232
233impl From<u64> for MvtValue {
234 fn from(value: u64) -> Self {
235 Self::UInt(value)
236 }
237}
238
239impl From<u32> for MvtValue {
240 fn from(value: u32) -> Self {
241 Self::UInt(u64::from(value))
242 }
243}
244
245impl From<u16> for MvtValue {
246 fn from(value: u16) -> Self {
247 Self::UInt(u64::from(value))
248 }
249}
250
251impl From<u8> for MvtValue {
252 fn from(value: u8) -> Self {
253 Self::UInt(u64::from(value))
254 }
255}
256
257impl From<bool> for MvtValue {
258 fn from(value: bool) -> Self {
259 Self::Bool(value)
260 }
261}
262
263#[cfg(feature = "json")]
264#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
265#[non_exhaustive]
266pub enum MvtJsonValueError {
267 #[error("non-finite float cannot be represented as JSON")]
268 NonFiniteFloat,
269 #[error("invalid JSON number")]
270 InvalidJsonNumber,
271 #[error("JSON array cannot be represented as an MVT value")]
272 UnsupportedJsonArray,
273 #[error("JSON object cannot be represented as an MVT value")]
274 UnsupportedJsonObject,
275}
276
277#[cfg(feature = "json")]
278impl TryFrom<MvtValue> for serde_json::Value {
279 type Error = MvtJsonValueError;
280
281 fn try_from(value: MvtValue) -> Result<Self, Self::Error> {
282 match value {
283 MvtValue::String(value) => Ok(Self::String(value)),
284 MvtValue::Float(value) => json_number(f64::from(value)),
285 MvtValue::Double(value) => json_number(value),
286 MvtValue::Int(value) | MvtValue::SInt(value) => Ok(value.into()),
287 MvtValue::UInt(value) => Ok(value.into()),
288 MvtValue::Bool(value) => Ok(Self::Bool(value)),
289 MvtValue::Null => Ok(Self::Null),
290 }
291 }
292}
293
294#[cfg(feature = "json")]
295impl TryFrom<serde_json::Value> for MvtValue {
296 type Error = MvtJsonValueError;
297
298 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
299 use serde_json::Value;
300
301 match value {
302 Value::Null => Ok(Self::Null),
303 Value::Bool(value) => Ok(Self::Bool(value)),
304 Value::Number(value) => {
305 if let Some(value) = value.as_i64() {
306 Ok(Self::Int(value))
307 } else if let Some(value) = value.as_u64() {
308 Ok(Self::UInt(value))
309 } else if let Some(value) = value.as_f64() {
310 Ok(Self::Double(value))
311 } else {
312 Err(MvtJsonValueError::InvalidJsonNumber)
313 }
314 }
315 Value::String(value) => Ok(Self::String(value)),
316 Value::Array(_) => Err(MvtJsonValueError::UnsupportedJsonArray),
317 Value::Object(_) => Err(MvtJsonValueError::UnsupportedJsonObject),
318 }
319 }
320}
321
322#[cfg(feature = "json")]
323fn json_number(value: f64) -> Result<serde_json::Value, MvtJsonValueError> {
324 serde_json::Number::from_f64(value)
325 .map(serde_json::Value::Number)
326 .ok_or(MvtJsonValueError::NonFiniteFloat)
327}
328
329impl PartialEq for MvtValue {
330 fn eq(&self, other: &Self) -> bool {
331 match (self, other) {
332 (Self::String(a), Self::String(b)) => a == b,
333 (Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
334 (Self::Double(a), Self::Double(b)) => a.to_bits() == b.to_bits(),
335 (Self::Int(a), Self::Int(b)) | (Self::SInt(a), Self::SInt(b)) => a == b,
336 (Self::UInt(a), Self::UInt(b)) => a == b,
337 (Self::Bool(a), Self::Bool(b)) => a == b,
338 (Self::Null, Self::Null) => true,
339 _ => false,
340 }
341 }
342}
343
344impl Eq for MvtValue {}
345
346impl std::hash::Hash for MvtValue {
347 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
348 std::mem::discriminant(self).hash(state);
349 match self {
350 Self::String(v) => v.hash(state),
351 Self::Float(v) => v.to_bits().hash(state),
352 Self::Double(v) => v.to_bits().hash(state),
353 Self::Int(v) | Self::SInt(v) => v.hash(state),
354 Self::UInt(v) => v.hash(state),
355 Self::Bool(v) => v.hash(state),
356 Self::Null => {}
357 }
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use std::borrow::Cow;
364 use std::hash::{Hash, Hasher};
365
366 use geo_types::point;
367
368 use super::*;
369
370 #[test]
371 fn owned_tile_layer_and_feature_helpers_mutate_expected_fields() {
372 let mut feature = MvtFeature::new(MvtGeometry::Point(point! { x: 1, y: 2 }));
373 assert_eq!(feature.id, None);
374 assert_eq!(feature.num_tags(), 0);
375
376 feature.set_id(7);
377 feature.add_tag("raw", MvtValue::Null);
378 feature.add_tag_string("string", "value");
379 feature.add_tag_float("float", 1.25);
380 feature.add_tag_double("double", 2.5);
381 feature.add_tag_int("int", -3);
382 feature.add_tag_uint("uint", 4);
383 feature.add_tag_sint("sint", -5);
384 feature.add_tag_bool("bool", true);
385 feature.add_tag_auto_int("auto_pos", 6_i32);
386 feature.add_tag_auto_int("auto_neg", -7_i16);
387 assert_eq!(feature.id, Some(7));
388 assert_eq!(feature.num_tags(), 10);
389 assert_eq!(feature.properties[8].1, MvtValue::UInt(6));
391 assert_eq!(feature.properties[9].1, MvtValue::SInt(-7));
392
393 let mut layer = MvtLayer::new("places", DEFAULT_EXTENT);
394 assert_eq!(layer.name(), "places");
395 assert_eq!(layer.num_features(), 0);
396 layer.add_feature(feature);
397 assert_eq!(layer.num_features(), 1);
398
399 let mut tile = MvtTile::new();
400 assert!(tile.layers.is_empty());
401 tile.add_layer(layer);
402 assert_eq!(tile.layers.len(), 1);
403 }
404
405 #[test]
406 fn mvt_value_from_impls_preserve_variant_intent() {
407 assert_eq!(
408 MvtValue::from(String::from("owned")),
409 MvtValue::String("owned".into())
410 );
411 assert_eq!(
412 MvtValue::from("borrowed"),
413 MvtValue::String("borrowed".into())
414 );
415 assert_eq!(
416 MvtValue::from(Cow::Borrowed("cow")),
417 MvtValue::String("cow".into())
418 );
419 assert_eq!(MvtValue::from(1.25_f32), MvtValue::Float(1.25));
420 assert_eq!(MvtValue::from(2.5_f64), MvtValue::Double(2.5));
421 assert_eq!(MvtValue::from(-3_i64), MvtValue::Int(-3));
422 assert_eq!(MvtValue::from(-4_i32), MvtValue::Int(-4));
423 assert_eq!(MvtValue::from(-5_i16), MvtValue::Int(-5));
424 assert_eq!(MvtValue::from(-6_i8), MvtValue::Int(-6));
425 assert_eq!(MvtValue::from(7_u64), MvtValue::UInt(7));
426 assert_eq!(MvtValue::from(8_u32), MvtValue::UInt(8));
427 assert_eq!(MvtValue::from(9_u16), MvtValue::UInt(9));
428 assert_eq!(MvtValue::from(10_u8), MvtValue::UInt(10));
429 assert_eq!(MvtValue::from(true), MvtValue::Bool(true));
430 }
431
432 #[test]
433 fn auto_int_picks_smallest_encoding() {
434 assert_eq!(MvtValue::auto_int(0_i64), MvtValue::UInt(0));
436 assert_eq!(MvtValue::auto_int(100_i64), MvtValue::UInt(100));
437 assert_eq!(MvtValue::auto_int(-1_i64), MvtValue::SInt(-1));
438 assert_eq!(MvtValue::auto_int(-100_i64), MvtValue::SInt(-100));
439 assert_eq!(MvtValue::auto_int(i64::MAX), MvtValue::UInt(u64::MAX / 2));
440 assert_eq!(MvtValue::auto_int(i64::MIN), MvtValue::SInt(i64::MIN));
441
442 assert_eq!(MvtValue::auto_int(-6_i8), MvtValue::SInt(-6));
444 assert_eq!(MvtValue::auto_int(-5_i16), MvtValue::SInt(-5));
445 assert_eq!(MvtValue::auto_int(-4_i32), MvtValue::SInt(-4));
446 assert_eq!(MvtValue::auto_int(7_i32), MvtValue::UInt(7));
447 }
448
449 #[test]
450 fn mvt_value_equality_and_hash_include_variant_and_float_bits() {
451 fn hash(value: &MvtValue) -> u64 {
452 let mut hasher = std::collections::hash_map::DefaultHasher::new();
453 value.hash(&mut hasher);
454 hasher.finish()
455 }
456
457 assert_eq!(MvtValue::Float(f32::NAN), MvtValue::Float(f32::NAN));
458 assert_ne!(MvtValue::Int(1), MvtValue::SInt(1));
459 assert_ne!(MvtValue::Int(1), MvtValue::UInt(1));
460 assert_eq!(
461 hash(&MvtValue::Double(f64::NAN)),
462 hash(&MvtValue::Double(f64::NAN))
463 );
464 assert_ne!(hash(&MvtValue::Int(1)), hash(&MvtValue::SInt(1)));
465 assert_eq!(hash(&MvtValue::Null), hash(&MvtValue::Null));
466 }
467}
468
469#[cfg(all(test, feature = "json"))]
470mod tests_json {
471 use serde_json::json;
472
473 use super::*;
474 use crate::generated::vector_tile::Tile;
475
476 #[test]
477 fn mvt_values_convert_to_json_values() {
478 assert_eq!(
479 serde_json::Value::try_from(MvtValue::String("name".into())),
480 Ok(json!("name"))
481 );
482 assert_eq!(
483 serde_json::Value::try_from(MvtValue::Int(-3)),
484 Ok(json!(-3))
485 );
486 assert_eq!(serde_json::Value::try_from(MvtValue::UInt(4)), Ok(json!(4)));
487 assert_eq!(
488 serde_json::Value::try_from(MvtValue::Double(1.5)),
489 Ok(json!(1.5))
490 );
491 assert_eq!(
492 serde_json::Value::try_from(MvtValue::Float(2.5)),
493 Ok(json!(2.5))
494 );
495 assert_eq!(
496 serde_json::Value::try_from(MvtValue::Bool(true)),
497 Ok(json!(true))
498 );
499 assert_eq!(
500 serde_json::Value::try_from(MvtValue::Null),
501 Ok(serde_json::Value::Null)
502 );
503 assert_eq!(
504 serde_json::Value::try_from(MvtValue::Double(f64::NAN)),
505 Err(MvtJsonValueError::NonFiniteFloat)
506 );
507 }
508
509 #[test]
510 fn json_values_convert_to_mvt_values() {
511 assert_eq!(
512 MvtValue::try_from(json!("name")),
513 Ok(MvtValue::String("name".into()))
514 );
515 assert_eq!(MvtValue::try_from(json!(-3)), Ok(MvtValue::Int(-3)));
516 assert_eq!(
517 MvtValue::try_from(json!(u64::MAX)),
518 Ok(MvtValue::UInt(u64::MAX))
519 );
520 assert_eq!(MvtValue::try_from(json!(1.5)), Ok(MvtValue::Double(1.5)));
521 assert_eq!(MvtValue::try_from(json!(true)), Ok(MvtValue::Bool(true)));
522 assert_eq!(
523 MvtValue::try_from(serde_json::Value::Null),
524 Ok(MvtValue::Null)
525 );
526 assert_eq!(
527 MvtValue::try_from(json!([])),
528 Err(MvtJsonValueError::UnsupportedJsonArray)
529 );
530 assert_eq!(
531 MvtValue::try_from(json!({})),
532 Err(MvtJsonValueError::UnsupportedJsonObject)
533 );
534 }
535
536 #[test]
537 fn tile_deserializes_from_object_but_not_layers_array() {
538 let object: Tile = serde_json::from_str(
539 r#"{
540 "layers": [{
541 "version": 2,
542 "name": "places",
543 "extent": 4096
544 }]
545 }"#,
546 )
547 .unwrap();
548
549 let array = serde_json::from_str::<Tile>(
550 r#"[{
551 "version": 2,
552 "name": "places",
553 "extent": 4096
554 }]"#,
555 );
556
557 assert!(array.is_err());
558 assert_eq!(object.layers[0].name, "places");
559 }
560}