use std::cmp::Reverse;
use std::collections::HashMap;
use integer_encoding::VarIntWriter as _;
use crate::codecs::presence_coding::{self, PresenceCoding};
use crate::decoder::stream::header02::{Count02, Family, StreamCtx02, WordWidth};
use crate::decoder::{
BoolLogical, ColumnCounts, ColumnType02, DataType02, DictionaryType, Extent02, LayerHeader02,
LayerLayout, LengthType, LogicalEncoding, NodeKind02, NodePresence, NodeType02,
PhysicalEncoding, Presence02, StreamMeta, StreamType, ValueType02,
};
use crate::encoder::geometry::encode02::encode_geometry02;
use crate::encoder::model::{StagedLayer, StrAt, StreamCtx};
use crate::encoder::nested::RowShapes;
use crate::encoder::{
Codecs, Encoder, StagedId, StagedInterior, StagedLeaf, StagedMValue, StagedNested, StagedNode,
StagedOptScalar, StagedProperty, StagedSharedDictItem, StagedStrings, StagedValues,
write_stream_payload,
};
use crate::utils::BinarySerializer as _;
use crate::{MltError, MltResult};
#[derive(Debug)]
pub(crate) struct SharedPresence {
masks: Vec<Vec<bool>>,
codings: Vec<PresenceCoding>,
index: HashMap<Vec<bool>, u8>,
}
impl SharedPresence {
fn plan(
id: &StagedId,
properties: &[StagedProperty],
nested: &[StagedNested],
m_values: &[StagedMValue],
) -> Self {
let mut groups: HashMap<Vec<bool>, (usize, usize)> = HashMap::new();
for (column, mask) in column_masks(id, properties, nested, m_values).enumerate() {
let group = groups.entry(mask).or_insert((0, column));
group.0 += 1;
}
let mut shared: Vec<(Vec<bool>, usize, usize)> = groups
.into_iter()
.filter(|&(_, (count, _))| count > 1)
.map(|(mask, (count, first))| (mask, count, first))
.collect();
shared.sort_unstable_by_key(|&(_, count, first)| (Reverse(count), first));
shared.truncate(usize::from(LayerLayout::MAX_SHARED_PRESENCE));
shared.sort_unstable_by_key(|&(_, _, first)| first);
let masks: Vec<Vec<bool>> = shared.into_iter().map(|(mask, _, _)| mask).collect();
let index = masks
.iter()
.enumerate()
.map(|(i, mask)| {
(
mask.clone(),
u8::try_from(i).expect("at most MAX_SHARED_PRESENCE masks"),
)
})
.collect();
let codings = masks.iter().map(|m| presence_coding::smallest(m)).collect();
Self {
masks,
codings,
index,
}
}
fn count(&self) -> u8 {
u8::try_from(self.masks.len()).expect("at most MAX_SHARED_PRESENCE masks")
}
fn coded(&self) -> bool {
self.codings.iter().any(|&c| c != PresenceCoding::Bitmap)
}
pub(crate) fn nibble_for(&self, mask: &[bool]) -> Presence02 {
self.index.get(mask).map_or_else(
|| Presence02::Inline(presence_coding::smallest(mask)),
|&i| Presence02::Shared(i),
)
}
fn write_to(&self, enc: &mut Encoder) {
let coded = self.coded();
let data = enc.data_mut();
for (mask, &coding) in self.masks.iter().zip(&self.codings) {
if coded {
data.push(coding as u8);
}
presence_coding::write(data, mask, coding);
}
}
}
fn column_masks<'a>(
id: &'a StagedId,
properties: &'a [StagedProperty],
nested: &'a [StagedNested],
m_values: &'a [StagedMValue],
) -> impl Iterator<Item = Vec<bool>> + 'a {
fn mask<T: Copy + PartialEq>(v: &StagedOptScalar<T>) -> Vec<bool> {
v.presence.clone()
}
let id = match id {
StagedId::OptU32(v) => Some(mask(v)),
StagedId::OptU64(v) => Some(mask(v)),
StagedId::None | StagedId::U32(_) | StagedId::U64(_) => None,
};
let props = properties.iter().flat_map(|prop| {
use StagedProperty as D;
match prop {
D::OptBool(v) => vec![mask(v)],
D::OptI8(v) => vec![mask(v)],
D::OptU8(v) => vec![mask(v)],
D::OptI32(v) => vec![mask(v)],
D::OptU32(v) => vec![mask(v)],
D::OptI64(v) => vec![mask(v)],
D::OptU64(v) => vec![mask(v)],
D::OptF32(v) => vec![mask(v)],
D::OptF64(v) => vec![mask(v)],
D::OptStr(v) => vec![v.presence_bools().collect()],
D::SharedDict(v) => v
.items
.iter()
.filter_map(StagedSharedDictItem::optional_presence)
.collect(),
D::Bool(_)
| D::I8(_)
| D::U8(_)
| D::I32(_)
| D::U32(_)
| D::I64(_)
| D::U64(_)
| D::F32(_)
| D::F64(_)
| D::Str(_) => vec![],
}
});
let nested = nested.iter().filter_map(|n| n.presence().cloned());
let m_values = m_values.iter().filter_map(|m| m.presence.clone());
id.into_iter().chain(props).chain(nested).chain(m_values)
}
pub(crate) fn write_inline_presence(data: &mut Vec<u8>, nibble: Presence02, bits: &[bool]) {
if let Presence02::Inline(coding) = nibble {
presence_coding::write(data, bits, coding);
}
}
pub(crate) fn write_presence_bits(data: &mut Vec<u8>, bits: &[bool]) {
let start = data.len();
data.resize(start + bits.len().div_ceil(8), 0);
for (i, &bit) in bits.iter().enumerate() {
if bit {
data[start + i / 8] |= 1 << (i % 8);
}
}
}
pub(crate) fn encode_into02(
layer: StagedLayer,
mut enc: Encoder,
codecs: &mut Codecs,
) -> MltResult<Encoder> {
let StagedLayer {
name,
extent,
id,
geometry,
properties,
m_values,
nested,
} = layer;
let extent = Extent02::new(extent.get())?;
let feature_count = u32::try_from(geometry.feature_count())?;
enc.count_context = Count02::Implied(feature_count);
let shared = SharedPresence::plan(&id, &properties, &nested, &m_values);
let geometry = encode_geometry02(geometry)?;
let layout_pos = enc.data().len();
enc.data_mut().push(0);
shared.write_to(&mut enc);
let geo = geometry.write_to(&mut enc, codecs)?;
if !m_values.is_empty() && !geo.layout.allows_m_values() {
return Err(MltError::MValuesNeedVertexCounts(geo.layout.into()));
}
enc.data_mut()[layout_pos] =
LayerLayout::new(geo.layout, shared.count(), shared.coded()).to_byte();
let column_count = usize::from(!matches!(id, StagedId::None)) + properties.len() + nested.len();
let counts = ColumnCounts {
columns: u32::try_from(column_count)?,
m_values: u32::try_from(m_values.len())?,
};
enc.data_mut().write_varint(counts.to_varint())?;
write_id02(&id, &shared, &mut enc, codecs)?;
for prop in &properties {
write_prop02(prop, &shared, &mut enc, codecs)?;
}
for column in &nested {
write_nested02(column, &shared, &mut enc, codecs)?;
}
for m_value in &m_values {
write_m_value02(m_value, &shared, &mut enc, codecs)?;
}
let header = LayerHeader02::new(extent, geo.uniform_type, !m_values.is_empty());
enc.write_header02(&name, header, feature_count)?;
Ok(enc)
}
fn begin_col02(
enc: &mut Encoder,
presence: Presence02,
typ: DataType02,
name: Option<&str>,
) -> MltResult<()> {
enc.family_context = StreamCtx02::Property(typ).family();
let data = enc.data_mut();
data.push(ColumnType02::new(presence, typ).to_byte());
debug_assert_eq!(typ.has_name(), name.is_some());
if let Some(name) = name {
data.write_string(name)?;
}
Ok(())
}
fn write_opt_col02<F>(
enc: &mut Encoder,
shared: &SharedPresence,
typ: DataType02,
name: Option<&str>,
presence: &[bool],
write_data: F,
) -> MltResult<()>
where
F: FnOnce(&mut Encoder) -> MltResult<()>,
{
let nibble = shared.nibble_for(presence);
begin_col02(enc, nibble, typ, name)?;
write_inline_presence(enc.data_mut(), nibble, presence);
let popcount = u32::try_from(presence.iter().filter(|&&p| p).count())?;
let feature_count = enc.count_context;
enc.count_context = Count02::Implied(popcount);
let result = write_data(enc);
enc.count_context = feature_count;
result
}
fn write_bool_bitfield(enc: &mut Encoder, values: &[bool]) -> MltResult<()> {
write_bool_stream02(enc, values, StreamType::Data(DictionaryType::None))
}
fn write_bool_stream02(
enc: &mut Encoder,
values: &[bool],
stream_type: StreamType,
) -> MltResult<()> {
let mut packed = Vec::with_capacity(values.len().div_ceil(8));
write_presence_bits(&mut packed, values);
let meta = StreamMeta::new2(
stream_type,
LogicalEncoding::Bool(BoolLogical::None),
PhysicalEncoding::None,
values.len(),
)?;
enc.family_context = Family::Bool;
write_stream_payload(enc, meta, false, &packed)
}
fn write_id02(
id: &StagedId,
shared: &SharedPresence,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
use DataType02 as DT;
use Presence02::AllPresent;
let ctx = StreamCtx::id(StreamType::Data(DictionaryType::None));
match id {
StagedId::None => Ok(()),
StagedId::U32(v) => {
begin_col02(enc, AllPresent, DT::Id, None)?;
codecs.write_int_stream(&v.values, &ctx, enc)
}
StagedId::OptU32(v) => write_opt_col02(enc, shared, DT::Id, None, &v.presence, |enc| {
codecs.write_int_stream(&v.values, &ctx, enc)
}),
StagedId::U64(v) => {
begin_col02(enc, AllPresent, DT::LongId, None)?;
codecs.write_int_stream(&v.values, &ctx, enc)
}
StagedId::OptU64(v) => write_opt_col02(enc, shared, DT::LongId, None, &v.presence, |enc| {
codecs.write_int_stream(&v.values, &ctx, enc)
}),
}
}
fn write_prop02(
prop: &StagedProperty,
shared: &SharedPresence,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
use DataType02 as DT;
use Presence02::AllPresent;
use StagedProperty as D;
macro_rules! scalar {
($ct:ident, $v:expr) => {{
begin_col02(enc, AllPresent, DT::$ct, Some(&$v.name))?;
codecs.write_int_stream(&$v.values, &StreamCtx::prop_data(&$v.name), enc)
}};
}
macro_rules! opt_scalar {
($ct:ident, $v:expr) => {{
write_opt_col02(enc, shared, DT::$ct, Some(&$v.name), &$v.presence, |enc| {
codecs.write_int_stream(&$v.values, &StreamCtx::prop_data(&$v.name), enc)
})
}};
}
macro_rules! opt_float {
($ct:ident, $v:expr) => {{
write_opt_col02(enc, shared, DT::$ct, Some(&$v.name), &$v.presence, |enc| {
codecs.write_float_stream(&$v.values, &StreamCtx::prop_data(&$v.name), enc)
})
}};
}
match prop {
D::Bool(v) => {
begin_col02(enc, AllPresent, DT::Bool, Some(&v.name))?;
write_bool_bitfield(enc, &v.values)
}
D::OptBool(v) => {
write_opt_col02(enc, shared, DT::Bool, Some(&v.name), &v.presence, |enc| {
write_bool_bitfield(enc, &v.values)
})
}
D::F32(v) => {
begin_col02(enc, AllPresent, DT::F32, Some(&v.name))?;
codecs.write_float_stream(&v.values, &StreamCtx::prop_data(&v.name), enc)
}
D::OptF32(v) => opt_float!(F32, v),
D::F64(v) => {
begin_col02(enc, AllPresent, DT::F64, Some(&v.name))?;
codecs.write_float_stream(&v.values, &StreamCtx::prop_data(&v.name), enc)
}
D::OptF64(v) => opt_float!(F64, v),
D::I8(v) => scalar!(I8, v),
D::OptI8(v) => opt_scalar!(I8, v),
D::U8(v) => scalar!(U8, v),
D::OptU8(v) => opt_scalar!(U8, v),
D::I32(v) => scalar!(I32, v),
D::OptI32(v) => opt_scalar!(I32, v),
D::U32(v) => scalar!(U32, v),
D::OptU32(v) => opt_scalar!(U32, v),
D::I64(v) => scalar!(I64, v),
D::OptI64(v) => opt_scalar!(I64, v),
D::U64(v) => scalar!(U64, v),
D::OptU64(v) => opt_scalar!(U64, v),
D::Str(v) => {
begin_col02(enc, AllPresent, DT::Str, Some(&v.name))?;
codecs.write_str_col02(v, StrAt::flat(&v.name), enc)
}
D::OptStr(v) => {
let presence: Vec<bool> = v.presence_bools().collect();
write_opt_col02(enc, shared, DT::Str, Some(&v.name), &presence, |enc| {
codecs.write_str_col02(v, StrAt::flat(&v.name), enc)
})
}
D::SharedDict(v) => codecs.write_shared_dict02(v, shared, enc),
}
}
macro_rules! impl_m_value_type02 {
(
scalar { $($sv:ident),* $(,)? }
string { $($gv:ident),* $(,)? }
) => {
fn m_value_type02(values: &StagedValues) -> DataType02 {
match values {
$(StagedValues::$sv(_) => DataType02::$sv,)*
$(StagedValues::$gv(_) => DataType02::$gv,)*
}
}
};
}
with_kinds!(impl_m_value_type02);
fn write_m_value02(
m_value: &StagedMValue,
shared: &SharedPresence,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
use StagedValues as V;
let name = m_value.name();
let typ = m_value_type02(m_value.values());
let nibble = match &m_value.presence {
Some(mask) => shared.nibble_for(mask),
None => Presence02::AllPresent,
};
begin_col02(enc, nibble, typ, Some(name))?;
if let Some(mask) = &m_value.presence {
write_inline_presence(enc.data_mut(), nibble, mask);
}
let features = enc.count_context;
enc.count_context = Count02::Explicit;
let ctx = StreamCtx::prop_data(name);
let result = match m_value.values() {
V::Bool(v) => write_bool_bitfield(enc, v),
V::I8(v) => codecs.write_int_stream(v, &ctx, enc),
V::U8(v) => codecs.write_int_stream(v, &ctx, enc),
V::I32(v) => codecs.write_int_stream(v, &ctx, enc),
V::U32(v) => codecs.write_int_stream(v, &ctx, enc),
V::I64(v) => codecs.write_int_stream(v, &ctx, enc),
V::U64(v) => codecs.write_int_stream(v, &ctx, enc),
V::F32(v) => codecs.write_float_stream(v, &ctx, enc),
V::F64(v) => codecs.write_float_stream(v, &ctx, enc),
V::Str(v) => codecs.write_str_col02(&m_value.strings(v), StrAt::flat(name), enc),
};
enc.count_context = features;
result
}
macro_rules! impl_value_type02 {
(
scalar { $($sv:ident),* $(,)? }
string { $($gv:ident),* $(,)? }
) => {
fn value_type02(values: &StagedValues) -> ValueType02 {
match values {
$(StagedValues::$sv(_) => ValueType02::$sv,)*
$(StagedValues::$gv(_) => ValueType02::$gv,)*
}
}
};
}
with_kinds!(impl_value_type02);
fn write_nested02(
column: &StagedNested,
shared: &SharedPresence,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
let name = column.name();
let as_map = column.root.as_map();
let mut roots = Vec::new();
for root in std::iter::once(&column.root).chain(as_map.iter()) {
roots.push((root, Axis::PerEntry));
if per_row_allowed(root, enc) {
roots.push((root, Axis::PerRow));
}
}
if let [(root, axis)] = roots[..] {
return write_nested_root02(name, root, axis, shared, enc, codecs);
}
let mut alt = enc.try_alternatives();
for (root, axis) in roots {
alt.with(|enc| write_nested_root02(name, root, axis, shared, enc, codecs))?;
}
Ok(())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Axis {
PerEntry,
PerRow,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Coding {
axis: Axis,
owner: Presence,
}
impl Coding {
const PER_ENTRY: Self = Self {
axis: Axis::PerEntry,
owner: Presence::Own,
};
#[must_use]
fn with_axis(self, axis: Axis) -> Self {
Self { axis, ..self }
}
#[must_use]
fn owned_by(self, owner: Presence) -> Self {
Self { owner, ..self }
}
}
fn per_row_allowed(interior: &StagedInterior, enc: &Encoder) -> bool {
enc.config().allow_row_shapes() && interior.row_shapes().is_some()
}
fn write_shapes02(
shapes: &RowShapes,
column: &str,
path: &str,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
let outer = enc.count_context;
enc.count_context = Count02::Explicit;
write_bool_stream02(enc, &shapes.table_bits(), StreamType::Present)?;
enc.family_context = Family::Int(WordWidth::W32);
let ctx = StreamCtx::prop2(StreamType::Data(DictionaryType::None), column, path);
let result = codecs.write_int_stream(&shapes.ids, &ctx, enc);
enc.count_context = outer;
result
}
fn write_nested_root02(
name: &str,
root: &StagedInterior,
axis: Axis,
shared: &SharedPresence,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
let presence = root.presence();
let nibble = presence.map_or(Presence02::AllPresent, |mask| shared.nibble_for(mask));
begin_col02(enc, nibble, interior_type02(root), Some(name))?;
if let Some(mask) = presence {
write_inline_presence(enc.data_mut(), nibble, mask);
}
if axis == Axis::PerRow {
enc.data_mut().push(NodePresence::SHAPES);
}
let outer = enc.count_context;
let values = match presence {
Some(mask) => u32::try_from(mask.iter().filter(|&&bit| bit).count())?,
None => match outer {
Count02::Implied(count) => count,
Count02::Explicit => u32::try_from(root.parent_count())?,
},
};
enc.count_context = body_context02(root, Count02::Implied(values));
let result = write_interior02(root, name, "", axis, enc, codecs);
enc.count_context = outer;
result
}
fn body_context02(interior: &StagedInterior, present: Count02) -> Count02 {
match interior {
StagedInterior::Struct(_) => present,
StagedInterior::List(_) | StagedInterior::Map(_) => Count02::Explicit,
}
}
fn interior_type02(interior: &StagedInterior) -> DataType02 {
match interior {
StagedInterior::Struct(_) => DataType02::Struct,
StagedInterior::List(_) => DataType02::List,
StagedInterior::Map(_) => DataType02::Map,
}
}
fn node_kind02(node: &StagedNode) -> NodeKind02 {
match node {
StagedNode::Interior(StagedInterior::Struct(_)) => NodeKind02::Struct,
StagedNode::Interior(StagedInterior::List(_)) => NodeKind02::List,
StagedNode::Interior(StagedInterior::Map(_)) => NodeKind02::Map,
StagedNode::Leaf(leaf) => NodeKind02::Leaf(value_type02(&leaf.values)),
}
}
fn write_node02(
node: &StagedNode,
column: &str,
path: &str,
field: Option<&str>,
coding: Coding,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
let as_map = match node {
StagedNode::Interior(interior) => interior.as_map().map(StagedNode::Interior),
StagedNode::Leaf(_) => None,
};
let mut nodes = Vec::new();
for candidate in std::iter::once(node).chain(as_map.iter()) {
nodes.push((candidate, coding));
if let StagedNode::Interior(interior) = candidate
&& per_row_allowed(interior, enc)
{
nodes.push((candidate, coding.with_axis(Axis::PerRow)));
}
}
if let [(node, coding)] = nodes[..] {
return write_node_shape02(node, column, path, field, coding, enc, codecs);
}
let mut alt = enc.try_alternatives();
for (node, coding) in nodes {
alt.with(|enc| write_node_shape02(node, column, path, field, coding, enc, codecs))?;
}
Ok(())
}
fn write_node_shape02(
node: &StagedNode,
column: &str,
path: &str,
field: Option<&str>,
coding: Coding,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
let presence = match (coding.owner, node) {
(Presence::Parent, _) => None,
(Presence::Own, StagedNode::Interior(interior)) => interior.presence(),
(Presence::Own, StagedNode::Leaf(leaf)) => leaf.presence.as_ref(),
};
let node_presence = if presence.is_some() {
NodePresence::Stream
} else {
NodePresence::AllPresent
};
let kind = node_kind02(node);
let typ = NodeType02::new(node_presence, kind);
let typ = match coding.axis {
Axis::PerRow => typ.shaped(),
Axis::PerEntry => typ,
};
enc.data_mut().push(typ.to_byte());
if let Some(field) = field {
enc.data_mut().write_string(field)?;
}
let parent = enc.count_context;
let node_count = match kind {
NodeKind02::List | NodeKind02::Map => Count02::Explicit,
NodeKind02::Struct | NodeKind02::Leaf(_) => parent,
};
if let Some(mask) = presence {
enc.count_context = node_count;
write_bool_stream02(enc, mask, StreamType::Present)?;
}
enc.count_context = match node_count {
Count02::Explicit => Count02::Explicit,
Count02::Implied(_) => Count02::Implied(u32::try_from(node.present_count())?),
};
let result = match node {
StagedNode::Interior(interior) => {
enc.count_context = body_context02(interior, enc.count_context);
write_interior02(interior, column, path, coding.axis, enc, codecs)
}
StagedNode::Leaf(leaf) => write_leaf02(leaf, column, path, enc, codecs),
};
enc.count_context = parent;
result
}
fn write_interior02(
interior: &StagedInterior,
column: &str,
path: &str,
axis: Axis,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
let shapes = match axis {
Axis::PerRow => interior.row_shapes(),
Axis::PerEntry => None,
};
match interior {
StagedInterior::Struct(node) => {
if node.fields.is_empty() {
return Err(MltError::EmptyStructNode);
}
enc.data_mut()
.write_varint(u32::try_from(node.fields.len())?)?;
let fields = enc.count_context;
let owner = match &shapes {
Some(shapes) => {
write_shapes02(shapes, column, path, enc, codecs)?;
Presence::Parent
}
None => Presence::Own,
};
for (name, field) in &node.fields {
enc.count_context = fields;
let path = format!("{path}.{name}");
let coding = Coding::PER_ENTRY.owned_by(owner);
write_node02(field, column, &path, Some(name), coding, enc, codecs)?;
}
enc.count_context = fields;
Ok(())
}
StagedInterior::List(node) => {
write_lengths02(&node.lengths, column, path, enc, codecs)?;
write_node02(
&node.element,
column,
&format!("{path}[]"),
None,
Coding::PER_ENTRY,
enc,
codecs,
)
}
StagedInterior::Map(node) => {
if let Some(shapes) = &shapes {
let keys = StagedStrings::from_strings(column, &shapes.keys);
codecs.write_str_col02(&keys, StrAt::nested(column, path), enc)?;
write_shapes02(shapes, column, path, enc, codecs)?;
} else {
write_lengths02(&node.lengths, column, path, enc, codecs)?;
let keys = StagedStrings::from_strings(column, &node.keys);
codecs.write_str_col02(&keys, StrAt::nested(column, path), enc)?;
}
write_node02(
&node.value,
column,
&format!("{path}{{}}"),
None,
Coding::PER_ENTRY,
enc,
codecs,
)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Presence {
Own,
Parent,
}
fn write_lengths02(
lengths: &[u32],
column: &str,
path: &str,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
enc.family_context = Family::Int(WordWidth::W32);
let ctx = StreamCtx::prop2(StreamType::Length(LengthType::Nested), column, path);
codecs.write_int_stream(lengths, &ctx, enc)
}
fn write_leaf02(
leaf: &StagedLeaf,
column: &str,
path: &str,
enc: &mut Encoder,
codecs: &mut Codecs,
) -> MltResult<()> {
use StagedValues as V;
let ctx = StreamCtx::prop2(StreamType::Data(DictionaryType::None), column, path);
enc.family_context = StreamCtx02::Property(value_type02(&leaf.values).into()).family();
match &leaf.values {
V::Bool(v) => write_bool_bitfield(enc, v),
V::I8(v) => codecs.write_int_stream(v, &ctx, enc),
V::U8(v) => codecs.write_int_stream(v, &ctx, enc),
V::I32(v) => codecs.write_int_stream(v, &ctx, enc),
V::U32(v) => codecs.write_int_stream(v, &ctx, enc),
V::I64(v) => codecs.write_int_stream(v, &ctx, enc),
V::U64(v) => codecs.write_int_stream(v, &ctx, enc),
V::F32(v) => codecs.write_float_stream(v, &ctx, enc),
V::F64(v) => codecs.write_float_stream(v, &ctx, enc),
V::Str(v) => codecs.write_str_col02(
&StagedStrings::from_strings(column, v),
StrAt::nested(column, path),
enc,
),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::decoder::GeometryValues;
use crate::encoder::{EncoderConfig, StagedStruct, WireVersion};
use crate::geo_types::{Geometry, Point};
fn points(count: usize) -> GeometryValues {
let mut geometry = GeometryValues::default();
for _ in 0..count {
geometry.push_geom(&Geometry::<i32>::Point(Point::new(0, 0)));
}
geometry
}
fn str_leaf(presence: Option<Vec<bool>>, values: &[&str]) -> StagedNode {
let values = values.iter().map(|v| (*v).to_string()).collect();
StagedNode::Leaf(StagedLeaf::new(presence, StagedValues::Str(values)))
}
fn encode_one_field(inner: StagedNode, rows: usize) -> Vec<u8> {
let root = StagedInterior::Struct(StagedStruct::new(None, vec![("inner", inner)]));
StagedLayer::with_nested(
"layer",
4096,
StagedId::None,
points(rows),
Vec::new(),
Vec::new(),
vec![StagedNested::new("n", root)],
)
.expect("staged layer")
.encode_into(
Encoder::new(EncoderConfig::default().with_wire_version(WireVersion::V02)),
&mut Codecs::default(),
)
.expect("encode")
.into_layer_bytes()
.expect("layer bytes")
}
fn field_type_byte(bytes: &[u8], field: &str) -> u8 {
let mut name = vec![u8::try_from(field.len()).expect("a short name")];
name.extend_from_slice(field.as_bytes());
let at = bytes
.windows(name.len())
.position(|window| window == name.as_slice())
.expect("the field name");
bytes[at - 1]
}
#[test]
fn an_interior_struct_of_sparse_keys_is_written_as_a_map() {
let rows = 12;
let fields: Vec<(String, StagedNode)> = (0..rows)
.map(|row| {
let mut presence = vec![false; rows];
presence[row] = true;
(format!("key{row}"), str_leaf(Some(presence), &["v"]))
})
.collect();
let inner = StagedNode::Interior(StagedInterior::Struct(StagedStruct::new(None, fields)));
assert_eq!(
field_type_byte(&encode_one_field(inner, rows), "inner"),
NodeType02::new(NodePresence::AllPresent, NodeKind02::Map).to_byte()
);
}
#[test]
fn an_interior_struct_of_dense_keys_stays_a_struct() {
let rows = 12;
let inner = StagedNode::Interior(StagedInterior::Struct(StagedStruct::new(
None,
vec![
("alpha", str_leaf(None, &["a"; 12])),
("beta", str_leaf(None, &["b"; 12])),
],
)));
assert_eq!(
field_type_byte(&encode_one_field(inner, rows), "inner"),
NodeType02::new(NodePresence::AllPresent, NodeKind02::Struct).to_byte()
);
}
}