Skip to main content

fast_mvt/
types.rs

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    /// Add an integer tag using the smallest MVT encoding for `value`.
136    ///
137    /// See [`MvtValue::auto_int`] for how the encoding is chosen.
138    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    /// Create an integer value using the smallest MVT wire encoding for `value`.
161    ///
162    /// Non-negative values become [`MvtValue::UInt`] (a plain varint) and negative
163    /// values become [`MvtValue::SInt`] (a zig-zag varint), whichever needs fewer
164    /// bytes. This is always at least as compact as [`MvtValue::Int`], which
165    /// sign-extends any negative to a full 10-byte varint.
166    ///
167    /// Accepts any signed integer that fits in `i64` (`i8`/`i16`/`i32`/`i64`).
168    #[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        // Non-negative -> UInt, negative -> SInt.
390        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        // Non-negative -> UInt (plain varint); negative -> SInt (zig-zag varint).
435        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        // Accepts all narrower signed widths.
443        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}