use std::sync::Arc;
use antecedent_core::{CausalSchema, VariableId};
use crate::column::{ColumnView, OwnedColumn};
use crate::error::DataError;
use crate::table::TableView;
#[derive(Clone, Debug)]
pub struct OwnedColumnarStorage {
schema: CausalSchema,
columns: Arc<[OwnedColumn]>,
row_count: usize,
analysis_mask: Option<crate::column::ValidityBitmap>,
weights: Option<Arc<[f64]>>,
}
impl OwnedColumnarStorage {
pub fn try_new(
schema: CausalSchema,
columns: Vec<OwnedColumn>,
analysis_mask: Option<crate::column::ValidityBitmap>,
weights: Option<Arc<[f64]>>,
) -> Result<Self, DataError> {
if columns.len() != schema.len() {
return Err(DataError::LengthMismatch {
expected: schema.len(),
actual: columns.len(),
context: "column count vs schema",
});
}
let row_count = columns.first().map_or(0, OwnedColumn::len);
for (i, col) in columns.iter().enumerate() {
let expected_id = VariableId::from_raw(u32::try_from(i).map_err(|_| {
DataError::InvalidArgument { message: "schema exceeds VariableId range".into() }
})?);
if col.id() != expected_id {
return Err(DataError::UnknownVariable { id: col.id() });
}
if col.len() != row_count {
return Err(DataError::LengthMismatch {
expected: row_count,
actual: col.len(),
context: "column row count",
});
}
}
if let Some(mask) = &analysis_mask {
if mask.len() != row_count {
return Err(DataError::LengthMismatch {
expected: row_count,
actual: mask.len(),
context: "analysis mask",
});
}
}
if let Some(w) = &weights {
if w.len() != row_count {
return Err(DataError::LengthMismatch {
expected: row_count,
actual: w.len(),
context: "weights",
});
}
}
Ok(Self { schema, columns: Arc::from(columns), row_count, analysis_mask, weights })
}
#[must_use]
pub fn analysis_mask(&self) -> Option<&crate::column::ValidityBitmap> {
self.analysis_mask.as_ref()
}
#[must_use]
pub fn weights(&self) -> Option<&[f64]> {
self.weights.as_deref()
}
#[must_use]
pub fn columns(&self) -> &[OwnedColumn] {
&self.columns
}
#[must_use]
pub fn columns_arc(&self) -> &Arc<[OwnedColumn]> {
&self.columns
}
}
impl TableView for OwnedColumnarStorage {
fn schema(&self) -> &CausalSchema {
&self.schema
}
fn row_count(&self) -> usize {
self.row_count
}
fn column(&self, id: VariableId) -> Result<ColumnView<'_>, DataError> {
self.columns
.get(id.as_usize())
.map(OwnedColumn::as_view)
.ok_or(DataError::UnknownVariable { id })
}
}