Skip to content

Commit de006a1

Browse files
authored
Add PopulationId (#135)
1 parent 630ccd5 commit de006a1

File tree

4 files changed

+72
-42
lines changed

4 files changed

+72
-42
lines changed

src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub use bindings::tsk_size_t;
121121
/// assert_eq!(y, z);
122122
/// ```
123123
///
124-
/// It is also possible to write functions accepting both the `NodeId`
124+
/// It is also possible to write functions accepting both the `NodeId`
125125
/// and `tsk_id_t`:
126126
///
127127
/// ```
@@ -151,8 +151,18 @@ pub struct NodeId(tsk_id_t);
151151
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
152152
pub struct IndividualId(tsk_id_t);
153153

154+
/// A population ID
155+
///
156+
/// This is an integer referring to a row of an [``PopulationTable``].
157+
///
158+
/// The features for this type follow the same pattern as for [``NodeId``]
159+
#[repr(transparent)]
160+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
161+
pub struct PopulationId(tsk_id_t);
162+
154163
impl_id_traits!(NodeId);
155164
impl_id_traits!(IndividualId);
165+
impl_id_traits!(PopulationId);
156166

157167
// tskit defines this via a type cast
158168
// in a macro. bindgen thus misses it.

src/node_table.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use crate::bindings as ll_bindings;
22
use crate::metadata;
3-
use crate::NodeId;
43
use crate::{tsk_flags_t, tsk_id_t, TskitError};
4+
use crate::{NodeId, PopulationId};
55

66
/// Row of a [`NodeTable`]
77
pub struct NodeTableRow {
88
pub id: NodeId,
99
pub time: f64,
1010
pub flags: tsk_flags_t,
11-
pub population: tsk_id_t,
11+
pub population: PopulationId,
1212
pub individual: tsk_id_t,
1313
pub metadata: Option<Vec<u8>>,
1414
}
@@ -117,8 +117,17 @@ impl<'a> NodeTable<'a> {
117117
///
118118
/// Will return [``IndexError``](crate::TskitError::IndexError)
119119
/// if ``row`` is out of range.
120-
pub fn population<N: Into<NodeId> + Copy>(&'a self, row: N) -> Result<tsk_id_t, TskitError> {
121-
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.population)
120+
pub fn population<N: Into<NodeId> + Copy>(
121+
&'a self,
122+
row: N,
123+
) -> Result<PopulationId, TskitError> {
124+
unsafe_tsk_column_access!(
125+
row.into().0,
126+
0,
127+
self.num_rows(),
128+
self.table_.population,
129+
PopulationId
130+
)
122131
}
123132

124133
/// Return the ``population`` value from row ``row`` of the table.
@@ -127,7 +136,7 @@ impl<'a> NodeTable<'a> {
127136
///
128137
/// Will return [``IndexError``](crate::TskitError::IndexError)
129138
/// if ``row`` is out of range.
130-
pub fn deme<N: Into<NodeId> + Copy>(&'a self, row: N) -> Result<tsk_id_t, TskitError> {
139+
pub fn deme<N: Into<NodeId> + Copy>(&'a self, row: N) -> Result<PopulationId, TskitError> {
131140
self.population(row)
132141
}
133142

src/population_table.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::bindings as ll_bindings;
22
use crate::metadata;
3+
use crate::PopulationId;
34
use crate::TskitError;
45
use crate::{tsk_id_t, tsk_size_t};
56

67
/// Row of a [`PopulationTable`]
78
#[derive(Eq)]
89
pub struct PopulationTableRow {
9-
pub id: tsk_id_t,
10+
pub id: PopulationId,
1011
pub metadata: Option<Vec<u8>>,
1112
}
1213

@@ -19,7 +20,7 @@ impl PartialEq for PopulationTableRow {
1920
fn make_population_table_row(table: &PopulationTable, pos: tsk_id_t) -> Option<PopulationTableRow> {
2021
if pos < table.num_rows() as tsk_id_t {
2122
let rv = PopulationTableRow {
22-
id: pos,
23+
id: pos.into(),
2324
metadata: table_row_decode_metadata!(table, pos),
2425
};
2526
Some(rv)
@@ -71,11 +72,11 @@ impl<'a> PopulationTable<'a> {
7172
self.table_.num_rows
7273
}
7374

74-
pub fn metadata<T: metadata::MetadataRoundtrip>(
75+
pub fn metadata<P: Into<PopulationId>, T: metadata::MetadataRoundtrip>(
7576
&'a self,
76-
row: tsk_id_t,
77+
row: P,
7778
) -> Result<Option<T>, TskitError> {
78-
let buffer = metadata_to_vector!(self, row)?;
79+
let buffer = metadata_to_vector!(self, row.into().0)?;
7980
decode_metadata_row!(T, buffer)
8081
}
8182

@@ -94,7 +95,10 @@ impl<'a> PopulationTable<'a> {
9495
/// # Errors
9596
///
9697
/// [`TskitError::IndexError`] if `r` is out of range.
97-
pub fn row(&self, r: tsk_id_t) -> Result<PopulationTableRow, TskitError> {
98-
table_row_access!(r, self, make_population_table_row)
98+
pub fn row<P: Into<PopulationId> + Copy>(
99+
&self,
100+
r: P,
101+
) -> Result<PopulationTableRow, TskitError> {
102+
table_row_access!(r.into().0, self, make_population_table_row)
99103
}
100104
}

src/table_collection.rs

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::TreeSequenceFlags;
2020
use crate::TskReturnValue;
2121
use crate::TskitTypeAccess;
2222
use crate::{tsk_flags_t, tsk_id_t, tsk_size_t, TSK_NULL};
23-
use crate::{IndividualId, NodeId};
23+
use crate::{IndividualId, NodeId, PopulationId};
2424
use ll_bindings::tsk_table_collection_free;
2525

2626
/// A table collection.
@@ -241,11 +241,11 @@ impl TableCollection {
241241
///
242242
/// Migration tables are not currently supported
243243
/// by tree sequence simplification.
244-
pub fn add_migration<N: Into<NodeId>>(
244+
pub fn add_migration<N: Into<NodeId>, SOURCE: Into<PopulationId>, DEST: Into<PopulationId>>(
245245
&mut self,
246246
span: (f64, f64),
247247
node: N,
248-
source_dest: (tsk_id_t, tsk_id_t),
248+
source_dest: (SOURCE, DEST),
249249
time: f64,
250250
) -> TskReturnValue {
251251
self.add_migration_with_metadata(span, node, source_dest, time, None)
@@ -257,11 +257,15 @@ impl TableCollection {
257257
///
258258
/// Migration tables are not currently supported
259259
/// by tree sequence simplification.
260-
pub fn add_migration_with_metadata<N: Into<NodeId>>(
260+
pub fn add_migration_with_metadata<
261+
N: Into<NodeId>,
262+
SOURCE: Into<PopulationId>,
263+
DEST: Into<PopulationId>,
264+
>(
261265
&mut self,
262266
span: (f64, f64),
263267
node: N,
264-
source_dest: (tsk_id_t, tsk_id_t),
268+
source_dest: (SOURCE, DEST),
265269
time: f64,
266270
metadata: Option<&dyn MetadataRoundtrip>,
267271
) -> TskReturnValue {
@@ -272,8 +276,8 @@ impl TableCollection {
272276
span.0,
273277
span.1,
274278
node.into().0,
275-
source_dest.0,
276-
source_dest.1,
279+
source_dest.0.into().0,
280+
source_dest.1.into().0,
277281
time,
278282
md.as_ptr(),
279283
md.len(),
@@ -283,22 +287,22 @@ impl TableCollection {
283287
}
284288

285289
/// Add a row to the node table
286-
pub fn add_node<I: Into<IndividualId>>(
290+
pub fn add_node<I: Into<IndividualId>, POP: Into<PopulationId>>(
287291
&mut self,
288292
flags: ll_bindings::tsk_flags_t,
289293
time: f64,
290-
population: tsk_id_t,
294+
population: POP,
291295
individual: I,
292296
) -> Result<NodeId, TskitError> {
293297
self.add_node_with_metadata(flags, time, population, individual, None)
294298
}
295299

296300
/// Add a row with metadata to the node table
297-
pub fn add_node_with_metadata<I: Into<IndividualId>>(
301+
pub fn add_node_with_metadata<I: Into<IndividualId>, POP: Into<PopulationId>>(
298302
&mut self,
299303
flags: ll_bindings::tsk_flags_t,
300304
time: f64,
301-
population: tsk_id_t,
305+
population: POP,
302306
individual: I,
303307
metadata: Option<&dyn MetadataRoundtrip>,
304308
) -> Result<NodeId, TskitError> {
@@ -308,7 +312,7 @@ impl TableCollection {
308312
&mut (*self.as_mut_ptr()).nodes,
309313
flags,
310314
time,
311-
population,
315+
population.into().0,
312316
individual.into().0,
313317
md.as_ptr(),
314318
md.len(),
@@ -390,15 +394,15 @@ impl TableCollection {
390394
}
391395

392396
/// Add a row to the population_table
393-
pub fn add_population(&mut self) -> TskReturnValue {
397+
pub fn add_population(&mut self) -> Result<PopulationId, TskitError> {
394398
self.add_population_with_metadata(None)
395399
}
396400

397401
/// Add a row with metadata to the population_table
398402
pub fn add_population_with_metadata(
399403
&mut self,
400404
metadata: Option<&dyn MetadataRoundtrip>,
401-
) -> TskReturnValue {
405+
) -> Result<PopulationId, TskitError> {
402406
let md = EncodedMetadata::new(metadata)?;
403407
let rv = unsafe {
404408
ll_bindings::tsk_population_table_add_row(
@@ -408,7 +412,7 @@ impl TableCollection {
408412
)
409413
};
410414

411-
handle_tsk_return_value!(rv)
415+
handle_tsk_return_value!(rv, PopulationId::from(rv))
412416
}
413417

414418
/// Build the "input" and "output"
@@ -1030,30 +1034,33 @@ mod test {
10301034
#[test]
10311035
fn test_add_population() {
10321036
let mut tables = TableCollection::new(1000.).unwrap();
1033-
tables.add_population().unwrap();
1037+
let pop_id = tables.add_population().unwrap();
1038+
assert_eq!(pop_id, 0);
10341039
assert_eq!(tables.populations().num_rows(), 1);
1040+
1041+
tables
1042+
.add_node(crate::TSK_NODE_IS_SAMPLE, 0.0, pop_id, crate::TSK_NULL)
1043+
.unwrap();
1044+
1045+
match tables.nodes().row(NodeId::from(0)) {
1046+
Ok(x) => match x.population {
1047+
PopulationId(0) => (),
1048+
_ => panic!("expected PopulationId(0)"),
1049+
},
1050+
Err(_) => panic!("expected Ok(_)"),
1051+
};
10351052
}
10361053

10371054
#[test]
10381055
fn test_dump_tables() {
10391056
let treefile = "trees.trees";
10401057
let mut tables = TableCollection::new(1000.).unwrap();
1041-
tables.add_population().unwrap();
1058+
let pop_id = tables.add_population().unwrap();
10421059
tables
1043-
.add_node(
1044-
crate::TSK_NODE_IS_SAMPLE,
1045-
0.0,
1046-
crate::TSK_NULL,
1047-
crate::TSK_NULL,
1048-
)
1060+
.add_node(crate::TSK_NODE_IS_SAMPLE, 0.0, pop_id, crate::TSK_NULL)
10491061
.unwrap();
10501062
tables
1051-
.add_node(
1052-
crate::TSK_NODE_IS_SAMPLE,
1053-
1.0,
1054-
crate::TSK_NULL,
1055-
crate::TSK_NULL,
1056-
)
1063+
.add_node(crate::TSK_NODE_IS_SAMPLE, 1.0, pop_id, crate::TSK_NULL)
10571064
.unwrap();
10581065
tables.add_edge(0., tables.sequence_length(), 1, 0).unwrap();
10591066
tables

0 commit comments

Comments
 (0)