use crate::capnp_messages::{read_route, read_shape, write_route, write_shape};
use crate::features_query::{
FeatureRef, FeatureResponseItem, GetFeaturesRequest, GetFeaturesResponse, QueryFeatureKind,
};
use ::capnp::message::Builder;
use ::capnp::serialize;
use std::io::Cursor;
fn query_feature_kind_to_capnp(
kind: QueryFeatureKind,
) -> crate::features_query_capnp::QueryFeatureKind {
match kind {
QueryFeatureKind::Route => crate::features_query_capnp::QueryFeatureKind::Route,
QueryFeatureKind::Shape => crate::features_query_capnp::QueryFeatureKind::Shape,
}
}
fn query_feature_kind_from_capnp(
kind: crate::features_query_capnp::QueryFeatureKind,
) -> QueryFeatureKind {
match kind {
crate::features_query_capnp::QueryFeatureKind::Route => QueryFeatureKind::Route,
crate::features_query_capnp::QueryFeatureKind::Shape => QueryFeatureKind::Shape,
}
}
fn write_feature_ref(
builder: &mut crate::features_query_capnp::feature_ref::Builder,
feature_ref: &FeatureRef,
) {
builder.set_id(&feature_ref.id);
builder.set_kind(query_feature_kind_to_capnp(feature_ref.kind));
}
fn write_feature_response_item(
builder: &mut crate::features_query_capnp::feature_response_item::Builder,
item: &FeatureResponseItem,
) {
match item {
FeatureResponseItem::Route(route) => {
let mut route_builder = builder.reborrow().init_route();
write_route(&mut route_builder, route);
}
FeatureResponseItem::Shape(shape) => {
let mut shape_builder = builder.reborrow().init_shape();
write_shape(&mut shape_builder, shape);
}
}
}
fn read_feature_ref(
reader: crate::features_query_capnp::feature_ref::Reader,
) -> Result<FeatureRef, ::capnp::Error> {
Ok(FeatureRef {
id: reader.get_id()?.to_str()?.to_string(),
kind: query_feature_kind_from_capnp(reader.get_kind()?),
})
}
fn read_feature_response_item(
reader: crate::features_query_capnp::feature_response_item::Reader,
) -> Result<FeatureResponseItem, ::capnp::Error> {
match reader.which()? {
crate::features_query_capnp::feature_response_item::Route(Ok(route_reader)) => {
Ok(FeatureResponseItem::Route(read_route(route_reader)?))
}
crate::features_query_capnp::feature_response_item::Shape(Ok(shape_reader)) => {
Ok(FeatureResponseItem::Shape(read_shape(shape_reader)?))
}
_ => Err(::capnp::Error::failed(
"Invalid feature response item variant".to_string(),
)),
}
}
pub fn serialize_get_features_request(
request: &GetFeaturesRequest,
) -> Result<Vec<u8>, ::capnp::Error> {
let mut message = Builder::new_default();
let mut builder =
message.init_root::<crate::features_query_capnp::get_features_request::Builder>();
let mut refs_builder = builder
.reborrow()
.init_feature_refs(request.feature_refs.len() as u32);
for (i, feature_ref) in request.feature_refs.iter().enumerate() {
let mut ref_builder = refs_builder.reborrow().get(i as u32);
write_feature_ref(&mut ref_builder, feature_ref);
}
let mut buf = Vec::new();
serialize::write_message(&mut buf, &message)?;
Ok(buf)
}
pub fn deserialize_get_features_request(data: &[u8]) -> Result<GetFeaturesRequest, ::capnp::Error> {
let cursor = Cursor::new(data);
let message_reader = serialize::read_message(cursor, ::capnp::message::ReaderOptions::new())?;
let reader =
message_reader.get_root::<crate::features_query_capnp::get_features_request::Reader>()?;
let refs_reader = reader.get_feature_refs()?;
let mut feature_refs = Vec::with_capacity(refs_reader.len() as usize);
for i in 0..refs_reader.len() {
feature_refs.push(read_feature_ref(refs_reader.get(i))?);
}
Ok(GetFeaturesRequest { feature_refs })
}
pub fn serialize_get_features_response(
response: &GetFeaturesResponse,
) -> Result<Vec<u8>, ::capnp::Error> {
let mut message = Builder::new_default();
let mut builder =
message.init_root::<crate::features_query_capnp::get_features_response::Builder>();
let mut items_builder = builder.reborrow().init_items(response.items.len() as u32);
for (i, item) in response.items.iter().enumerate() {
let mut item_builder = items_builder.reborrow().get(i as u32);
write_feature_response_item(&mut item_builder, item);
}
let mut buf = Vec::new();
serialize::write_message(&mut buf, &message)?;
Ok(buf)
}
pub fn deserialize_get_features_response(
data: &[u8],
) -> Result<GetFeaturesResponse, ::capnp::Error> {
let cursor = Cursor::new(data);
let message_reader = serialize::read_message(cursor, ::capnp::message::ReaderOptions::new())?;
let reader =
message_reader.get_root::<crate::features_query_capnp::get_features_response::Reader>()?;
let items_reader = reader.get_items()?;
let mut items = Vec::with_capacity(items_reader.len() as usize);
for i in 0..items_reader.len() {
items.push(read_feature_response_item(items_reader.get(i))?);
}
Ok(GetFeaturesResponse { items })
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core_model::{
AssetIdentity, GeoPoint2, GeoPose, LayerRole, Route, RouteData, ScopeType, Shape, ShapeData,
};
#[test]
fn test_get_features_request_roundtrip() {
let original = GetFeaturesRequest {
feature_refs: vec![
FeatureRef {
id: "Route-123".to_string(),
kind: QueryFeatureKind::Route,
},
FeatureRef {
id: "geom-456".to_string(),
kind: QueryFeatureKind::Shape,
},
],
};
let serialized = serialize_get_features_request(&original).expect("Failed to serialize");
let deserialized =
deserialize_get_features_request(&serialized).expect("Failed to deserialize");
assert_eq!(original, deserialized);
}
#[test]
fn test_get_features_response_roundtrip() {
let original = GetFeaturesResponse {
items: vec![
FeatureResponseItem::Route(Route {
identity: AssetIdentity {
id: "route-123".to_string(),
name: "Test Route".to_string(),
rev: 1,
hash: "abc123".to_string(),
},
data: RouteData::Path(vec![
GeoPose {
lat_deg: 37.7749,
lon_deg: -122.4194,
altitude_m: 10.0,
heading_deg: 45.0,
},
GeoPose {
lat_deg: 37.7750,
lon_deg: -122.4195,
altitude_m: 10.0,
heading_deg: 90.0,
},
]),
area_type: LayerRole::Target,
scope: ScopeType::Fleet,
feature_type: None,
}),
FeatureResponseItem::Shape(Shape {
identity: AssetIdentity {
id: "shape-456".to_string(),
name: "Test Shape".to_string(),
rev: 2,
hash: "def456".to_string(),
},
data: ShapeData::Polygon {
exterior: vec![
GeoPoint2 {
lon: -122.4194,
lat: 37.7749,
},
GeoPoint2 {
lon: -122.4195,
lat: 37.7750,
},
GeoPoint2 {
lon: -122.4196,
lat: 37.7749,
},
],
holes: vec![],
},
area_type: LayerRole::WorkArea,
scope: ScopeType::Fleet,
min_z_m: 0.0,
max_z_m: 100.0,
level_id: 0,
}),
],
};
let serialized = serialize_get_features_response(&original).expect("Failed to serialize");
let deserialized =
deserialize_get_features_response(&serialized).expect("Failed to deserialize");
assert_eq!(original, deserialized);
}
#[test]
fn test_empty_request_roundtrip() {
let original = GetFeaturesRequest {
feature_refs: vec![],
};
let serialized = serialize_get_features_request(&original).expect("Failed to serialize");
let deserialized =
deserialize_get_features_request(&serialized).expect("Failed to deserialize");
assert_eq!(original, deserialized);
}
#[test]
fn test_empty_response_roundtrip() {
let original = GetFeaturesResponse { items: vec![] };
let serialized = serialize_get_features_response(&original).expect("Failed to serialize");
let deserialized =
deserialize_get_features_response(&serialized).expect("Failed to deserialize");
assert_eq!(original, deserialized);
}
}