1pub mod error;
62pub mod feature;
63
64mod vector_tile;
65
66use feature::{Feature, Value};
67use geo_types::{
68 Coord, Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
69};
70use prost::{Message, bytes::Bytes};
71use vector_tile::{Tile, tile::GeomType};
72
73const DIMENSION: u32 = 2;
75
76pub struct Reader {
78 tile: Tile,
79}
80
81impl Reader {
82 pub fn new(data: Vec<u8>) -> Result<Self, error::ParserError> {
101 match Tile::decode(Bytes::from(data)) {
102 Ok(tile) => Ok(Self { tile }),
103 Err(error) => Err(error::ParserError::new(error::DecodeError::new(Box::new(
104 error,
105 )))),
106 }
107 }
108
109 pub fn get_layer_names(&self) -> Result<Vec<String>, error::ParserError> {
135 let mut layer_names = Vec::with_capacity(self.tile.layers.len());
136 for layer in self.tile.layers.iter() {
137 match layer.version {
138 1 | 2 => {
139 layer_names.push(layer.name.clone());
140 }
141 _ => {
142 return Err(error::ParserError::new(error::VersionError::new(
143 layer.name.clone(),
144 layer.version,
145 )));
146 }
147 }
148 }
149 Ok(layer_names)
150 }
151
152 pub fn get_features(&self, layer_index: usize) -> Result<Vec<Feature>, error::ParserError> {
182 let layer = self.tile.layers.get(layer_index);
183 match layer {
184 Some(layer) => {
185 let mut features = Vec::with_capacity(layer.features.len());
186 for feature in layer.features.iter() {
187 if let Some(geom_type) = feature.r#type {
188 match GeomType::try_from(geom_type) {
189 Ok(geom_type) => {
190 let parsed_geometry = match parse_geometry(&feature.geometry, geom_type) {
191 Ok(parsed_geometry) => parsed_geometry,
192 Err(error) => {
193 return Err(error);
194 }
195 };
196
197 let parsed_tags = match parse_tags(&feature.tags, &layer.keys, &layer.values) {
198 Ok(parsed_tags) => parsed_tags,
199 Err(error) => {
200 return Err(error);
201 }
202 };
203
204 features.push(Feature {
205 geometry: parsed_geometry,
206 id: feature.id,
207 properties: Some(parsed_tags),
208 });
209 }
210 Err(error) => {
211 return Err(error::ParserError::new(error::DecodeError::new(Box::new(
212 error,
213 ))));
214 }
215 }
216 }
217 }
218 Ok(features)
219 }
220 None => Ok(vec![]),
221 }
222 }
223}
224
225fn parse_tags(
226 tags: &[u32],
227 keys: &[String],
228 values: &[vector_tile::tile::Value],
229) -> Result<std::collections::HashMap<String, Value>, error::ParserError> {
230 let mut result = std::collections::HashMap::new();
231 for item in tags.chunks(2) {
232 if item.len() != 2
233 || item[0] >= keys.len().try_into().unwrap()
234 || item[1] >= values.len().try_into().unwrap()
235 {
236 return Err(error::ParserError::new(error::TagsError::new()));
237 }
238 result.insert(
239 keys[item[0] as usize].clone(),
240 map_value(values[item[1] as usize].clone()),
241 );
242 }
243 Ok(result)
244}
245
246fn map_value(value: vector_tile::tile::Value) -> Value {
247 if let Some(s) = value.string_value {
248 return Value::String(s);
249 }
250 if let Some(f) = value.float_value {
251 return Value::Float(f);
252 }
253 if let Some(d) = value.double_value {
254 return Value::Double(d);
255 }
256 if let Some(i) = value.int_value {
257 return Value::Int(i);
258 }
259 if let Some(u) = value.uint_value {
260 return Value::UInt(u);
261 }
262 if let Some(s) = value.sint_value {
263 return Value::SInt(s);
264 }
265 if let Some(b) = value.bool_value {
266 return Value::Bool(b);
267 }
268 Value::Null
269}
270
271fn shoelace_formula(points: &[Point<f32>]) -> f32 {
272 let mut area: f32 = 0.0;
273 let n = points.len();
274 let mut v1 = points[n - 1];
275 for v2 in points.iter().take(n) {
276 area += (v2.y() - v1.y()) * (v2.x() + v1.x());
277 v1 = *v2;
278 }
279 area * 0.5
280}
281
282fn parse_geometry(
283 geometry_data: &[u32],
284 geom_type: GeomType,
285) -> Result<Geometry<f32>, error::ParserError> {
286 if geom_type == GeomType::Unknown {
287 return Err(error::ParserError::new(error::GeometryError::new()));
288 }
289
290 let mut coordinates: Vec<Coord<f32>> = Vec::with_capacity(geometry_data.len());
292 let mut polygons: Vec<Polygon<f32>> = Vec::new();
293 let mut linestrings: Vec<LineString<f32>> = Vec::new();
294
295 let mut cursor: [i32; 2] = [0, 0];
296 let mut parameter_count: u32 = 0;
297
298 for value in geometry_data.iter() {
299 if parameter_count == 0 {
300 let command_integer = value;
301 let id = (command_integer & 0x7) as u8;
302 match id {
303 1 => {
304 parameter_count = (command_integer >> 3) * DIMENSION;
306 if geom_type == GeomType::Linestring && !coordinates.is_empty() {
307 linestrings.push(LineString::new(coordinates));
308 coordinates = Vec::with_capacity(geometry_data.len());
310 }
311 }
312 2 => {
313 parameter_count = (command_integer >> 3) * DIMENSION;
315 }
316 7 => {
317 let first_coordinate = match coordinates.first() {
319 Some(coord) => coord.to_owned(),
320 None => {
321 return Err(error::ParserError::new(error::GeometryError::new()));
322 }
323 };
324 coordinates.push(first_coordinate);
325
326 let ring = LineString::new(coordinates);
327
328 let area = shoelace_formula(&ring.clone().into_points());
329
330 if area > 0.0 {
331 if !linestrings.is_empty() {
333 polygons.push(Polygon::new(
335 linestrings[0].clone(),
336 linestrings[1..].into(),
337 ));
338 linestrings = Vec::new();
339 }
340 }
341
342 linestrings.push(ring);
343 coordinates = Vec::with_capacity(geometry_data.len());
345 }
346 _ => (),
347 }
348 } else {
349 let parameter_integer = value;
350 let integer_value = ((parameter_integer >> 1) as i32) ^ -((parameter_integer & 1) as i32);
351 if parameter_count % DIMENSION == 0 {
352 cursor[0] = match cursor[0].checked_add(integer_value) {
353 Some(result) => result,
354 None => i32::MAX, };
356 } else {
357 cursor[1] = match cursor[1].checked_add(integer_value) {
358 Some(result) => result,
359 None => i32::MAX, };
361 coordinates.push(Coord {
362 x: cursor[0] as f32,
363 y: cursor[1] as f32,
364 });
365 }
366 parameter_count -= 1;
367 }
368 }
369
370 match geom_type {
371 GeomType::Linestring => {
372 if !linestrings.is_empty() {
374 linestrings.push(LineString::new(coordinates));
375 return Ok(MultiLineString::new(linestrings).into());
376 }
377 Ok(LineString::new(coordinates).into())
378 }
379 GeomType::Point => Ok(
380 MultiPoint(
381 coordinates
382 .iter()
383 .map(|coord| Point::new(coord.x, coord.y))
384 .collect(),
385 )
386 .into(),
387 ),
388 GeomType::Polygon => {
389 if !linestrings.is_empty() {
390 polygons.push(Polygon::new(
392 linestrings[0].clone(),
393 linestrings[1..].into(),
394 ));
395 return Ok(MultiPolygon::new(polygons).into());
396 }
397 match polygons.first() {
398 Some(polygon) => Ok(polygon.to_owned().into()),
399 None => Err(error::ParserError::new(error::GeometryError::new())),
400 }
401 }
402 GeomType::Unknown => Err(error::ParserError::new(error::GeometryError::new())),
403 }
404}
405
406#[cfg(feature = "wasm")]
407pub mod wasm {
408
409 use crate::feature::Value;
410 use geojson::{Feature, GeoJson, JsonObject, JsonValue, feature::Id};
411 use serde::Serialize;
412 use serde_wasm_bindgen::Serializer;
413 use wasm_bindgen::prelude::*;
414
415 impl From<Value> for JsonValue {
416 fn from(value: Value) -> Self {
417 match value {
418 Value::Null => JsonValue::Null,
419 Value::Bool(b) => JsonValue::from(b),
420 Value::Int(i) => JsonValue::from(i),
421 Value::UInt(u) => JsonValue::from(u),
422 Value::SInt(s) => JsonValue::from(s),
423 Value::Float(f) => JsonValue::from(f),
424 Value::Double(d) => JsonValue::from(d),
425 Value::String(s) => JsonValue::from(s),
426 }
427 }
428 }
429
430 impl From<super::feature::Feature> for wasm_bindgen::JsValue {
432 fn from(feature: super::feature::Feature) -> Self {
433 let properties: Option<JsonObject> = feature.properties.as_ref().map(|props| {
434 props
435 .clone()
436 .into_iter()
437 .map(|(k, v)| (k, v.into()))
438 .collect()
439 });
440
441 let geojson = GeoJson::Feature(Feature {
442 bbox: None,
443 geometry: Some(feature.get_geometry().into()),
444 id: feature.id.map(|id| Id::Number(id.into())),
445 properties,
446 foreign_members: None,
447 });
448
449 geojson.serialize(&Serializer::json_compatible()).unwrap()
450 }
451 }
452
453 #[wasm_bindgen]
455 pub struct Reader {
456 reader: Option<super::Reader>,
457 }
458
459 #[wasm_bindgen]
460 impl Reader {
461 #[wasm_bindgen(constructor)]
475 pub fn new(data: Vec<u8>, error_callback: Option<js_sys::Function>) -> Reader {
476 let reader = match super::Reader::new(data) {
477 Ok(reader) => Some(reader),
478 Err(error) => {
479 if let Some(callback) = error_callback {
480 callback
481 .call1(&JsValue::NULL, &JsValue::from_str(&format!("{:?}", error)))
482 .unwrap();
483 }
484 None
485 }
486 };
487 Reader { reader }
488 }
489
490 #[wasm_bindgen(js_name = getLayerNames)]
509 pub fn get_layer_names(&self, error_callback: Option<js_sys::Function>) -> JsValue {
510 match &self.reader {
511 Some(reader) => match reader.get_layer_names() {
512 Ok(layer_names) => JsValue::from(
513 layer_names
514 .into_iter()
515 .map(JsValue::from)
516 .collect::<js_sys::Array>(),
517 ),
518 Err(error) => {
519 if let Some(callback) = error_callback {
520 callback
521 .call1(&JsValue::NULL, &JsValue::from_str(&format!("{:?}", error)))
522 .unwrap();
523 }
524 JsValue::NULL
525 }
526 },
527 None => JsValue::NULL,
528 }
529 }
530
531 #[wasm_bindgen(js_name = getFeatures)]
551 pub fn get_features(
552 &self,
553 layer_index: usize,
554 error_callback: Option<js_sys::Function>,
555 ) -> JsValue {
556 match &self.reader {
557 Some(reader) => match reader.get_features(layer_index) {
558 Ok(features) => JsValue::from(
559 features
560 .into_iter()
561 .map(JsValue::from)
562 .collect::<js_sys::Array>(),
563 ),
564 Err(error) => {
565 if let Some(callback) = error_callback {
566 callback
567 .call1(&JsValue::NULL, &JsValue::from_str(&format!("{:?}", error)))
568 .unwrap();
569 }
570 JsValue::NULL
571 }
572 },
573 None => JsValue::NULL,
574 }
575 }
576 }
577}