use super::FeatureCollectionPBuffer;
use super::feature_collection_p_buffer::*;
use crate::{Feature, FeatureSet, GeometryType, Result};
use prost::Message;
use std::collections::HashMap;
pub fn decode_feature_collection(bytes: &[u8]) -> Result<FeatureSet> {
let pbf = FeatureCollectionPBuffer::decode(bytes).map_err(|e| {
crate::Error::from(crate::ErrorKind::Other(format!("PBF decode error: {}", e)))
})?;
let query_result = pbf.query_result.ok_or_else(|| {
crate::Error::from(crate::ErrorKind::Other(
"Missing query result in PBF".to_string(),
))
})?;
match query_result.results {
Some(query_result::Results::FeatureResult(feature_result)) => {
decode_feature_result(feature_result)
}
Some(query_result::Results::CountResult(count_result)) => {
Ok(FeatureSet::new(
None,
vec![],
Some(count_result.count as u32),
false,
))
}
Some(query_result::Results::IdsResult(object_ids_result)) => {
let features = object_ids_result
.object_ids
.iter()
.map(|&oid| {
let mut attributes = HashMap::new();
attributes.insert(
object_ids_result.object_id_field_name.clone(),
serde_json::Value::Number(serde_json::Number::from(oid)),
);
Feature::new(attributes, None)
})
.collect();
Ok(FeatureSet::new(None, features, None, false))
}
None => Err(crate::Error::from(crate::ErrorKind::Other(
"No result data in query result".to_string(),
))),
}
}
fn decode_feature_result(feature_result: FeatureResult) -> Result<FeatureSet> {
let geometry_type = convert_geometry_type(feature_result.geometry_type)?;
let _values_lookup: Vec<serde_json::Value> = feature_result
.values
.iter()
.map(convert_pbf_value)
.collect();
let features: Vec<Feature> = feature_result
.features
.iter()
.map(|pbf_feature| {
let mut attributes = HashMap::new();
for (idx, field) in feature_result.fields.iter().enumerate() {
if let Some(attr) = pbf_feature.attributes.get(idx) {
let value = if let Some(value_type) = &attr.value_type {
match value_type {
value::ValueType::StringValue(s) => {
serde_json::Value::String(s.clone())
}
value::ValueType::FloatValue(f) => serde_json::Value::Number(
serde_json::Number::from_f64(*f as f64).unwrap(),
),
value::ValueType::DoubleValue(d) => {
serde_json::Value::Number(serde_json::Number::from_f64(*d).unwrap())
}
value::ValueType::SintValue(i) => {
serde_json::Value::Number((*i).into())
}
value::ValueType::UintValue(u) => {
serde_json::Value::Number((*u).into())
}
value::ValueType::Int64Value(i) => {
serde_json::Value::Number((*i).into())
}
value::ValueType::Uint64Value(u) => {
serde_json::Value::Number((*u).into())
}
value::ValueType::Sint64Value(i) => {
serde_json::Value::Number((*i).into())
}
value::ValueType::BoolValue(b) => serde_json::Value::Bool(*b),
}
} else {
serde_json::Value::Null
};
attributes.insert(field.name.clone(), value);
}
}
let geometry = if let Some(compressed_geom) = &pbf_feature.compressed_geometry {
match compressed_geom {
feature::CompressedGeometry::Geometry(geom) => {
match super::geometry::decode_geometry(
geom,
geometry_type,
feature_result.transform.as_ref(),
feature_result.has_z,
feature_result.has_m,
) {
Ok(g) => Some(g),
Err(e) => {
tracing::warn!(error = %e, "Failed to decode geometry, skipping");
None
}
}
}
feature::CompressedGeometry::ShapeBuffer(_) => {
tracing::warn!("ShapeBuffer geometry format not yet supported");
None
}
}
} else {
None
};
Feature::new(attributes, geometry)
})
.collect();
Ok(FeatureSet::new(
Some(geometry_type),
features,
None,
feature_result.exceeded_transfer_limit,
))
}
fn convert_geometry_type(pbf_type: i32) -> Result<GeometryType> {
use GeometryType as GT;
match pbf_type {
0 => Ok(GT::Point),
1 => Ok(GT::Multipoint),
2 => Ok(GT::Polyline),
3 => Ok(GT::Polygon),
4 => Err(crate::Error::from(crate::ErrorKind::Other(
"Multipatch geometry not supported yet".to_string(),
))), 127 => Err(crate::Error::from(crate::ErrorKind::Other(
"Geometry type is None".to_string(),
))),
_ => Err(crate::Error::from(crate::ErrorKind::Other(format!(
"Unknown geometry type: {}",
pbf_type
)))),
}
}
fn convert_pbf_value(pbf_value: &Value) -> serde_json::Value {
if let Some(value_type) = &pbf_value.value_type {
match value_type {
value::ValueType::StringValue(s) => serde_json::Value::String(s.clone()),
value::ValueType::FloatValue(f) => {
serde_json::Value::Number(serde_json::Number::from_f64(*f as f64).unwrap())
}
value::ValueType::DoubleValue(d) => {
serde_json::Value::Number(serde_json::Number::from_f64(*d).unwrap())
}
value::ValueType::SintValue(i) => serde_json::Value::Number((*i).into()),
value::ValueType::UintValue(u) => serde_json::Value::Number((*u).into()),
value::ValueType::Int64Value(i) => serde_json::Value::Number((*i).into()),
value::ValueType::Uint64Value(u) => serde_json::Value::Number((*u).into()),
value::ValueType::Sint64Value(i) => serde_json::Value::Number((*i).into()),
value::ValueType::BoolValue(b) => serde_json::Value::Bool(*b),
}
} else {
serde_json::Value::Null
}
}