Skip to main content

fast_mvt/reader/
property.rs

1use std::fmt;
2
3use usize_cast::IntoUsize;
4
5use crate::generated::vector_tile::tile as proto_tile;
6use crate::{MvtError, MvtResult, MvtValue};
7
8#[derive(Debug, Clone)]
9pub struct MvtPropertyIter<'a> {
10    keys: &'a [&'a str],
11    values: &'a [proto_tile::ValueView<'a>],
12    tags: std::slice::Chunks<'a, u32>,
13}
14
15impl<'a> MvtPropertyIter<'a> {
16    pub(crate) fn new(
17        keys: &'a [&'a str],
18        values: &'a [proto_tile::ValueView<'a>],
19        tags: std::slice::Chunks<'a, u32>,
20    ) -> Self {
21        Self { keys, values, tags }
22    }
23}
24
25impl<'a> Iterator for MvtPropertyIter<'a> {
26    type Item = MvtResult<(&'a str, MvtValueRef<'a>)>;
27
28    fn next(&mut self) -> Option<Self::Item> {
29        let pair = self.tags.next()?;
30        let [key_idx, value_idx] = pair else {
31            return Some(Err(MvtError::InvalidTagsLength(pair.len())));
32        };
33        let key = match self.keys.get((*key_idx).into_usize()) {
34            Some(key) => *key,
35            None => return Some(Err(MvtError::InvalidKeyIndex(*key_idx))),
36        };
37        let value = match self.values.get((*value_idx).into_usize()) {
38            Some(value) => value_ref(value),
39            None => return Some(Err(MvtError::InvalidValueIndex(*value_idx))),
40        };
41        Some(Ok((key, value)))
42    }
43}
44
45#[derive(Copy, Clone, PartialEq)]
46pub enum MvtValueRef<'a> {
47    String(&'a str),
48    Float(f32),
49    Double(f64),
50    Int(i64),
51    UInt(u64),
52    SInt(i64),
53    Bool(bool),
54    Null,
55}
56
57impl MvtValueRef<'_> {
58    #[must_use]
59    pub fn into_owned(self) -> MvtValue {
60        match self {
61            Self::String(value) => MvtValue::String(value.to_string()),
62            Self::Float(value) => MvtValue::Float(value),
63            Self::Double(value) => MvtValue::Double(value),
64            Self::Int(value) => MvtValue::Int(value),
65            Self::UInt(value) => MvtValue::UInt(value),
66            Self::SInt(value) => MvtValue::SInt(value),
67            Self::Bool(value) => MvtValue::Bool(value),
68            Self::Null => MvtValue::Null,
69        }
70    }
71}
72
73impl fmt::Debug for MvtValueRef<'_> {
74    /// Renders the bare textual value (strings quoted)
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match *self {
77            MvtValueRef::String(value) => write!(f, "{value:?}"),
78            MvtValueRef::Float(value) => write!(f, "{value} (float)"),
79            MvtValueRef::Double(value) => write!(f, "{value} (double)"),
80            MvtValueRef::Int(value) => write!(f, "{value} (int)"),
81            MvtValueRef::SInt(value) => write!(f, "{value} (sint)"),
82            MvtValueRef::UInt(value) => write!(f, "{value} (uint)"),
83            MvtValueRef::Bool(value) => write!(f, "{value} (bool)"),
84            MvtValueRef::Null => f.write_str("null"),
85        }
86    }
87}
88
89pub(crate) fn value_ref<'a>(value: &'a proto_tile::ValueView<'a>) -> MvtValueRef<'a> {
90    if let Some(value) = value.string_value {
91        MvtValueRef::String(value)
92    } else if let Some(value) = value.float_value {
93        MvtValueRef::Float(value)
94    } else if let Some(value) = value.double_value {
95        MvtValueRef::Double(value)
96    } else if let Some(value) = value.int_value {
97        MvtValueRef::Int(value)
98    } else if let Some(value) = value.uint_value {
99        MvtValueRef::UInt(value)
100    } else if let Some(value) = value.sint_value {
101        MvtValueRef::SInt(value)
102    } else if let Some(value) = value.bool_value {
103        MvtValueRef::Bool(value)
104    } else {
105        MvtValueRef::Null
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use crate::MvtReaderRef;
113    use crate::reader::tests::{encode_layer, first_feature};
114
115    #[test]
116    fn value_ref_debug_renders_bare_values() {
117        insta::assert_debug_snapshot!(MvtValueRef::String("x"), @r#""x""#);
118        insta::assert_debug_snapshot!(MvtValueRef::Float(1.25), @"1.25 (float)");
119        insta::assert_debug_snapshot!(MvtValueRef::Double(2.5), @"2.5 (double)");
120        insta::assert_debug_snapshot!(MvtValueRef::Int(-3), @"-3 (int)");
121        insta::assert_debug_snapshot!(MvtValueRef::UInt(4), @"4 (uint)");
122        insta::assert_debug_snapshot!(MvtValueRef::SInt(-5), @"-5 (sint)");
123        insta::assert_debug_snapshot!(MvtValueRef::Bool(true), @"true (bool)");
124        insta::assert_debug_snapshot!(MvtValueRef::Null, @"null");
125    }
126
127    #[test]
128    fn value_ref_into_owned_covers_every_variant() {
129        assert_eq!(
130            MvtValueRef::String("x").into_owned(),
131            MvtValue::String("x".into())
132        );
133        assert_eq!(MvtValueRef::Float(1.25).into_owned(), MvtValue::Float(1.25));
134        assert_eq!(MvtValueRef::Double(2.5).into_owned(), MvtValue::Double(2.5));
135        assert_eq!(MvtValueRef::Int(-3).into_owned(), MvtValue::Int(-3));
136        assert_eq!(MvtValueRef::UInt(4).into_owned(), MvtValue::UInt(4));
137        assert_eq!(MvtValueRef::SInt(-5).into_owned(), MvtValue::SInt(-5));
138        assert_eq!(MvtValueRef::Bool(true).into_owned(), MvtValue::Bool(true));
139        assert_eq!(MvtValueRef::Null.into_owned(), MvtValue::Null);
140    }
141
142    #[test]
143    fn property_iterator_reports_malformed_tags() {
144        let layer = proto_tile::Layer {
145            version: 2,
146            name: "tags".into(),
147            keys: vec!["k".into()],
148            values: vec![proto_tile::Value::default()],
149            ..Default::default()
150        };
151
152        for (tags, expected) in [
153            (vec![0], "invalid feature tags length: 1"),
154            (vec![1, 0], "invalid key index 1"),
155            (vec![0, 1], "invalid value index 1"),
156        ] {
157            let feature = proto_tile::Feature {
158                tags,
159                ..Default::default()
160            };
161            let mut layer = layer.clone();
162            layer.features = vec![feature];
163            let bytes = encode_layer(layer);
164            let reader = MvtReaderRef::new(&bytes).unwrap();
165            let err = first_feature(&reader)
166                .properties()
167                .next()
168                .unwrap()
169                .unwrap_err();
170            assert_eq!(err.to_string(), expected);
171        }
172    }
173}