use crate::decoder::{Layer01, ParsedLayer01, ParsedProperty, PropValueRef};
use crate::errors::AsMltError as _;
use crate::tile::{PropValue, TileFeature, TileLayer};
use crate::{Decoder, LendingIterator, MltResult};
impl ParsedLayer01<'_> {
pub fn into_tile(self, dec: &mut Decoder) -> MltResult<TileLayer> {
let name = self.name().to_string();
let extent = self.extent().get();
let names: Vec<String> = self.iterate_prop_names().map(|n| n.to_string()).collect();
let col_nulls = typed_nulls(&self.properties);
let mut features = dec.alloc::<TileFeature>(self.feature_count())?;
let mut feat_iter = self.iter_features();
while let Some(feat) = feat_iter.next() {
let feat = feat?;
let mut values = dec.alloc::<PropValue>(names.len())?;
for (col_idx, value) in feat.iter_all_properties().enumerate() {
values.push(match value {
Some(v) => prop_value_from_ref(v),
None => col_nulls[col_idx].clone(),
});
}
charge_str_props(dec, &values)?;
features.push(TileFeature {
id: feat.id(),
geometry: feat.geometry().clone(),
properties: values,
});
}
TileLayer::from_parts(name, extent, names, features)
}
}
impl Layer01<'_> {
pub fn into_tile(self, dec: &mut Decoder) -> MltResult<TileLayer> {
self.decode_all(dec)?.into_tile(dec)
}
}
fn prop_value_from_ref(value: PropValueRef<'_>) -> PropValue {
match value {
PropValueRef::Bool(v) => PropValue::Bool(Some(v)),
PropValueRef::I8(v) => PropValue::I8(Some(v)),
PropValueRef::U8(v) => PropValue::U8(Some(v)),
PropValueRef::I32(v) => PropValue::I32(Some(v)),
PropValueRef::U32(v) => PropValue::U32(Some(v)),
PropValueRef::I64(v) => PropValue::I64(Some(v)),
PropValueRef::U64(v) => PropValue::U64(Some(v)),
PropValueRef::F32(v) => PropValue::F32(Some(v)),
PropValueRef::F64(v) => PropValue::F64(Some(v)),
PropValueRef::Str(s) => PropValue::Str(Some(s.to_string())),
}
}
fn typed_nulls(properties: &[ParsedProperty<'_>]) -> Vec<PropValue> {
use ParsedProperty as PP;
use PropValue as PV;
let mut nulls = Vec::new();
for prop in properties {
match prop {
PP::Bool(_) => nulls.push(PV::Bool(None)),
PP::I8(_) => nulls.push(PV::I8(None)),
PP::U8(_) => nulls.push(PV::U8(None)),
PP::I32(_) => nulls.push(PV::I32(None)),
PP::U32(_) => nulls.push(PV::U32(None)),
PP::I64(_) => nulls.push(PV::I64(None)),
PP::U64(_) => nulls.push(PV::U64(None)),
PP::F32(_) => nulls.push(PV::F32(None)),
PP::F64(_) => nulls.push(PV::F64(None)),
PP::Str(_) => nulls.push(PV::Str(None)),
PP::SharedDict(d) => {
for _ in &d.items {
nulls.push(PV::Str(None));
}
}
}
}
nulls
}
fn charge_str_props(dec: &mut Decoder, props: &[PropValue]) -> MltResult<()> {
let str_bytes = props
.iter()
.filter_map(|p| {
if let PropValue::Str(Some(s)) = p {
Some(s.len())
} else {
None
}
})
.try_fold(0u32, |acc, n| {
acc.checked_add(u32::try_from(n).or_overflow()?)
.or_overflow()
})?;
if str_bytes > 0 {
dec.consume(str_bytes)?;
}
Ok(())
}