use tracing::instrument;
use crate::array::{Array, RealmRef, RefOrTaggedValue};
use crate::column::{Column, ColumnImpl, ColumnType};
use crate::realm::Realm;
use crate::table::{ColumnAttributes, Row, Table};
use crate::traits::{ArrayLike, Node, NodeWithContext};
use crate::utils::read_array_value;
use std::sync::Arc;
#[derive(Debug, Clone, Copy)]
pub(crate) struct SubtableContext {
header_ref: RealmRef,
}
pub(crate) struct SubtableColumnType;
impl ColumnType for SubtableColumnType {
type Value = Option<Vec<Row<'static>>>;
type LeafType = SubtableArrayLeaf;
type LeafContext = SubtableContext;
}
#[derive(Debug)]
pub(crate) struct SubtableArrayLeaf {
root: Array,
header_array: Array,
}
impl NodeWithContext<SubtableContext> for SubtableArrayLeaf {
#[instrument(level = "debug")]
fn from_ref_with_context(
realm: Arc<Realm>,
ref_: RealmRef,
context: SubtableContext,
) -> crate::RealmResult<Self>
where
Self: Sized,
{
let root = Array::from_ref(Arc::clone(&realm), ref_)?;
let header_array = Array::from_ref(realm, context.header_ref)?;
Ok(SubtableArrayLeaf { root, header_array })
}
}
impl ArrayLike<Option<Vec<Row<'static>>>, SubtableContext> for SubtableArrayLeaf {
fn get(&self, index: usize) -> crate::RealmResult<Option<Vec<Row<'static>>>> {
let Some(data_array) = self.root.get_node(index)? else {
return Ok(None);
};
Ok(Some(
Table::build_from(&self.header_array, data_array, usize::MAX)?
.get_rows()?
.into_iter()
.map(Row::into_owned)
.collect(),
))
}
fn get_direct(
realm: Arc<Realm>,
ref_: RealmRef,
index: usize,
context: SubtableContext,
) -> crate::RealmResult<Option<Vec<Row<'static>>>> {
let header = realm.header(ref_)?;
let payload = realm.payload(ref_, header.payload_len());
let data_array = match read_array_value(payload, header.width(), index) {
0 => return Ok(None),
n => match RefOrTaggedValue::from_raw(n) {
RefOrTaggedValue::Ref(ref_) => Array::from_ref(Arc::clone(&realm), ref_)?,
_ => return Ok(None),
},
};
let header_array = Array::from_ref(realm, context.header_ref)?;
Ok(Some(
Table::build_from(&header_array, data_array, usize::MAX)?
.get_rows()?
.into_iter()
.map(|row| Row::into_owned(row))
.collect(),
))
}
fn is_null(&self, index: usize) -> crate::RealmResult<bool> {
Ok(self.root.get_ref(index).is_none())
}
fn size(&self) -> usize {
self.root.node.header.size as usize
}
}
pub(crate) fn create_subtable_column(
realm: Arc<Realm>,
header_ref: RealmRef,
data_ref: RealmRef,
attributes: ColumnAttributes,
name: String,
) -> crate::RealmResult<Box<dyn Column>> {
Ok(Box::new(SubtableColumn::new(
realm,
data_ref,
None,
attributes,
Some(name),
SubtableContext { header_ref },
)?))
}
pub(crate) type SubtableColumn = ColumnImpl<SubtableColumnType>;