1use antecedent_core::{CausalSchema, VariableId};
6
7use crate::column::ColumnView;
8use crate::error::DataError;
9
10fn analysis_f64_from_i64(v: i64) -> f64 {
12 #[allow(clippy::cast_precision_loss)]
13 {
14 v as f64
15 }
16}
17
18pub trait TableView {
20 fn schema(&self) -> &CausalSchema;
22
23 fn row_count(&self) -> usize;
25
26 fn column(&self, id: VariableId) -> Result<ColumnView<'_>, DataError>;
32
33 fn float64_values(&self, id: VariableId) -> Result<Vec<f64>, DataError> {
43 match self.column(id)? {
44 ColumnView::Float64(c) => Ok(c.values.to_vec()),
45 ColumnView::Int64(c) => {
46 let mut out = Vec::with_capacity(c.values.len());
47 for (i, &v) in c.values.iter().enumerate() {
48 out.push(if c.validity.is_valid(i) {
49 analysis_f64_from_i64(v)
50 } else {
51 f64::NAN
52 });
53 }
54 Ok(out)
55 }
56 ColumnView::Boolean(c) => {
57 let mut out = Vec::with_capacity(c.values.len());
58 for (i, &v) in c.values.iter().enumerate() {
59 out.push(if c.validity.is_valid(i) { f64::from(v) } else { f64::NAN });
60 }
61 Ok(out)
62 }
63 _ => Err(DataError::TypeMismatch {
64 id,
65 expected: "float64 (or coercible int64/boolean)",
66 }),
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use std::sync::Arc;
74
75 use antecedent_core::{
76 CausalSchemaBuilder, MeasurementSpec, RoleHint, SmallRoleSet, ValueType, VariableId,
77 };
78
79 use super::*;
80 use crate::column::{BooleanColumn, Float64Column, Int64Column, OwnedColumn, ValidityBitmap};
81 use crate::dataset::TabularData;
82 use crate::storage::OwnedColumnarStorage;
83
84 fn schema_n(n: usize) -> antecedent_core::CausalSchema {
85 let mut b = CausalSchemaBuilder::new();
86 for i in 0..n {
87 b.add_variable(
88 format!("v{i}"),
89 ValueType::Continuous,
90 SmallRoleSet::from_hint(RoleHint::Context),
91 None,
92 None,
93 MeasurementSpec::default(),
94 )
95 .unwrap();
96 }
97 b.build().unwrap()
98 }
99
100 #[test]
101 fn float64_values_coerces_int64_and_boolean() {
102 let schema = schema_n(3);
103 let cols = vec![
104 OwnedColumn::Float64(
105 Float64Column::new(
106 VariableId::from_raw(0),
107 Arc::from([1.5_f64, 2.5]),
108 ValidityBitmap::all_valid(2),
109 )
110 .unwrap(),
111 ),
112 OwnedColumn::Int64(
113 Int64Column::new(
114 VariableId::from_raw(1),
115 Arc::<[i64]>::from([3_i64, 4]),
116 ValidityBitmap::all_valid(2),
117 )
118 .unwrap(),
119 ),
120 OwnedColumn::Boolean(
121 BooleanColumn::new(
122 VariableId::from_raw(2),
123 Arc::<[u8]>::from([1_u8, 0]),
124 ValidityBitmap::all_valid(2),
125 )
126 .unwrap(),
127 ),
128 ];
129 let storage = OwnedColumnarStorage::try_new(schema, cols, None, None).unwrap();
130 let data = TabularData::new(storage);
131 assert_eq!(data.float64_values(VariableId::from_raw(0)).unwrap(), vec![1.5, 2.5]);
132 assert_eq!(data.float64_values(VariableId::from_raw(1)).unwrap(), vec![3.0, 4.0]);
133 assert_eq!(data.float64_values(VariableId::from_raw(2)).unwrap(), vec![1.0, 0.0]);
134 }
135}