Skip to content

Commit 0ee9f86

Browse files
authored
Merge pull request #61 from molpopgen/add_individual_and_migration_tables
Add individual and migration tables
2 parents b2c8913 + 8f072c4 commit 0ee9f86

File tree

5 files changed

+556
-1
lines changed

5 files changed

+556
-1
lines changed

src/_macros.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,32 @@ macro_rules! unsafe_tsk_column_access {
3737
}};
3838
}
3939

40+
macro_rules! unsafe_tsk_ragged_column_access {
41+
($i: expr, $lo: expr, $hi: expr, $array: expr, $offset_array: expr, $offset_array_len: expr) => {{
42+
if $i < $lo || $i >= ($hi as tsk_id_t) {
43+
Err(TskitError::IndexError {})
44+
} else if $offset_array_len == 0 {
45+
Ok(None)
46+
} else {
47+
let start = unsafe { *$offset_array.offset($i as isize) };
48+
let stop = if $i < ($hi as tsk_id_t) {
49+
unsafe { *$offset_array.offset(($i + 1) as isize) }
50+
} else {
51+
$offset_array_len as tsk_size_t
52+
};
53+
if start == stop {
54+
Ok(None)
55+
} else {
56+
let mut buffer = vec![];
57+
for i in start..stop {
58+
buffer.push(unsafe { *$array.offset(i as isize) });
59+
}
60+
Ok(Some(buffer))
61+
}
62+
}
63+
}};
64+
}
65+
4066
macro_rules! drop_for_tskit_type {
4167
($name: ident, $drop: ident) => {
4268
impl Drop for $name {

src/individual_table.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
use crate::bindings as ll_bindings;
2+
use crate::metadata;
3+
use crate::{tsk_flags_t, tsk_id_t, tsk_size_t, TskitError};
4+
5+
/// Row of a [`IndividualTable`]
6+
pub struct IndividualTableRow {
7+
pub flags: u32,
8+
pub location: Option<Vec<f64>>,
9+
pub parents: Option<Vec<tsk_id_t>>,
10+
pub metadata: Option<Vec<u8>>,
11+
}
12+
13+
impl PartialEq for IndividualTableRow {
14+
fn eq(&self, other: &Self) -> bool {
15+
self.flags == other.flags
16+
&& self.parents == other.parents
17+
&& self.metadata == other.metadata
18+
&& match &self.location {
19+
None => other.location.is_none(),
20+
Some(a) => match &other.location {
21+
None => false,
22+
Some(b) => {
23+
if a.len() != b.len() {
24+
false
25+
} else {
26+
for (i, j) in a.iter().enumerate() {
27+
if !crate::util::f64_partial_cmp_equal(&j, &b[i]) {
28+
return false;
29+
}
30+
}
31+
true
32+
}
33+
}
34+
},
35+
}
36+
}
37+
}
38+
39+
/// An immutable view of a individual table.
40+
///
41+
/// These are not created directly.
42+
/// Instead, use [`TableCollection::individuals`](crate::TableCollection::individuals)
43+
/// to get a reference to an existing node table;
44+
pub struct IndividualTable<'a> {
45+
table_: &'a ll_bindings::tsk_individual_table_t,
46+
}
47+
48+
fn make_individual_table_row(
49+
table: &IndividualTable,
50+
pos: tsk_id_t,
51+
decode_metadata: bool,
52+
) -> Option<IndividualTableRow> {
53+
if pos < table.num_rows() as tsk_id_t {
54+
let rv = IndividualTableRow {
55+
flags: table.flags(pos).unwrap(),
56+
location: table.location(pos).unwrap(),
57+
parents: table.parents(pos).unwrap(),
58+
metadata: match decode_metadata {
59+
true => match metadata_to_vector!(table, pos).unwrap() {
60+
Some(x) => Some(x),
61+
None => None,
62+
},
63+
false => None,
64+
},
65+
};
66+
Some(rv)
67+
} else {
68+
None
69+
}
70+
}
71+
72+
pub type IndividualTableRefIterator<'a> =
73+
crate::table_iterator::TableIterator<&'a IndividualTable<'a>>;
74+
pub type IndividualTableIterator<'a> = crate::table_iterator::TableIterator<IndividualTable<'a>>;
75+
76+
impl<'a> IndividualTable<'a> {
77+
pub(crate) fn new_from_table(individuals: &'a ll_bindings::tsk_individual_table_t) -> Self {
78+
IndividualTable {
79+
table_: individuals,
80+
}
81+
}
82+
83+
/// Return the number of rows
84+
pub fn num_rows(&'a self) -> ll_bindings::tsk_size_t {
85+
self.table_.num_rows
86+
}
87+
88+
/// Return the flags for a given row.
89+
///
90+
/// # Errors
91+
///
92+
/// * [`TskitError::IndexError`] if `row` is out of range.
93+
pub fn flags(&self, row: tsk_id_t) -> Result<tsk_flags_t, TskitError> {
94+
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.flags)
95+
}
96+
97+
/// Return the locations for a given row.
98+
///
99+
/// # Errors
100+
///
101+
/// * [`TskitError::IndexError`] if `row` is out of range.
102+
pub fn location(&self, row: tsk_id_t) -> Result<Option<Vec<f64>>, TskitError> {
103+
unsafe_tsk_ragged_column_access!(
104+
row,
105+
0,
106+
self.num_rows(),
107+
self.table_.location,
108+
self.table_.location_offset,
109+
self.table_.location_length
110+
)
111+
}
112+
113+
/// Return the parents for a given row.
114+
///
115+
/// # Errors
116+
///
117+
/// * [`TskitError::IndexError`] if `row` is out of range.
118+
pub fn parents(&self, row: tsk_id_t) -> Result<Option<Vec<tsk_id_t>>, TskitError> {
119+
unsafe_tsk_ragged_column_access!(
120+
row,
121+
0,
122+
self.num_rows(),
123+
self.table_.parents,
124+
self.table_.parents_offset,
125+
self.table_.parents_length
126+
)
127+
}
128+
129+
/// Return the metadata for a given row.
130+
///
131+
/// # Errors
132+
///
133+
/// * [`TskitError::IndexError`] if `row` is out of range.
134+
pub fn metadata<T: metadata::MetadataRoundtrip>(
135+
&'a self,
136+
row: tsk_id_t,
137+
) -> Result<Option<T>, TskitError> {
138+
let buffer = metadata_to_vector!(self, row)?;
139+
decode_metadata_row!(T, buffer)
140+
}
141+
142+
/// Return an iterator over rows of the table.
143+
/// The value of the iterator is [`IndividualTableRow`].
144+
///
145+
/// # Parameters
146+
///
147+
/// * `decode_metadata`: if `true`, then a *copy* of row metadata
148+
/// will be provided in [`IndividualTableRow::metadata`].
149+
/// The meta data are *not* decoded.
150+
/// Rows with no metadata will contain the value `None`.
151+
///
152+
pub fn iter(&self, decode_metadata: bool) -> IndividualTableRefIterator {
153+
crate::table_iterator::make_table_iterator::<&IndividualTable<'a>>(&self, decode_metadata)
154+
}
155+
156+
/// Return row `r` of the table.
157+
///
158+
/// # Parameters
159+
///
160+
/// * `r`: the row id.
161+
/// * `decode_metadata`: if `true`, then a *copy* of row metadata
162+
/// will be provided in [`IndividualTableRow::metadata`].
163+
/// The meta data are *not* decoded.
164+
/// Rows with no metadata will contain the value `None`.
165+
///
166+
/// # Errors
167+
///
168+
/// [`TskitError::IndexError`] if `r` is out of range.
169+
pub fn row(
170+
&self,
171+
r: tsk_id_t,
172+
decode_metadata: bool,
173+
) -> Result<IndividualTableRow, TskitError> {
174+
table_row_access!(r, decode_metadata, self, make_individual_table_row)
175+
}
176+
}

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ mod _macros; // Starts w/_ to be sorted at front by rustfmt!
1010
mod edge_table;
1111
pub mod error;
1212
pub mod ffi;
13+
mod individual_table;
1314
pub mod metadata;
15+
mod migration_table;
1416
mod mutation_table;
1517
mod node_table;
1618
mod population_table;
@@ -40,6 +42,8 @@ pub const TSK_NULL: tsk_id_t = -1;
4042

4143
pub use edge_table::{EdgeTable, EdgeTableRow};
4244
pub use error::TskitError;
45+
pub use individual_table::{IndividualTable, IndividualTableRow};
46+
pub use migration_table::{MigrationTable, MigrationTableRow};
4347
pub use mutation_table::{MutationTable, MutationTableRow};
4448
pub use node_table::{NodeTable, NodeTableRow};
4549
pub use population_table::{PopulationTable, PopulationTableRow};

0 commit comments

Comments
 (0)