use std::fmt::Debug;
use std::fmt::Formatter;
use std::sync::Arc;
use flatbuffers::Follow;
use itertools::Itertools;
use vortex_array::dtype::DType;
use vortex_error::VortexResult;
use vortex_error::vortex_bail;
use vortex_error::vortex_err;
use vortex_flatbuffers::FlatBuffer;
use vortex_flatbuffers::layout as fbl;
use vortex_session::registry::ReadContext;
use crate::LayoutRef;
use crate::segments::SegmentId;
use crate::session::LayoutRegistry;
pub trait LayoutChildren: 'static + Send + Sync {
fn to_arc(&self) -> Arc<dyn LayoutChildren>;
fn child(&self, idx: usize, dtype: &DType) -> VortexResult<LayoutRef>;
fn child_row_count(&self, idx: usize) -> u64;
fn nchildren(&self) -> usize;
}
impl Debug for dyn LayoutChildren {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LayoutChildren")
.field("nchildren", &self.nchildren())
.finish()
}
}
impl LayoutChildren for Arc<dyn LayoutChildren> {
fn to_arc(&self) -> Arc<dyn LayoutChildren> {
Arc::clone(self)
}
fn child(&self, idx: usize, dtype: &DType) -> VortexResult<LayoutRef> {
self.as_ref().child(idx, dtype)
}
fn child_row_count(&self, idx: usize) -> u64 {
self.as_ref().child_row_count(idx)
}
fn nchildren(&self) -> usize {
self.as_ref().nchildren()
}
}
#[derive(Clone)]
pub(crate) struct OwnedLayoutChildren(Vec<LayoutRef>);
impl OwnedLayoutChildren {
pub fn layout_children(children: Vec<LayoutRef>) -> Arc<dyn LayoutChildren> {
Arc::new(Self(children))
}
}
impl LayoutChildren for OwnedLayoutChildren {
fn to_arc(&self) -> Arc<dyn LayoutChildren> {
Arc::new(self.clone())
}
fn child(&self, idx: usize, dtype: &DType) -> VortexResult<LayoutRef> {
if idx >= self.0.len() {
vortex_bail!("Child index out of bounds: {} of {}", idx, self.0.len());
}
let child = &self.0[idx];
if child.dtype() != dtype {
vortex_bail!("Child dtype mismatch: {} != {}", child.dtype(), dtype);
}
Ok(Arc::clone(child))
}
fn child_row_count(&self, idx: usize) -> u64 {
self.0[idx].row_count()
}
fn nchildren(&self) -> usize {
self.0.len()
}
}
#[derive(Clone)]
pub(crate) struct ViewedLayoutChildren {
flatbuffer: FlatBuffer,
flatbuffer_loc: usize,
array_read_ctx: ReadContext,
layout_read_ctx: ReadContext,
layouts: LayoutRegistry,
allow_unknown: bool,
}
impl ViewedLayoutChildren {
pub(super) unsafe fn new_unchecked(
flatbuffer: FlatBuffer,
flatbuffer_loc: usize,
array_read_ctx: ReadContext,
layout_read_ctx: ReadContext,
layouts: LayoutRegistry,
allow_unknown: bool,
) -> Self {
Self {
flatbuffer,
flatbuffer_loc,
array_read_ctx,
layout_read_ctx,
layouts,
allow_unknown,
}
}
fn flatbuffer(&self) -> fbl::Layout<'_> {
unsafe { fbl::Layout::follow(self.flatbuffer.as_ref(), self.flatbuffer_loc) }
}
fn foreign_layout_from_fb(
&self,
fb_layout: fbl::Layout<'_>,
dtype: &DType,
) -> VortexResult<LayoutRef> {
let encoding_id = self
.layout_read_ctx
.resolve(fb_layout.encoding())
.ok_or_else(|| vortex_err!("Encoding not found: {}", fb_layout.encoding()))?;
let children = fb_layout
.children()
.unwrap_or_default()
.iter()
.map(|child| self.foreign_layout_from_fb(child, dtype))
.collect::<VortexResult<Vec<_>>>()?;
Ok(crate::layouts::foreign::new_foreign_layout(
encoding_id,
dtype.clone(),
fb_layout.row_count(),
fb_layout
.metadata()
.map(|m| m.bytes().to_vec())
.unwrap_or_default(),
fb_layout
.segments()
.unwrap_or_default()
.iter()
.map(SegmentId::from)
.collect_vec(),
children,
))
}
}
impl LayoutChildren for ViewedLayoutChildren {
fn to_arc(&self) -> Arc<dyn LayoutChildren> {
Arc::new(self.clone())
}
fn child(&self, idx: usize, dtype: &DType) -> VortexResult<LayoutRef> {
if idx >= self.nchildren() {
vortex_bail!("Child index out of bounds: {} of {}", idx, self.nchildren());
}
let fb_child = self.flatbuffer().children().unwrap_or_default().get(idx);
let viewed_children = ViewedLayoutChildren {
flatbuffer: self.flatbuffer.clone(),
flatbuffer_loc: fb_child._tab.loc(),
array_read_ctx: self.array_read_ctx.clone(),
layout_read_ctx: self.layout_read_ctx.clone(),
layouts: self.layouts.clone(),
allow_unknown: self.allow_unknown,
};
let encoding_id = self
.layout_read_ctx
.resolve(fb_child.encoding())
.ok_or_else(|| vortex_err!("Encoding not found: {}", fb_child.encoding()))?;
let Some(encoding) = self.layouts.find(&encoding_id) else {
if self.allow_unknown {
return viewed_children.foreign_layout_from_fb(fb_child, dtype);
}
return Err(vortex_err!(
"Encoding not found in registry: {}",
fb_child.encoding()
));
};
encoding.build(
dtype,
fb_child.row_count(),
fb_child
.metadata()
.map(|m| m.bytes())
.unwrap_or_else(|| &[]),
fb_child
.segments()
.unwrap_or_default()
.iter()
.map(SegmentId::from)
.collect_vec(),
&viewed_children,
&self.array_read_ctx,
)
}
fn child_row_count(&self, idx: usize) -> u64 {
self.flatbuffer()
.children()
.unwrap_or_default()
.get(idx)
.row_count()
}
fn nchildren(&self) -> usize {
self.flatbuffer().children().unwrap_or_default().len()
}
}