Skip to content

Commit 7713ef6

Browse files
authored
Add SiteId and MutationId (#136)
1 parent de006a1 commit 7713ef6

File tree

7 files changed

+104
-50
lines changed

7 files changed

+104
-50
lines changed

examples/mutation_metadata_bincode.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ pub fn run() {
4545
// 1. The first is to handle errors.
4646
// 2. The second is b/c metadata are optional,
4747
// so a row may return None.
48-
let decoded = tables.mutations().metadata::<Mutation>(0).unwrap().unwrap();
48+
let decoded = tables
49+
.mutations()
50+
.metadata::<Mutation>(0.into())
51+
.unwrap()
52+
.unwrap();
4953

5054
// Check that we've made the round trip:
5155
assert_eq!(decoded.origin_time, 1);

examples/mutation_metadata_std.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ pub fn run() {
2525
// 1. The first is to handle errors.
2626
// 2. The second is b/c metadata are optional,
2727
// so a row may return None.
28-
let decoded = tables.mutations().metadata::<Mutation>(0).unwrap().unwrap();
28+
let decoded = tables
29+
.mutations()
30+
.metadata::<Mutation>(0.into())
31+
.unwrap()
32+
.unwrap();
2933

3034
// Check that we've made the round trip:
3135
assert_eq!(decoded.origin_time, 1);

src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,29 @@ pub struct IndividualId(tsk_id_t);
160160
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
161161
pub struct PopulationId(tsk_id_t);
162162

163+
/// A site ID
164+
///
165+
/// This is an integer referring to a row of an [``SiteTable``].
166+
///
167+
/// The features for this type follow the same pattern as for [``NodeId``]
168+
#[repr(transparent)]
169+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
170+
pub struct SiteId(tsk_id_t);
171+
172+
/// A mutation ID
173+
///
174+
/// This is an integer referring to a row of an [``MutationTable``].
175+
///
176+
/// The features for this type follow the same pattern as for [``NodeId``]
177+
#[repr(transparent)]
178+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
179+
pub struct MutationId(tsk_id_t);
180+
163181
impl_id_traits!(NodeId);
164182
impl_id_traits!(IndividualId);
165183
impl_id_traits!(PopulationId);
184+
impl_id_traits!(SiteId);
185+
impl_id_traits!(MutationId);
166186

167187
// tskit defines this via a type cast
168188
// in a macro. bindgen thus misses it.

src/metadata.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ use thiserror::Error;
5252
/// // The two unwraps are:
5353
/// // 1. Handle Errors vs Option.
5454
/// // 2. Handle the option for the case of no error.
55-
/// let decoded = tables.mutations().metadata::<MyMutation>(0).unwrap().unwrap();
55+
/// //
56+
/// // The .into() reflects the fact that metadata fetching
57+
/// // functions only take a strong ID type, and tskit-rust
58+
/// // adds Into<strong ID type> for i32 for all strong ID types.
59+
///
60+
/// let decoded = tables.mutations().metadata::<MyMutation>(0.into()).unwrap().unwrap();
5661
/// assert_eq!(mutation.origin_time, decoded.origin_time);
5762
/// match decoded.effect_size.partial_cmp(&mutation.effect_size) {
5863
/// Some(std::cmp::Ordering::Greater) => assert!(false),

src/mutation_table.rs

Lines changed: 28 additions & 19 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_id_t, tsk_size_t, TskitError};
4+
use crate::{MutationId, NodeId, SiteId};
55

66
/// Row of a [`MutationTable`]
77
pub struct MutationTableRow {
8-
pub id: tsk_id_t,
9-
pub site: tsk_id_t,
8+
pub id: MutationId,
9+
pub site: SiteId,
1010
pub node: NodeId,
11-
pub parent: tsk_id_t,
11+
pub parent: MutationId,
1212
pub time: f64,
1313
pub derived_state: Option<Vec<u8>>,
1414
pub metadata: Option<Vec<u8>>,
@@ -29,7 +29,7 @@ impl PartialEq for MutationTableRow {
2929
fn make_mutation_table_row(table: &MutationTable, pos: tsk_id_t) -> Option<MutationTableRow> {
3030
if pos < table.num_rows() as tsk_id_t {
3131
let rv = MutationTableRow {
32-
id: pos,
32+
id: pos.into(),
3333
site: table.site(pos).unwrap(),
3434
node: table.node(pos).unwrap(),
3535
parent: table.parent(pos).unwrap(),
@@ -90,8 +90,8 @@ impl<'a> MutationTable<'a> {
9090
///
9191
/// Will return [``IndexError``](crate::TskitError::IndexError)
9292
/// if ``row`` is out of range.
93-
pub fn site(&'a self, row: tsk_id_t) -> Result<tsk_id_t, TskitError> {
94-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.site)
93+
pub fn site<M: Into<MutationId> + Copy>(&'a self, row: M) -> Result<SiteId, TskitError> {
94+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.site, SiteId)
9595
}
9696

9797
/// Return the ``node`` value from row ``row`` of the table.
@@ -100,8 +100,8 @@ impl<'a> MutationTable<'a> {
100100
///
101101
/// Will return [``IndexError``](crate::TskitError::IndexError)
102102
/// if ``row`` is out of range.
103-
pub fn node(&'a self, row: tsk_id_t) -> Result<NodeId, TskitError> {
104-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.node, NodeId)
103+
pub fn node<M: Into<MutationId> + Copy>(&'a self, row: M) -> Result<NodeId, TskitError> {
104+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.node, NodeId)
105105
}
106106

107107
/// Return the ``parent`` value from row ``row`` of the table.
@@ -110,8 +110,14 @@ impl<'a> MutationTable<'a> {
110110
///
111111
/// Will return [``IndexError``](crate::TskitError::IndexError)
112112
/// if ``row`` is out of range.
113-
pub fn parent(&'a self, row: tsk_id_t) -> Result<tsk_id_t, TskitError> {
114-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.parent)
113+
pub fn parent<M: Into<MutationId> + Copy>(&'a self, row: M) -> Result<MutationId, TskitError> {
114+
unsafe_tsk_column_access!(
115+
row.into().0,
116+
0,
117+
self.num_rows(),
118+
self.table_.parent,
119+
MutationId
120+
)
115121
}
116122

117123
/// Return the ``time`` value from row ``row`` of the table.
@@ -120,8 +126,8 @@ impl<'a> MutationTable<'a> {
120126
///
121127
/// Will return [``IndexError``](crate::TskitError::IndexError)
122128
/// if ``row`` is out of range.
123-
pub fn time(&'a self, row: tsk_id_t) -> Result<f64, TskitError> {
124-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.time)
129+
pub fn time<M: Into<MutationId> + Copy>(&'a self, row: M) -> Result<f64, TskitError> {
130+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.time)
125131
}
126132

127133
/// Get the ``derived_state`` value from row ``row`` of the table.
@@ -134,21 +140,24 @@ impl<'a> MutationTable<'a> {
134140
///
135141
/// Will return [``IndexError``](crate::TskitError::IndexError)
136142
/// if ``row`` is out of range.
137-
pub fn derived_state(&'a self, row: tsk_id_t) -> Result<Option<Vec<u8>>, TskitError> {
143+
pub fn derived_state<M: Into<MutationId>>(
144+
&'a self,
145+
row: M,
146+
) -> Result<Option<Vec<u8>>, TskitError> {
138147
metadata::char_column_to_vector(
139148
self.table_.derived_state,
140149
self.table_.derived_state_offset,
141-
row,
150+
row.into().0,
142151
self.table_.num_rows,
143152
self.table_.derived_state_length,
144153
)
145154
}
146155

147156
pub fn metadata<T: metadata::MetadataRoundtrip>(
148157
&'a self,
149-
row: tsk_id_t,
158+
row: MutationId,
150159
) -> Result<Option<T>, TskitError> {
151-
let buffer = metadata_to_vector!(self, row)?;
160+
let buffer = metadata_to_vector!(self, row.0)?;
152161
decode_metadata_row!(T, buffer)
153162
}
154163

@@ -167,7 +176,7 @@ impl<'a> MutationTable<'a> {
167176
/// # Errors
168177
///
169178
/// [`TskitError::IndexError`] if `r` is out of range.
170-
pub fn row(&self, r: tsk_id_t) -> Result<MutationTableRow, TskitError> {
171-
table_row_access!(r, self, make_mutation_table_row)
179+
pub fn row<M: Into<MutationId> + Copy>(&self, r: M) -> Result<MutationTableRow, TskitError> {
180+
table_row_access!(r.into().0, self, make_mutation_table_row)
172181
}
173182
}

src/site_table.rs

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

67
/// Row of a [`SiteTable`]
78
pub struct SiteTableRow {
8-
pub id: tsk_id_t,
9+
pub id: SiteId,
910
pub position: f64,
1011
pub ancestral_state: Option<Vec<u8>>,
1112
pub metadata: Option<Vec<u8>>,
@@ -23,7 +24,7 @@ impl PartialEq for SiteTableRow {
2324
fn make_site_table_row(table: &SiteTable, pos: tsk_id_t) -> Option<SiteTableRow> {
2425
if pos < table.num_rows() as tsk_id_t {
2526
let rv = SiteTableRow {
26-
id: pos,
27+
id: pos.into(),
2728
position: table.position(pos).unwrap(),
2829
ancestral_state: table.ancestral_state(pos).unwrap(),
2930
metadata: table_row_decode_metadata!(table, pos),
@@ -82,8 +83,8 @@ impl<'a> SiteTable<'a> {
8283
///
8384
/// Will return [``IndexError``](crate::TskitError::IndexError)
8485
/// if ``row`` is out of range.
85-
pub fn position(&'a self, row: tsk_id_t) -> Result<f64, TskitError> {
86-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.position)
86+
pub fn position<S: Into<SiteId> + Copy>(&'a self, row: S) -> Result<f64, TskitError> {
87+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.position)
8788
}
8889

8990
/// Get the ``ancestral_state`` value from row ``row`` of the table.
@@ -96,21 +97,24 @@ impl<'a> SiteTable<'a> {
9697
///
9798
/// Will return [``IndexError``](crate::TskitError::IndexError)
9899
/// if ``row`` is out of range.
99-
pub fn ancestral_state(&'a self, row: tsk_id_t) -> Result<Option<Vec<u8>>, TskitError> {
100+
pub fn ancestral_state<S: Into<SiteId>>(
101+
&'a self,
102+
row: S,
103+
) -> Result<Option<Vec<u8>>, TskitError> {
100104
crate::metadata::char_column_to_vector(
101105
self.table_.ancestral_state,
102106
self.table_.ancestral_state_offset,
103-
row,
107+
row.into().0,
104108
self.table_.num_rows,
105109
self.table_.ancestral_state_length,
106110
)
107111
}
108112

109113
pub fn metadata<T: metadata::MetadataRoundtrip>(
110114
&'a self,
111-
row: tsk_id_t,
115+
row: SiteId,
112116
) -> Result<Option<T>, TskitError> {
113-
let buffer = metadata_to_vector!(self, row)?;
117+
let buffer = metadata_to_vector!(self, row.0)?;
114118
decode_metadata_row!(T, buffer)
115119
}
116120

@@ -129,7 +133,7 @@ impl<'a> SiteTable<'a> {
129133
/// # Errors
130134
///
131135
/// [`TskitError::IndexError`] if `r` is out of range.
132-
pub fn row(&self, r: tsk_id_t) -> Result<SiteTableRow, TskitError> {
133-
table_row_access!(r, self, make_site_table_row)
136+
pub fn row<S: Into<SiteId> + Copy>(&self, r: S) -> Result<SiteTableRow, TskitError> {
137+
table_row_access!(r.into().0, self, make_site_table_row)
134138
}
135139
}

src/table_collection.rs

Lines changed: 26 additions & 18 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, PopulationId};
23+
use crate::{IndividualId, MutationId, NodeId, PopulationId, SiteId};
2424
use ll_bindings::tsk_table_collection_free;
2525

2626
/// A table collection.
@@ -323,7 +323,11 @@ impl TableCollection {
323323
}
324324

325325
/// Add a row to the site table
326-
pub fn add_site(&mut self, position: f64, ancestral_state: Option<&[u8]>) -> TskReturnValue {
326+
pub fn add_site(
327+
&mut self,
328+
position: f64,
329+
ancestral_state: Option<&[u8]>,
330+
) -> Result<SiteId, TskitError> {
327331
self.add_site_with_metadata(position, ancestral_state, None)
328332
}
329333

@@ -333,7 +337,7 @@ impl TableCollection {
333337
position: f64,
334338
ancestral_state: Option<&[u8]>,
335339
metadata: Option<&dyn MetadataRoundtrip>,
336-
) -> TskReturnValue {
340+
) -> Result<SiteId, TskitError> {
337341
let astate = process_state_input!(ancestral_state);
338342
let md = EncodedMetadata::new(metadata)?;
339343

@@ -348,40 +352,40 @@ impl TableCollection {
348352
)
349353
};
350354

351-
handle_tsk_return_value!(rv)
355+
handle_tsk_return_value!(rv, SiteId::from(rv))
352356
}
353357

354358
/// Add a row to the mutation table.
355-
pub fn add_mutation<N: Into<NodeId>>(
359+
pub fn add_mutation<N: Into<NodeId>, M: Into<MutationId>, S: Into<SiteId>>(
356360
&mut self,
357-
site: tsk_id_t,
361+
site: S,
358362
node: N,
359-
parent: tsk_id_t,
363+
parent: M,
360364
time: f64,
361365
derived_state: Option<&[u8]>,
362-
) -> TskReturnValue {
366+
) -> Result<MutationId, TskitError> {
363367
self.add_mutation_with_metadata(site, node, parent, time, derived_state, None)
364368
}
365369

366370
/// Add a row with metadata to the mutation table.
367-
pub fn add_mutation_with_metadata<N: Into<NodeId>>(
371+
pub fn add_mutation_with_metadata<N: Into<NodeId>, M: Into<MutationId>, S: Into<SiteId>>(
368372
&mut self,
369-
site: tsk_id_t,
373+
site: S,
370374
node: N,
371-
parent: tsk_id_t,
375+
parent: M,
372376
time: f64,
373377
derived_state: Option<&[u8]>,
374378
metadata: Option<&dyn MetadataRoundtrip>,
375-
) -> TskReturnValue {
379+
) -> Result<MutationId, TskitError> {
376380
let dstate = process_state_input!(derived_state);
377381
let md = EncodedMetadata::new(metadata)?;
378382

379383
let rv = unsafe {
380384
ll_bindings::tsk_mutation_table_add_row(
381385
&mut (*self.as_mut_ptr()).mutations,
382-
site,
386+
site.into().0,
383387
node.into().0,
384-
parent,
388+
parent.into().0,
385389
time,
386390
dstate.0,
387391
dstate.1,
@@ -390,7 +394,7 @@ impl TableCollection {
390394
)
391395
};
392396

393-
handle_tsk_return_value!(rv)
397+
handle_tsk_return_value!(rv, MutationId::from(rv))
394398
}
395399

396400
/// Add a row to the population_table
@@ -983,7 +987,7 @@ mod test {
983987
.unwrap();
984988
// The double unwrap is to first check for error
985989
// and then to process the Option.
986-
let md = tables.mutations().metadata::<F>(0).unwrap().unwrap();
990+
let md = tables.mutations().metadata::<F>(0.into()).unwrap().unwrap();
987991
assert_eq!(md.x, -3);
988992
assert_eq!(md.y, 666);
989993

@@ -1016,7 +1020,11 @@ mod test {
10161020
let mut num_with_metadata = 0;
10171021
let mut num_without_metadata = 0;
10181022
for i in 0..tables.mutations().num_rows() {
1019-
match tables.mutations().metadata::<F>(i as tsk_id_t).unwrap() {
1023+
match tables
1024+
.mutations()
1025+
.metadata::<F>((i as tsk_id_t).into())
1026+
.unwrap()
1027+
{
10201028
Some(x) => {
10211029
num_with_metadata += 1;
10221030
assert_eq!(x.x, -3);
@@ -1166,7 +1174,7 @@ mod test_bad_metadata {
11661174
tables
11671175
.add_mutation_with_metadata(0, 0, crate::TSK_NULL, 0.0, None, Some(&md))
11681176
.unwrap();
1169-
if tables.mutations().metadata::<Ff>(0).is_ok() {
1177+
if tables.mutations().metadata::<Ff>(0.into()).is_ok() {
11701178
panic!("expected an error!!");
11711179
}
11721180
}

0 commit comments

Comments
 (0)