use std::io;
use std::io::Write;
use num_enum::TryFromPrimitive;
use crate::MltError::ParsingColumnType;
use crate::decoder::{Geometry, GeometryValues, Id, ParsedProperty, Property};
use crate::tile::Extent;
use crate::utils::{BinarySerializer as _, parse_string, parse_u8};
use crate::{DecodeState, Lazy, MltRefResult, Parsed, Parser};
pub(crate) const OPTIONAL_FLAG: u8 = 0b0000_0001;
pub(crate) const BASE_TYPE_MASK: u8 = 0b1111_1110;
#[derive(Debug, Clone)]
pub struct Layer01<'a, S: DecodeState = Lazy> {
pub(crate) name: &'a str,
pub(crate) extent: Extent,
pub(crate) id: Option<Id<'a, S>>,
pub(crate) geometry: Geometry<'a, S>,
pub(crate) properties: Vec<Property<'a, S>>,
#[cfg(fuzzing)]
pub(crate) layer_order: Vec<crate::decoder::fuzzing::LayerOrdering>,
}
pub type ParsedLayer01<'a> = Layer01<'a, Parsed>;
impl<'a, S: DecodeState> Layer01<'a, S> {
#[must_use]
pub fn name(&self) -> &'a str {
self.name
}
#[must_use]
pub fn extent(&self) -> Extent {
self.extent
}
}
impl ParsedLayer01<'_> {
#[must_use]
pub fn geometry_values(&self) -> &GeometryValues {
&self.geometry
}
#[must_use]
pub fn feature_count(&self) -> usize {
self.geometry.vector_types.len()
}
#[must_use]
pub fn properties(&self) -> &[ParsedProperty<'_>] {
&self.properties
}
}
#[derive(Debug, PartialEq)]
pub struct Column<'a> {
pub(crate) typ: ColumnType,
pub(crate) name: Option<&'a str>,
pub(crate) children: Vec<Self>,
}
#[derive(Debug, Clone, Copy, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum ColumnType {
Id = 0b0000_0000,
OptId = 0b0000_0001,
LongId = 0b0000_0010,
OptLongId = 0b0000_0011,
Geometry = 0b0000_0100,
Bool = 0b0000_1010,
OptBool = 0b0000_1011,
I32 = 0b0001_0000,
OptI32 = 0b0001_0001,
U32 = 0b0001_0010,
OptU32 = 0b0001_0011,
I64 = 0b0001_0100,
OptI64 = 0b0001_0101,
U64 = 0b0001_0110,
OptU64 = 0b0001_0111,
F32 = 0b0001_1000,
OptF32 = 0b0001_1001,
F64 = 0b0001_1010,
OptF64 = 0b0001_1011,
Str = 0b0001_1100,
OptStr = 0b0001_1101,
SharedDict = 0b0001_1110,
}
impl Column<'_> {
pub(crate) fn from_bytes<'a>(
input: &'a [u8],
_parser: &mut Parser,
) -> MltRefResult<'a, Column<'a>> {
let (mut input, typ) = ColumnType::from_bytes(input)?;
let name = if typ.has_name() {
let pair = parse_string(input)?;
input = pair.0;
Some(pair.1)
} else {
None
};
Ok((
input,
Column {
typ,
name,
children: Vec::new(),
},
))
}
}
impl ColumnType {
pub(crate) fn from_bytes(input: &[u8]) -> MltRefResult<'_, Self> {
let (input, value) = parse_u8(input)?;
let value = Self::try_from(value).or(Err(ParsingColumnType(value)))?;
Ok((input, value))
}
pub(crate) fn write_to<W: Write>(self, writer: &mut W) -> io::Result<()> {
writer.write_u8(self as u8)?;
Ok(())
}
#[must_use]
pub(crate) fn has_name(self) -> bool {
!matches!(
self,
Self::Id | Self::OptId | Self::LongId | Self::OptLongId | Self::Geometry
)
}
#[must_use]
pub(crate) fn is_optional(self) -> bool {
(self as u8) & OPTIONAL_FLAG != 0
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::ColumnType;
use crate::MltError;
#[rstest]
fn column_type_rejects_unassigned(#[values(5, 6, 7, 8, 9, 12, 13, 14, 15, 31)] byte: u8) {
let err = ColumnType::from_bytes(&[byte]).unwrap_err();
assert!(matches!(err, MltError::ParsingColumnType(b) if b == byte));
}
}