use martin_core::tiles::Tile;
use martin_tile_utils::{Encoding, Format, TileInfo};
use mlt_core::mvt::tile_layers_to_mvt;
use mlt_core::{Decoder, Layer, Parser};
use crate::srv::tiles::content;
use crate::srv::tiles::process::ProcessError;
pub fn convert_mlt_to_mvt(tile: Tile) -> Result<Tile, ProcessError> {
let mlt =
content::decode(tile).map_err(|e| ProcessError::DecompressionFailed(e.to_string()))?;
let mut parser = Parser::default();
let layers = parser
.parse_layers(&mlt.data)
.map_err(|e| ProcessError::MvtConversion(format!("MLT parse failed: {e}")))?;
let mut decoder = Decoder::default();
let mut tile_layers = Vec::with_capacity(layers.len());
for layer in layers {
if let Layer::Tag01(l) = layer {
tile_layers.push(
l.into_tile(&mut decoder)
.map_err(|e| ProcessError::MvtConversion(format!("MLT decode failed: {e}")))?,
);
}
}
let mvt_bytes =
tile_layers_to_mvt(tile_layers).map_err(|e| ProcessError::MvtConversion(e.to_string()))?;
Ok(Tile::new_hash_etag(
mvt_bytes,
TileInfo::new(Format::Mvt, Encoding::Uncompressed),
))
}
#[cfg(test)]
pub(super) fn mvt_with_feature_bytes() -> Vec<u8> {
use mlt_core::geo_types::{Geometry, Point};
use mlt_core::{PropKind, PropValue, TileLayer};
let mut builder = TileLayer::builder("test", 4096).expect("layer builder");
let name_key = builder
.add_property("name", PropKind::Str)
.expect("add property");
{
let mut feature = builder.feature(Geometry::Point(Point::new(100, 200)));
feature.id(Some(1));
feature
.property(name_key, PropValue::Str(Some("hello".to_string())))
.expect("set property");
feature.finish().expect("finish feature");
}
tile_layers_to_mvt(vec![builder.finish()]).expect("encode test MVT")
}
#[cfg(test)]
pub(super) fn empty_layer_mvt_bytes() -> Vec<u8> {
use mlt_core::TileLayer;
let layer = TileLayer::builder("x", 4096)
.expect("layer builder")
.finish();
tile_layers_to_mvt(vec![layer]).expect("encode empty MVT")
}
#[cfg(test)]
mod tests {
use mlt_core::encoder::EncoderConfig;
use mlt_core::mvt::mvt_to_tile_layers;
use super::*;
fn build_mlt_bytes() -> Vec<u8> {
let mvt = mvt_with_feature_bytes();
let layers = mvt_to_tile_layers(mvt).expect("decode MVT");
let mut mlt_bytes = Vec::new();
for layer in layers {
mlt_bytes.extend(layer.encode(EncoderConfig::default()).expect("encode MLT"));
}
mlt_bytes
}
#[test]
fn round_trips_through_mlt() {
let mlt_bytes = build_mlt_bytes();
let tile = Tile::new_hash_etag(mlt_bytes, TileInfo::new(Format::Mlt, Encoding::Internal));
let result = convert_mlt_to_mvt(tile).expect("MLT->MVT");
assert_eq!(result.info.format, Format::Mvt);
let layers = mvt_to_tile_layers(result.data).expect("decode MVT");
assert_eq!(layers.len(), 1);
assert_eq!(layers[0].name(), "test");
assert_eq!(layers[0].features().len(), 1);
}
#[test]
fn gzip_compressed_mlt_is_decodable() {
use martin_tile_utils::encode_gzip;
let mlt_bytes = build_mlt_bytes();
let gzipped = encode_gzip(&mlt_bytes).expect("gzip MLT");
let tile = Tile::new_hash_etag(gzipped, TileInfo::new(Format::Mlt, Encoding::Gzip));
let result = convert_mlt_to_mvt(tile).expect("MLT->MVT");
assert_eq!(result.info.format, Format::Mvt);
let layers = mvt_to_tile_layers(result.data).expect("decode MVT");
assert_eq!(layers.len(), 1);
}
}