Skip to content

Commit 7ed2b9f

Browse files
authored
feat: column slice getters for tables (#404)
1 parent aa94e1e commit 7ed2b9f

File tree

8 files changed

+285
-7
lines changed

8 files changed

+285
-7
lines changed

src/_macros.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,38 @@ macro_rules! optional_container_comparison {
11591159
};
11601160
}
11611161

1162+
macro_rules! build_table_column_slice_getter {
1163+
($(#[$attr:meta])* => $column: ident, $name: ident, $cast: ty) => {
1164+
$(#[$attr])*
1165+
pub fn $name(&self) -> &[$cast] {
1166+
// Caveat: num_rows is u64 but we need usize
1167+
// The conversion is fallible but unlikely.
1168+
let num_rows =
1169+
usize::try_from(self.num_rows()).expect("conversion of num_rows to usize failed");
1170+
let ptr = self.as_ref().$column as *const $cast;
1171+
// SAFETY: tables are initialzed, num rows comes
1172+
// from the C back end.
1173+
unsafe { std::slice::from_raw_parts(ptr, num_rows) }
1174+
}
1175+
};
1176+
}
1177+
1178+
macro_rules! build_table_column_slice_mut_getter {
1179+
($(#[$attr:meta])* => $column: ident, $name: ident, $cast: ty) => {
1180+
$(#[$attr])*
1181+
pub fn $name(&mut self) -> &mut [$cast] {
1182+
// Caveat: num_rows is u64 but we need usize
1183+
// The conversion is fallible but unlikely.
1184+
let num_rows =
1185+
usize::try_from(self.num_rows()).expect("conversion of num_rows to usize failed");
1186+
let ptr = self.as_ref().$column as *mut $cast;
1187+
// SAFETY: tables are initialzed, num rows comes
1188+
// from the C back end.
1189+
unsafe { std::slice::from_raw_parts_mut(ptr, num_rows) }
1190+
}
1191+
};
1192+
}
1193+
11621194
#[cfg(test)]
11631195
mod test {
11641196
use crate::error::TskitError;

src/edge_table.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,31 @@ impl EdgeTable {
312312
};
313313
Some(view)
314314
}
315+
316+
build_table_column_slice_getter!(
317+
/// Get the left column as a slice
318+
=> left, left_slice, Position);
319+
build_table_column_slice_getter!(
320+
/// Get the left column as a slice of [`f64`]
321+
=> left, left_slice_raw, f64);
322+
build_table_column_slice_getter!(
323+
/// Get the right column as a slice
324+
=> right, right_slice, Position);
325+
build_table_column_slice_getter!(
326+
/// Get the left column as a slice of [`f64`]
327+
=> right, right_slice_raw, f64);
328+
build_table_column_slice_getter!(
329+
/// Get the parent column as a slice
330+
=> parent, parent_slice, NodeId);
331+
build_table_column_slice_getter!(
332+
/// Get the parent column as a slice of [`crate::bindings::tsk_id_t`]
333+
=> parent, parent_slice_raw, ll_bindings::tsk_id_t);
334+
build_table_column_slice_getter!(
335+
/// Get the child column as a slice
336+
=> child, child_slice, NodeId);
337+
build_table_column_slice_getter!(
338+
/// Get the child column as a slice of [`crate::bindings::tsk_id_t`]
339+
=> child, child_slice_raw, ll_bindings::tsk_id_t);
315340
}
316341

317342
build_owned_table_type!(

src/individual_table.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,13 @@ match tables.individuals().metadata::<MutationMetadata>(0.into())
444444
};
445445
Some(view)
446446
}
447+
448+
build_table_column_slice_getter!(
449+
/// Get the flags column as a slice
450+
=> flags, flags_slice, IndividualFlags);
451+
build_table_column_slice_getter!(
452+
/// Get the flags column as a slice
453+
=> flags, flags_slice_raw, ll_bindings::tsk_flags_t);
447454
}
448455

449456
build_owned_table_type!(

src/migration_table.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,43 @@ impl MigrationTable {
365365
};
366366
Some(view)
367367
}
368+
369+
build_table_column_slice_getter!(
370+
/// Get the left column as a slice
371+
=> left, left_slice, Position);
372+
build_table_column_slice_getter!(
373+
/// Get the left column as a slice
374+
=> left, left_slice_raw, f64);
375+
build_table_column_slice_getter!(
376+
/// Get the right column as a slice
377+
=> right, right_slice, Position);
378+
build_table_column_slice_getter!(
379+
/// Get the right column as a slice
380+
=> right, right_slice_raw, f64);
381+
build_table_column_slice_getter!(
382+
/// Get the time column as a slice
383+
=> time, time_slice, Time);
384+
build_table_column_slice_getter!(
385+
/// Get the time column as a slice
386+
=> time, time_slice_raw, f64);
387+
build_table_column_slice_getter!(
388+
/// Get the node column as a slice
389+
=> node, node_slice, NodeId);
390+
build_table_column_slice_getter!(
391+
/// Get the node column as a slice
392+
=> node, node_slice_raw, ll_bindings::tsk_id_t);
393+
build_table_column_slice_getter!(
394+
/// Get the source column as a slice
395+
=> source, source_slice, PopulationId);
396+
build_table_column_slice_getter!(
397+
/// Get the source column as a slice
398+
=> source, source_slice_raw, ll_bindings::tsk_id_t);
399+
build_table_column_slice_getter!(
400+
/// Get the dest column as a slice
401+
=> dest, dest_slice, PopulationId);
402+
build_table_column_slice_getter!(
403+
/// Get the dest column as a slice
404+
=> dest, dest_slice_raw, ll_bindings::tsk_id_t);
368405
}
369406

370407
build_owned_table_type!(

src/mutation_table.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,31 @@ impl MutationTable {
344344
};
345345
Some(view)
346346
}
347+
348+
build_table_column_slice_getter!(
349+
/// Get the node column as a slice
350+
=> node, node_slice, NodeId);
351+
build_table_column_slice_getter!(
352+
/// Get the node column as a slice
353+
=> node, node_slice_raw, crate::tsk_id_t);
354+
build_table_column_slice_getter!(
355+
/// Get the site column as a slice
356+
=> site, site_slice, SiteId);
357+
build_table_column_slice_getter!(
358+
/// Get the site column as a slice
359+
=> site, site_slice_raw, crate::tsk_id_t);
360+
build_table_column_slice_getter!(
361+
/// Get the time column as a slice
362+
=> time, time_slice, Time);
363+
build_table_column_slice_getter!(
364+
/// Get the time column as a slice
365+
=> time, time_slice_raw, f64);
366+
build_table_column_slice_getter!(
367+
/// Get the parent column as a slice
368+
=> parent, parent_slice, MutationId);
369+
build_table_column_slice_getter!(
370+
/// Get the parent column as a slice
371+
=> parent, parent_slice_raw, crate::tsk_id_t);
347372
}
348373

349374
build_owned_table_type!(

src/node_table.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,43 @@ impl NodeTable {
520520
.map(|row| row.id)
521521
.collect::<Vec<_>>()
522522
}
523+
524+
build_table_column_slice_getter!(
525+
/// Get the time column as a slice
526+
=> time, time_slice, Time);
527+
build_table_column_slice_getter!(
528+
/// Get the time column as a slice
529+
=> time, time_slice_raw, f64);
530+
build_table_column_slice_mut_getter!(
531+
/// Get the time column as a mutable slice
532+
=> time, time_slice_mut, Time);
533+
build_table_column_slice_mut_getter!(
534+
/// Get the time column as a mutable slice
535+
=> time, time_slice_raw_mut, f64);
536+
build_table_column_slice_getter!(
537+
/// Get the flags column as a slice
538+
=> flags, flags_slice, NodeFlags);
539+
build_table_column_slice_getter!(
540+
/// Get the flags column as a slice
541+
=> flags, flags_slice_raw, ll_bindings::tsk_flags_t);
542+
build_table_column_slice_mut_getter!(
543+
/// Get the flags column as a mutable slice
544+
=> flags, flags_slice_mut, NodeFlags);
545+
build_table_column_slice_mut_getter!(
546+
/// Get the flags column as a mutable slice
547+
=> flags, flags_slice_raw_mut, ll_bindings::tsk_flags_t);
548+
build_table_column_slice_getter!(
549+
/// Get the individual column as a slice
550+
=> individual, individual_slice, IndividualId);
551+
build_table_column_slice_getter!(
552+
/// Get the individual column as a slice
553+
=> individual, individual_slice_raw, crate::tsk_id_t);
554+
build_table_column_slice_getter!(
555+
/// Get the population column as a slice
556+
=> population, population_slice, PopulationId);
557+
build_table_column_slice_getter!(
558+
/// Get the population column as a slice
559+
=> population, population_slice_raw, crate::tsk_id_t);
523560
}
524561

525562
build_owned_table_type!(

src/site_table.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,13 @@ impl SiteTable {
263263
};
264264
Some(view)
265265
}
266+
267+
build_table_column_slice_getter!(
268+
/// Get the position column as a slice
269+
=> position, position_slice, Position);
270+
build_table_column_slice_getter!(
271+
/// Get the position column as a slice
272+
=> position, position_slice_raw, f64);
266273
}
267274

268275
build_owned_table_type!(

tests/test_tables.rs

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,58 @@ mod test_adding_rows_without_metadata {
7171
Err(e) => panic!("Err from tables.{}: {:?}", stringify!(adder), e)
7272
}
7373
assert_eq!(tables.$table().iter().count(), 2);
74+
tables
7475
}
7576
}};
7677
}
7778

79+
macro_rules! compare_column_to_raw_column {
80+
($table: expr, $col: ident, $raw: ident) => {
81+
assert_eq!(
82+
$table.$col().len(),
83+
usize::try_from($table.num_rows()).unwrap()
84+
);
85+
assert_eq!(
86+
$table.$raw().len(),
87+
usize::try_from($table.num_rows()).unwrap()
88+
);
89+
assert!($table
90+
.$col()
91+
.iter()
92+
.zip($table.$raw().iter())
93+
.all(|(a, b)| a == b))
94+
};
95+
}
96+
97+
macro_rules! compare_column_to_row {
98+
($table: expr, $col: ident, $target: ident) => {
99+
assert!($table
100+
.$col()
101+
.iter()
102+
.zip($table.iter())
103+
.all(|(c, r)| c == &r.$target));
104+
};
105+
}
106+
78107
// NOTE: all functions arguments for adding rows are Into<T>
79108
// where T is one of our new types.
80109
// Further, functions taking multiple inputs of T are defined
81110
// as X: Into<T>, X2: Into<T>, etc., allowing mix-and-match.
82111

83112
#[test]
84113
fn test_adding_edge() {
85-
add_row_without_metadata!(edges, add_edge, 0.1, 0.5, 0, 1); // left, right, parent, child
114+
{
115+
let tables = add_row_without_metadata!(edges, add_edge, 0.1, 0.5, 0, 1); // left, right, parent, child
116+
compare_column_to_raw_column!(tables.edges(), left_slice, left_slice_raw);
117+
compare_column_to_raw_column!(tables.edges(), right_slice, right_slice_raw);
118+
compare_column_to_raw_column!(tables.edges(), parent_slice, parent_slice_raw);
119+
compare_column_to_raw_column!(tables.edges(), child_slice, child_slice_raw);
120+
121+
compare_column_to_row!(tables.edges(), left_slice, left);
122+
compare_column_to_row!(tables.edges(), right_slice, right);
123+
compare_column_to_row!(tables.edges(), parent_slice, parent);
124+
compare_column_to_row!(tables.edges(), child_slice, child);
125+
}
86126
add_row_without_metadata!(edges, add_edge, tskit::Position::from(0.1), 0.5, 0, 1); // left, right, parent, child
87127
add_row_without_metadata!(edges, add_edge, 0.1, tskit::Position::from(0.5), 0, 1); // left, right, parent, child
88128
add_row_without_metadata!(
@@ -105,8 +145,30 @@ mod test_adding_rows_without_metadata {
105145

106146
#[test]
107147
fn test_adding_node() {
108-
add_row_without_metadata!(nodes, add_node, 0, 0.1, -1, -1); // flags, time, population,
109-
// individual
148+
{
149+
let tables =
150+
add_row_without_metadata!(nodes, add_node, tskit::TSK_NODE_IS_SAMPLE, 0.1, -1, -1); // flags, time, population,
151+
// individual
152+
assert!(tables
153+
.nodes()
154+
.flags_slice()
155+
.iter()
156+
.zip(tables.nodes().flags_slice_raw().iter())
157+
.all(|(a, b)| a.bits() == *b));
158+
compare_column_to_raw_column!(tables.nodes(), time_slice, time_slice_raw);
159+
compare_column_to_raw_column!(tables.nodes(), population_slice, population_slice_raw);
160+
compare_column_to_raw_column!(tables.nodes(), individual_slice, individual_slice_raw);
161+
162+
assert!(tables
163+
.nodes()
164+
.flags_slice()
165+
.iter()
166+
.zip(tables.nodes().iter())
167+
.all(|(c, r)| c == &r.flags));
168+
compare_column_to_row!(tables.nodes(), time_slice, time);
169+
compare_column_to_row!(tables.nodes(), population_slice, population);
170+
compare_column_to_row!(tables.nodes(), individual_slice, individual);
171+
}
110172
add_row_without_metadata!(
111173
nodes,
112174
add_node,
@@ -120,7 +182,11 @@ mod test_adding_rows_without_metadata {
120182
#[test]
121183
fn test_adding_site() {
122184
// No ancestral state
123-
add_row_without_metadata!(sites, add_site, 2. / 3., None);
185+
{
186+
let tables = add_row_without_metadata!(sites, add_site, 2. / 3., None);
187+
compare_column_to_raw_column!(tables.sites(), position_slice, position_slice_raw);
188+
compare_column_to_row!(tables.sites(), position_slice, position);
189+
}
124190
add_row_without_metadata!(sites, add_site, tskit::Position::from(2. / 3.), None);
125191
add_row_without_metadata!(sites, add_site, 2. / 3., Some(&[1_u8]));
126192
add_row_without_metadata!(
@@ -136,14 +202,40 @@ mod test_adding_rows_without_metadata {
136202
// site, node, parent mutation, time, derived_state
137203
// Each value is a different Into<T> so we skip doing
138204
// permutations
139-
add_row_without_metadata!(mutations, add_mutation, 0, 0, -1, 0.0, None);
205+
{
206+
let tables = add_row_without_metadata!(mutations, add_mutation, 0, 0, -1, 0.0, None);
207+
compare_column_to_raw_column!(tables.mutations(), node_slice, node_slice_raw);
208+
compare_column_to_raw_column!(tables.mutations(), time_slice, time_slice_raw);
209+
compare_column_to_raw_column!(tables.mutations(), site_slice, site_slice_raw);
210+
compare_column_to_raw_column!(tables.mutations(), parent_slice, parent_slice_raw);
211+
212+
compare_column_to_row!(tables.mutations(), node_slice, node);
213+
compare_column_to_row!(tables.mutations(), time_slice, time);
214+
compare_column_to_row!(tables.mutations(), site_slice, site);
215+
compare_column_to_row!(tables.mutations(), parent_slice, parent);
216+
}
217+
140218
add_row_without_metadata!(mutations, add_mutation, 0, 0, -1, 0.0, Some(&[23_u8]));
141219
}
142220

143221
#[test]
144222
fn test_adding_individual() {
145223
// flags, location, parents
146-
add_row_without_metadata!(individuals, add_individual, 0, None, None);
224+
{
225+
let tables = add_row_without_metadata!(individuals, add_individual, 0, None, None);
226+
assert!(tables
227+
.individuals()
228+
.flags_slice()
229+
.iter()
230+
.zip(tables.individuals().flags_slice_raw().iter())
231+
.all(|(a, b)| a.bits() == *b));
232+
assert!(tables
233+
.individuals()
234+
.flags_slice()
235+
.iter()
236+
.zip(tables.individuals().iter())
237+
.all(|(c, r)| c == &r.flags));
238+
}
147239
add_row_without_metadata!(
148240
individuals,
149241
add_individual,
@@ -179,7 +271,23 @@ mod test_adding_rows_without_metadata {
179271
fn test_adding_migration() {
180272
// migration table
181273
// (left, right), node, (source, dest), time
182-
add_row_without_metadata!(migrations, add_migration, (0., 1.), 0, (0, 1), 0.0);
274+
{
275+
let tables =
276+
add_row_without_metadata!(migrations, add_migration, (0., 1.), 0, (0, 1), 0.0);
277+
compare_column_to_raw_column!(tables.migrations(), left_slice, left_slice_raw);
278+
compare_column_to_raw_column!(tables.migrations(), right_slice, right_slice_raw);
279+
compare_column_to_raw_column!(tables.migrations(), node_slice, node_slice_raw);
280+
compare_column_to_raw_column!(tables.migrations(), time_slice, time_slice_raw);
281+
compare_column_to_raw_column!(tables.migrations(), source_slice, source_slice_raw);
282+
compare_column_to_raw_column!(tables.migrations(), dest_slice, dest_slice_raw);
283+
284+
compare_column_to_row!(tables.migrations(), left_slice, left);
285+
compare_column_to_row!(tables.migrations(), right_slice, right);
286+
compare_column_to_row!(tables.migrations(), node_slice, node);
287+
compare_column_to_row!(tables.migrations(), time_slice, time);
288+
compare_column_to_row!(tables.migrations(), source_slice, source);
289+
compare_column_to_row!(tables.migrations(), dest_slice, dest);
290+
}
183291
add_row_without_metadata!(
184292
migrations,
185293
add_migration,

0 commit comments

Comments
 (0)