Skip to content

Commit baf7f84

Browse files
authored
feat: add row_view() for tables (#402)
1 parent 7d84c84 commit baf7f84

File tree

9 files changed

+220
-1
lines changed

9 files changed

+220
-1
lines changed

src/edge_table.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,29 @@ impl EdgeTable {
289289
pub fn row<E: Into<EdgeId> + Copy>(&self, r: E) -> Option<EdgeTableRow> {
290290
table_row_access!(r.into().0, self, make_edge_table_row)
291291
}
292+
293+
/// Return a view of row `r` of the table.
294+
///
295+
/// # Parameters
296+
///
297+
/// * `r`: the row id.
298+
///
299+
/// # Returns
300+
///
301+
/// * `Some(row_view)` if `r` is valid
302+
/// * `None` otherwise
303+
pub fn row_view<E: Into<EdgeId> + Copy>(&self, r: E) -> Option<EdgeTableRowView> {
304+
let view = EdgeTableRowView {
305+
table: self,
306+
id: r.into(),
307+
left: self.left(r)?,
308+
right: self.right(r)?,
309+
parent: self.parent(r)?,
310+
child: self.child(r)?,
311+
metadata: self.raw_metadata(r.into()),
312+
};
313+
Some(view)
314+
}
292315
}
293316

294317
build_owned_table_type!(

src/individual_table.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,28 @@ match tables.individuals().metadata::<MutationMetadata>(0.into())
422422
let ri = r.into().0;
423423
table_row_access!(ri, self, make_individual_table_row)
424424
}
425+
426+
/// Return a view of `r` of the table.
427+
///
428+
/// # Parameters
429+
///
430+
/// * `r`: the row id.
431+
///
432+
/// # Returns
433+
///
434+
/// * `Some(row view)` if `r` is valid
435+
/// * `None` otherwise
436+
pub fn row_view<I: Into<IndividualId> + Copy>(&self, r: I) -> Option<IndividualTableRowView> {
437+
let view = IndividualTableRowView {
438+
table: self,
439+
id: r.into(),
440+
flags: self.flags(r)?,
441+
location: self.location(r),
442+
parents: self.parents(r),
443+
metadata: self.raw_metadata(r.into()),
444+
};
445+
Some(view)
446+
}
425447
}
426448

427449
build_owned_table_type!(

src/migration_table.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,31 @@ impl MigrationTable {
340340
let ri = r.into().0;
341341
table_row_access!(ri, self, make_migration_table_row)
342342
}
343+
344+
/// Return a view of `r` of the table.
345+
///
346+
/// # Parameters
347+
///
348+
/// * `r`: the row id.
349+
///
350+
/// # Returns
351+
///
352+
/// * `Some(row view)` if `r` is valid
353+
/// * `None` otherwise
354+
pub fn row_view<M: Into<MigrationId> + Copy>(&self, r: M) -> Option<MigrationTableRowView> {
355+
let view = MigrationTableRowView {
356+
table: self,
357+
id: r.into(),
358+
left: self.left(r)?,
359+
right: self.right(r)?,
360+
node: self.node(r)?,
361+
source: self.source(r)?,
362+
dest: self.dest(r)?,
363+
time: self.time(r)?,
364+
metadata: self.raw_metadata(r.into()),
365+
};
366+
Some(view)
367+
}
343368
}
344369

345370
build_owned_table_type!(

src/mutation_table.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,30 @@ impl MutationTable {
320320
let ri = r.into().0;
321321
table_row_access!(ri, self, make_mutation_table_row)
322322
}
323+
324+
/// Return a view of row `r` of the table.
325+
///
326+
/// # Parameters
327+
///
328+
/// * `r`: the row id.
329+
///
330+
/// # Returns
331+
///
332+
/// * `Some(row view)` if `r` is valid
333+
/// * `None` otherwise
334+
pub fn row_view<M: Into<MutationId> + Copy>(&self, r: M) -> Option<MutationTableRowView> {
335+
let view = MutationTableRowView {
336+
table: self,
337+
id: r.into(),
338+
site: self.site(r)?,
339+
node: self.node(r)?,
340+
parent: self.parent(r)?,
341+
time: self.time(r)?,
342+
derived_state: self.derived_state(r),
343+
metadata: self.raw_metadata(r.into()),
344+
};
345+
Some(view)
346+
}
323347
}
324348

325349
build_owned_table_type!(

src/node_table.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,28 @@ impl NodeTable {
483483
table_row_access!(ri, self, make_node_table_row)
484484
}
485485

486+
/// Return a view of row `r` of the table.
487+
///
488+
/// # Parameters
489+
///
490+
/// * `r`: the row id.
491+
///
492+
/// # Returns
493+
///
494+
/// * `Some(row view)` if `r` is valid
495+
/// * `None` otherwise
496+
pub fn row_view<N: Into<NodeId> + Copy>(&self, r: N) -> Option<NodeTableRowView> {
497+
let view = NodeTableRowView {
498+
table: self,
499+
id: r.into(),
500+
time: self.time(r)?,
501+
flags: self.flags(r)?,
502+
population: self.population(r)?,
503+
individual: self.individual(r)?,
504+
metadata: self.raw_metadata(r.into()),
505+
};
506+
Some(view)
507+
}
486508
/// Obtain a vector containing the indexes ("ids")
487509
/// of all nodes for which [`crate::TSK_NODE_IS_SAMPLE`]
488510
/// is `true`.

src/population_table.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,30 @@ impl PopulationTable {
191191
let ri = r.into().0;
192192
table_row_access!(ri, self, make_population_table_row)
193193
}
194+
195+
/// Return a view of row `r` of the table.
196+
///
197+
/// # Parameters
198+
///
199+
/// * `r`: the row id.
200+
///
201+
/// # Returns
202+
///
203+
/// * `Some(row view)` if `r` is valid
204+
/// * `None` otherwise
205+
pub fn row_view<P: Into<PopulationId> + Copy>(&self, r: P) -> Option<PopulationTableRowView> {
206+
match SizeType::try_from(r.into().0).ok() {
207+
Some(row) if row < self.num_rows() => {
208+
let view = PopulationTableRowView {
209+
table: self,
210+
id: r.into(),
211+
metadata: self.raw_metadata(r.into()),
212+
};
213+
Some(view)
214+
}
215+
_ => None,
216+
}
217+
}
194218
}
195219

196220
build_owned_table_type!(

src/provenance.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ impl<'a> streaming_iterator::StreamingIterator for ProvenanceTableRowView<'a> {
122122

123123
row_lending_iterator_get!();
124124

125+
// FIXME: bad duplication
125126
fn advance(&mut self) {
126127
self.id = (i32::from(self.id) + 1).into();
127128
let record_slice = unsafe_tsk_ragged_char_column_access_to_slice_u8!(
@@ -262,6 +263,52 @@ impl ProvenanceTable {
262263
make_provenance_row(self, row.into().0)
263264
}
264265

266+
/// Obtain a [`ProvenanceTableRowView`] for row `row`.
267+
///
268+
/// # Returns
269+
///
270+
/// * `Some(row view)` if `r` is valid
271+
/// * `None` otherwise
272+
pub fn row_view<P: Into<ProvenanceId> + Copy>(&self, row: P) -> Option<ProvenanceTableRowView> {
273+
match u64::try_from(row.into().0).ok() {
274+
// FIXME: bad duplication
275+
Some(x) if x < self.num_rows() => {
276+
let record_slice = unsafe_tsk_ragged_char_column_access_to_slice_u8!(
277+
row.into().0,
278+
0,
279+
self.num_rows(),
280+
self.as_ref(),
281+
record,
282+
record_offset,
283+
record_length
284+
);
285+
let timestamp_slice = unsafe_tsk_ragged_char_column_access_to_slice_u8!(
286+
row.into().0,
287+
0,
288+
self.num_rows(),
289+
self.as_ref(),
290+
timestamp,
291+
timestamp_offset,
292+
timestamp_length
293+
);
294+
let view = ProvenanceTableRowView {
295+
table: self,
296+
id: row.into(),
297+
record: match record_slice {
298+
Some(r) => std::str::from_utf8(r).unwrap(),
299+
None => "",
300+
},
301+
timestamp: match timestamp_slice {
302+
Some(t) => std::str::from_utf8(t).unwrap(),
303+
None => "",
304+
},
305+
};
306+
Some(view)
307+
}
308+
_ => None,
309+
}
310+
}
311+
265312
/// Return an iterator over rows of the table.
266313
/// The value of the iterator is [`ProvenanceTableRow`].
267314
pub fn iter(&self) -> impl Iterator<Item = ProvenanceTableRow> + '_ {

src/site_table.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,27 @@ impl SiteTable {
242242
let ri = r.into().0;
243243
table_row_access!(ri, self, make_site_table_row)
244244
}
245+
246+
/// Return a view of row `r` of the table.
247+
///
248+
/// # Parameters
249+
///
250+
/// * `r`: the row id.
251+
///
252+
/// # Returns
253+
///
254+
/// * `Some(row view)` if `r` is valid
255+
/// * `None` otherwise
256+
pub fn row_view<S: Into<SiteId> + Copy>(&self, r: S) -> Option<SiteTableRowView> {
257+
let view = SiteTableRowView {
258+
table: self,
259+
id: r.into(),
260+
position: self.position(r)?,
261+
ancestral_state: self.ancestral_state(r),
262+
metadata: self.raw_metadata(r.into()),
263+
};
264+
Some(view)
265+
}
245266
}
246267

247268
build_owned_table_type!(

tests/test_tables.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ fn test_empty_table_collection() {
33
macro_rules! validate_empty_tables {
44
($tables: ident, $table: ident, $table_iter: ident, $row: expr) => {
55
assert!($tables.$table().row($row).is_none());
6+
assert!($tables.$table().row_view($row).is_none());
67
assert_eq!($tables.$table().num_rows(), 0);
78
assert_eq!($tables.$table().iter().count(), 0);
89
assert_eq!($tables.$table_iter().count(), 0);
@@ -43,6 +44,10 @@ mod test_adding_rows_without_metadata {
4344
// are held in an Option.
4445
match tables.$table().row(id) {
4546
Some(row) => {
47+
match tables.$table().row_view(id) {
48+
Some(view) => assert_eq!(view, row),
49+
None => panic!("if there is a row, there must be a row view")
50+
}
4651
assert!(row.metadata.is_none());
4752

4853
// A row equals itself
@@ -273,7 +278,13 @@ mod test_metadata_round_trips {
273278
assert_eq!($tables.$table().num_rows(), 1);
274279

275280
match $tables.$table().row(id) {
276-
Some(row) => assert!(row.metadata.is_some()),
281+
Some(row) => {
282+
assert!(row.metadata.is_some());
283+
match $tables.$table().row_view(id) {
284+
Some(view) => assert_eq!(row, view),
285+
None => panic!("if there is a row, there must be a view!"),
286+
}
287+
}
277288
None => panic!("Expected Some(row) from {} table", stringify!(table)),
278289
}
279290

0 commit comments

Comments
 (0)