Skip to content

Commit 6bae100

Browse files
authored
Add EdgeId (#138)
1 parent 9baff07 commit 6bae100

File tree

3 files changed

+70
-24
lines changed

3 files changed

+70
-24
lines changed

src/edge_table.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::bindings as ll_bindings;
22
use crate::metadata;
33
use crate::{tsk_id_t, tsk_size_t, TskitError};
4+
use crate::{EdgeId, NodeId};
45

56
/// Row of an [`EdgeTable`]
67
pub struct EdgeTableRow {
7-
pub id: tsk_id_t,
8+
pub id: EdgeId,
89
pub left: f64,
910
pub right: f64,
10-
pub parent: tsk_id_t,
11-
pub child: tsk_id_t,
11+
pub parent: NodeId,
12+
pub child: NodeId,
1213
pub metadata: Option<Vec<u8>>,
1314
}
1415

@@ -26,7 +27,7 @@ impl PartialEq for EdgeTableRow {
2627
fn make_edge_table_row(table: &EdgeTable, pos: tsk_id_t) -> Option<EdgeTableRow> {
2728
if pos < table.num_rows() as tsk_id_t {
2829
let rv = EdgeTableRow {
29-
id: pos,
30+
id: pos.into(),
3031
left: table.left(pos).unwrap(),
3132
right: table.right(pos).unwrap(),
3233
parent: table.parent(pos).unwrap(),
@@ -87,8 +88,8 @@ impl<'a> EdgeTable<'a> {
8788
///
8889
/// Will return [``IndexError``](crate::TskitError::IndexError)
8990
/// if ``row`` is out of range.
90-
pub fn parent(&'a self, row: tsk_id_t) -> Result<tsk_id_t, TskitError> {
91-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.parent)
91+
pub fn parent<E: Into<EdgeId> + Copy>(&'a self, row: E) -> Result<NodeId, TskitError> {
92+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.parent, NodeId)
9293
}
9394

9495
/// Return the ``child`` value from row ``row`` of the table.
@@ -97,8 +98,8 @@ impl<'a> EdgeTable<'a> {
9798
///
9899
/// Will return [``IndexError``](crate::TskitError::IndexError)
99100
/// if ``row`` is out of range.
100-
pub fn child(&'a self, row: tsk_id_t) -> Result<tsk_id_t, TskitError> {
101-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.child)
101+
pub fn child<E: Into<EdgeId> + Copy>(&'a self, row: E) -> Result<NodeId, TskitError> {
102+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.child, NodeId)
102103
}
103104

104105
/// Return the ``left`` value from row ``row`` of the table.
@@ -107,8 +108,8 @@ impl<'a> EdgeTable<'a> {
107108
///
108109
/// Will return [``IndexError``](crate::TskitError::IndexError)
109110
/// if ``row`` is out of range.
110-
pub fn left(&'a self, row: tsk_id_t) -> Result<f64, TskitError> {
111-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.left)
111+
pub fn left<E: Into<EdgeId> + Copy>(&'a self, row: E) -> Result<f64, TskitError> {
112+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.left)
112113
}
113114

114115
/// Return the ``right`` value from row ``row`` of the table.
@@ -117,15 +118,15 @@ impl<'a> EdgeTable<'a> {
117118
///
118119
/// Will return [``IndexError``](crate::TskitError::IndexError)
119120
/// if ``row`` is out of range.
120-
pub fn right(&'a self, row: tsk_id_t) -> Result<f64, TskitError> {
121-
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.right)
121+
pub fn right<E: Into<EdgeId> + Copy>(&'a self, row: E) -> Result<f64, TskitError> {
122+
unsafe_tsk_column_access!(row.into().0, 0, self.num_rows(), self.table_.right)
122123
}
123124

124125
pub fn metadata<T: metadata::MetadataRoundtrip>(
125126
&'a self,
126-
row: tsk_id_t,
127+
row: EdgeId,
127128
) -> Result<Option<T>, TskitError> {
128-
let buffer = metadata_to_vector!(self, row)?;
129+
let buffer = metadata_to_vector!(self, row.0)?;
129130
decode_metadata_row!(T, buffer)
130131
}
131132

@@ -145,7 +146,7 @@ impl<'a> EdgeTable<'a> {
145146
/// # Errors
146147
///
147148
/// [`TskitError::IndexError`] if `r` is out of range.
148-
pub fn row(&self, r: tsk_id_t) -> Result<EdgeTableRow, TskitError> {
149-
table_row_access!(r, self, make_edge_table_row)
149+
pub fn row<E: Into<EdgeId> + Copy>(&self, r: E) -> Result<EdgeTableRow, TskitError> {
150+
table_row_access!(r.into().0, self, make_edge_table_row)
150151
}
151152
}

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,22 @@ pub struct MutationId(tsk_id_t);
187187
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
188188
pub struct MigrationId(tsk_id_t);
189189

190+
/// An edge ID
191+
///
192+
/// This is an integer referring to a row of an [``EdgeTable``].
193+
///
194+
/// The features for this type follow the same pattern as for [``NodeId``]
195+
#[repr(transparent)]
196+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
197+
pub struct EdgeId(tsk_id_t);
198+
190199
impl_id_traits!(NodeId);
191200
impl_id_traits!(IndividualId);
192201
impl_id_traits!(PopulationId);
193202
impl_id_traits!(SiteId);
194203
impl_id_traits!(MutationId);
195204
impl_id_traits!(MigrationId);
205+
impl_id_traits!(EdgeId);
196206

197207
// tskit defines this via a type cast
198208
// in a macro. bindgen thus misses it.

src/table_collection.rs

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

2626
/// A table collection.
@@ -172,7 +172,7 @@ impl TableCollection {
172172
right: f64,
173173
parent: P,
174174
child: C,
175-
) -> TskReturnValue {
175+
) -> Result<EdgeId, TskitError> {
176176
self.add_edge_with_metadata(left, right, parent, child, None)
177177
}
178178

@@ -184,7 +184,7 @@ impl TableCollection {
184184
parent: P,
185185
child: C,
186186
metadata: Option<&dyn MetadataRoundtrip>,
187-
) -> TskReturnValue {
187+
) -> Result<EdgeId, TskitError> {
188188
let md = EncodedMetadata::new(metadata)?;
189189
let rv = unsafe {
190190
ll_bindings::tsk_edge_table_add_row(
@@ -198,7 +198,7 @@ impl TableCollection {
198198
)
199199
};
200200

201-
handle_tsk_return_value!(rv)
201+
handle_tsk_return_value!(rv, EdgeId::from(rv))
202202
}
203203

204204
/// Add a row to the individual table
@@ -440,11 +440,11 @@ impl TableCollection {
440440
/// If `self.is_indexed()` is `true`, return a non-owning
441441
/// slice containing the edge insertion order.
442442
/// Otherwise, return `None`.
443-
pub fn edge_insertion_order(&self) -> Option<&[tsk_id_t]> {
443+
pub fn edge_insertion_order(&self) -> Option<&[EdgeId]> {
444444
if self.is_indexed() {
445445
Some(unsafe {
446446
std::slice::from_raw_parts(
447-
(*self.as_ptr()).indexes.edge_insertion_order,
447+
(*self.as_ptr()).indexes.edge_insertion_order as *const EdgeId,
448448
(*self.as_ptr()).indexes.num_edges as usize,
449449
)
450450
})
@@ -456,11 +456,11 @@ impl TableCollection {
456456
/// If `self.is_indexed()` is `true`, return a non-owning
457457
/// slice containing the edge removal order.
458458
/// Otherwise, return `None`.
459-
pub fn edge_removal_order(&self) -> Option<&[tsk_id_t]> {
459+
pub fn edge_removal_order(&self) -> Option<&[EdgeId]> {
460460
if self.is_indexed() {
461461
Some(unsafe {
462462
std::slice::from_raw_parts(
463-
(*self.as_ptr()).indexes.edge_removal_order,
463+
(*self.as_ptr()).indexes.edge_removal_order as *const EdgeId,
464464
(*self.as_ptr()).indexes.num_edges as usize,
465465
)
466466
})
@@ -803,6 +803,41 @@ mod test {
803803
assert!(*i >= 0);
804804
assert!(*i < tables.edges().num_rows() as tsk_id_t);
805805
}
806+
807+
// The "transparent" casts are such black magic that we
808+
// should probably test against what C thinks is going on :)
809+
let input = unsafe {
810+
std::slice::from_raw_parts(
811+
(*tables.as_ptr()).indexes.edge_insertion_order,
812+
(*tables.as_ptr()).indexes.num_edges as usize,
813+
)
814+
};
815+
816+
assert!(!input.is_empty());
817+
818+
let tables_input = tables.edge_insertion_order().unwrap();
819+
820+
assert_eq!(input.len(), tables_input.len());
821+
822+
for i in 0..input.len() {
823+
assert_eq!(EdgeId::from(input[i]), tables_input[i]);
824+
}
825+
826+
let output = unsafe {
827+
std::slice::from_raw_parts(
828+
(*tables.as_ptr()).indexes.edge_removal_order,
829+
(*tables.as_ptr()).indexes.num_edges as usize,
830+
)
831+
};
832+
assert!(!output.is_empty());
833+
834+
let tables_output = tables.edge_removal_order().unwrap();
835+
836+
assert_eq!(output.len(), tables_output.len());
837+
838+
for i in 0..output.len() {
839+
assert_eq!(EdgeId::from(output[i]), tables_output[i]);
840+
}
806841
}
807842

808843
#[test]

0 commit comments

Comments
 (0)