Skip to content

Commit b613b87

Browse files
authored
feat: ergonomic access to immutable NodeTable columns (#726)
1 parent d87d4f7 commit b613b87

File tree

4 files changed

+82
-0
lines changed

4 files changed

+82
-0
lines changed

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub mod prelude;
9797
mod site_table;
9898
mod sys;
9999
mod table_collection;
100+
mod table_column;
100101
mod table_iterator;
101102
mod traits;
102103
mod trees;
@@ -116,6 +117,7 @@ pub use site_table::{SiteTable, SiteTableRow};
116117
pub use sys::flags::*;
117118
pub use sys::NodeTraversalOrder;
118119
pub use table_collection::TableCollection;
120+
pub use table_column::NodeTableColumn;
119121
pub use traits::IndividualLocation;
120122
pub use traits::IndividualParents;
121123
pub use trees::{Tree, TreeSequence};

src/node_table.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,22 @@ impl NodeTable {
807807
/// Get the population column as a slice
808808
=> population, population_slice_raw, crate::sys::bindings::tsk_id_t);
809809

810+
pub fn individual_column(&self) -> crate::table_column::NodeTableColumn<IndividualId> {
811+
crate::NodeTableColumn::new(self.individual_slice())
812+
}
813+
814+
pub fn population_column(&self) -> crate::NodeTableColumn<PopulationId> {
815+
crate::NodeTableColumn::new(self.population_slice())
816+
}
817+
818+
pub fn time_column(&self) -> crate::NodeTableColumn<Time> {
819+
crate::NodeTableColumn::new(self.time_slice())
820+
}
821+
822+
pub fn flags_column(&self) -> crate::NodeTableColumn<NodeFlags> {
823+
crate::NodeTableColumn::new(self.flags_slice())
824+
}
825+
810826
/// Clear all data from the table
811827
pub fn clear(&mut self) -> Result<i32, TskitError> {
812828
handle_tsk_return_value!(self.table_.clear())

src/table_column.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
macro_rules! make_table_column {
2+
($name: ident, $index: ident) => {
3+
/// Immutable view of a column
4+
#[derive(Clone, Debug)]
5+
#[repr(transparent)]
6+
pub struct $name<'table, T>(&'table [T]);
7+
8+
impl<'table, T> $name<'table, T> {
9+
pub(crate) fn new(column: &'table [T]) -> $name<'table, T> {
10+
Self(column)
11+
}
12+
13+
/// View the underlying slice
14+
pub fn as_slice(&self) -> &[T] {
15+
self.0
16+
}
17+
}
18+
19+
impl<T> std::ops::Index<usize> for $name<'_, T> {
20+
type Output = T;
21+
fn index(&self, index: usize) -> &Self::Output {
22+
&self.0[index]
23+
}
24+
}
25+
26+
impl<T> std::ops::Index<crate::$index> for $name<'_, T> {
27+
type Output = T;
28+
fn index(&self, index: crate::$index) -> &Self::Output {
29+
&self.0[usize::try_from(index).unwrap()]
30+
}
31+
}
32+
33+
impl<T> std::ops::Index<crate::SizeType> for $name<'_, T> {
34+
type Output = T;
35+
fn index(&self, index: crate::SizeType) -> &Self::Output {
36+
&self.0[usize::try_from(index).unwrap()]
37+
}
38+
}
39+
40+
impl<T> std::convert::AsRef<[T]> for $name<'_, T> {
41+
fn as_ref(&self) -> &[T] {
42+
self.0
43+
}
44+
}
45+
};
46+
}
47+
48+
make_table_column!(NodeTableColumn, NodeId);

tests/test_tables.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,19 @@ mod test_metadata_round_trips {
550550
);
551551
}
552552
}
553+
554+
#[test]
555+
fn test_node_table_column_access() {
556+
let mut t = tskit::NodeTable::new().unwrap();
557+
let node = t
558+
.add_row(tskit::NodeFlags::new_sample(), 0.0, -1, -1)
559+
.unwrap();
560+
let individual = t.individual_column();
561+
assert_eq!(individual[node], tskit::IndividualId::NULL);
562+
let population = t.population_column();
563+
assert_eq!(population[node], tskit::PopulationId::NULL);
564+
let time = t.time_column();
565+
assert_eq!(time[node], 0.0);
566+
let flags = t.flags_column();
567+
assert_eq!(flags[node], tskit::NodeFlags::IS_SAMPLE);
568+
}

0 commit comments

Comments
 (0)