Skip to content

Commit 7352ca9

Browse files
committed
Update table operations to metadata API.
1 parent 275074d commit 7352ca9

File tree

6 files changed

+180
-67
lines changed

6 files changed

+180
-67
lines changed

src/edge_table.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::bindings as ll_bindings;
2+
use crate::metadata;
23
use crate::{tsk_id_t, tsk_size_t, TskitRustError};
34

45
/// An immutable view of an edge table.
@@ -59,4 +60,12 @@ impl<'a> EdgeTable<'a> {
5960
pub fn right(&'a self, row: tsk_id_t) -> Result<f64, TskitRustError> {
6061
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.right);
6162
}
63+
64+
pub fn metadata<T: metadata::MetadataRoundtrip>(
65+
&'a self,
66+
row: tsk_id_t,
67+
) -> Result<Option<T>, TskitRustError> {
68+
let buffer = metadata_to_vector!(T, self, row);
69+
decode_metadata_row!(T, buffer)
70+
}
6271
}

src/mutation_table.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::bindings as ll_bindings;
2+
use crate::metadata;
23
use crate::{tsk_id_t, tsk_size_t, TskitRustError};
34

45
/// An immutable view of site table.
@@ -71,25 +72,20 @@ impl<'a> MutationTable<'a> {
7172
/// Will return [``IndexError``](crate::TskitRustError::IndexError)
7273
/// if ``row`` is out of range.
7374
pub fn derived_state(&'a self, row: tsk_id_t) -> Result<Option<Vec<u8>>, TskitRustError> {
74-
if row < 0 || (row as tsk_size_t) >= self.num_rows() {
75-
return Err(TskitRustError::IndexError {});
76-
}
77-
if self.table_.derived_state_length == 0 {
78-
return Ok(None);
79-
}
80-
let start = unsafe { *self.table_.derived_state_offset.offset(row as isize) };
81-
let stop = if (row as tsk_size_t) < self.table_.num_rows {
82-
unsafe { *self.table_.derived_state_offset.offset((row + 1) as isize) }
83-
} else {
84-
self.table_.derived_state_length
85-
};
86-
if stop - start == 0 {
87-
return Ok(None);
88-
}
89-
let mut buffer: Vec<u8> = vec![];
90-
for i in start..stop {
91-
buffer.push(unsafe { *self.table_.derived_state.offset(i as isize) } as u8);
92-
}
93-
Ok(Some(buffer))
75+
metadata::char_column_to_vector(
76+
self.table_.derived_state,
77+
self.table_.derived_state_offset,
78+
row,
79+
self.table_.num_rows,
80+
self.table_.derived_state_length,
81+
)
82+
}
83+
84+
pub fn metadata<T: metadata::MetadataRoundtrip>(
85+
&'a self,
86+
row: tsk_id_t,
87+
) -> Result<Option<T>, TskitRustError> {
88+
let buffer = metadata_to_vector!(T, self, row);
89+
decode_metadata_row!(T, buffer)
9490
}
9591
}

src/node_table.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::bindings as ll_bindings;
2+
use crate::metadata;
23
use crate::{tsk_flags_t, tsk_id_t, TskitRustError};
34

45
/// An immtable view of a node table.
@@ -69,4 +70,12 @@ impl<'a> NodeTable<'a> {
6970
pub fn individual(&'a self, row: tsk_id_t) -> Result<tsk_id_t, TskitRustError> {
7071
unsafe_tsk_column_access!(row, 0, self.num_rows(), self.table_.individual);
7172
}
73+
74+
pub fn metadata<T: metadata::MetadataRoundtrip>(
75+
&'a self,
76+
row: tsk_id_t,
77+
) -> Result<Option<T>, TskitRustError> {
78+
let buffer = metadata_to_vector!(T, self, row);
79+
decode_metadata_row!(T, buffer)
80+
}
7281
}

src/population_table.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::bindings as ll_bindings;
2-
use crate::tsk_size_t;
2+
use crate::metadata;
3+
use crate::TskitRustError;
4+
use crate::{tsk_id_t, tsk_size_t};
35

46
/// An immutable view of site table.
57
///
@@ -19,4 +21,12 @@ impl<'a> PopulationTable<'a> {
1921
pub fn num_rows(&'a self) -> tsk_size_t {
2022
self.table_.num_rows
2123
}
24+
25+
pub fn metadata<T: metadata::MetadataRoundtrip>(
26+
&'a self,
27+
row: tsk_id_t,
28+
) -> Result<Option<T>, TskitRustError> {
29+
let buffer = metadata_to_vector!(T, self, row);
30+
decode_metadata_row!(T, buffer)
31+
}
2232
}

src/site_table.rs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::bindings as ll_bindings;
2+
use crate::metadata;
23
use crate::TskitRustError;
34
use crate::{tsk_id_t, tsk_size_t};
45

@@ -42,30 +43,20 @@ impl<'a> SiteTable<'a> {
4243
/// Will return [``IndexError``](crate::TskitRustError::IndexError)
4344
/// if ``row`` is out of range.
4445
pub fn ancestral_state(&'a self, row: tsk_id_t) -> Result<Option<Vec<u8>>, TskitRustError> {
45-
if row < 0 || (row as tsk_size_t) >= self.num_rows() {
46-
return Err(TskitRustError::IndexError {});
47-
}
48-
if self.table_.ancestral_state_length == 0 {
49-
return Ok(None);
50-
}
51-
let start = unsafe { *self.table_.ancestral_state_offset.offset(row as isize) };
52-
let stop = if (row as tsk_size_t) < self.table_.num_rows {
53-
unsafe {
54-
*self
55-
.table_
56-
.ancestral_state_offset
57-
.offset((row + 1) as isize)
58-
}
59-
} else {
60-
self.table_.ancestral_state_length
61-
};
62-
if stop - start == 0 {
63-
return Ok(None);
64-
}
65-
let mut buffer: Vec<u8> = vec![];
66-
for i in start..stop {
67-
buffer.push(unsafe { *self.table_.ancestral_state.offset(i as isize) } as u8);
68-
}
69-
Ok(Some(buffer))
46+
crate::metadata::char_column_to_vector(
47+
self.table_.ancestral_state,
48+
self.table_.ancestral_state_offset,
49+
row,
50+
self.table_.num_rows,
51+
self.table_.ancestral_state_length,
52+
)
53+
}
54+
55+
pub fn metadata<T: metadata::MetadataRoundtrip>(
56+
&'a self,
57+
row: tsk_id_t,
58+
) -> Result<Option<T>, TskitRustError> {
59+
let buffer = metadata_to_vector!(T, self, row);
60+
decode_metadata_row!(T, buffer)
7061
}
7162
}

src/table_collection.rs

Lines changed: 119 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::bindings as ll_bindings;
22
use crate::error::TskitRustError;
33
use crate::ffi::TskitType;
4+
use crate::metadata::*;
45
use crate::types::Bookmark;
56
use crate::EdgeTable;
67
use crate::MutationTable;
78
use crate::NodeTable;
89
use crate::PopulationTable;
910
use crate::SiteTable;
1011
use crate::TskReturnValue;
11-
use crate::{tsk_flags_t, tsk_id_t, tsk_size_t};
12+
use crate::{tsk_flags_t, tsk_id_t};
1213
use ll_bindings::tsk_table_collection_free;
1314

1415
/// A table collection.
@@ -159,15 +160,28 @@ impl TableCollection {
159160
parent: tsk_id_t,
160161
child: tsk_id_t,
161162
) -> TskReturnValue {
163+
self.add_edge_with_metadata(left, right, parent, child, None)
164+
}
165+
166+
/// Add a row with metadata to the edge table
167+
pub fn add_edge_with_metadata(
168+
&mut self,
169+
left: f64,
170+
right: f64,
171+
parent: tsk_id_t,
172+
child: tsk_id_t,
173+
metadata: Option<&dyn MetadataRoundtrip>,
174+
) -> TskReturnValue {
175+
let md = EncodedMetadata::new(metadata)?;
162176
let rv = unsafe {
163177
ll_bindings::tsk_edge_table_add_row(
164178
&mut (*self.as_mut_ptr()).edges,
165179
left,
166180
right,
167181
parent,
168182
child,
169-
std::ptr::null(),
170-
0,
183+
md.as_ptr(),
184+
md.len(),
171185
)
172186
};
173187

@@ -182,15 +196,28 @@ impl TableCollection {
182196
population: tsk_id_t,
183197
individual: tsk_id_t,
184198
) -> TskReturnValue {
199+
self.add_node_witha_metadata(flags, time, population, individual, None)
200+
}
201+
202+
/// Add a row with metadata to the node table
203+
pub fn add_node_witha_metadata(
204+
&mut self,
205+
flags: ll_bindings::tsk_flags_t,
206+
time: f64,
207+
population: tsk_id_t,
208+
individual: tsk_id_t,
209+
metadata: Option<&dyn MetadataRoundtrip>,
210+
) -> TskReturnValue {
211+
let md = EncodedMetadata::new(metadata)?;
185212
let rv = unsafe {
186213
ll_bindings::tsk_node_table_add_row(
187214
&mut (*self.as_mut_ptr()).nodes,
188215
flags,
189216
time,
190217
population,
191218
individual,
192-
std::ptr::null(),
193-
0,
219+
md.as_ptr(),
220+
md.len(),
194221
)
195222
};
196223

@@ -199,19 +226,27 @@ impl TableCollection {
199226

200227
/// Add a row to the site table
201228
pub fn add_site(&mut self, position: f64, ancestral_state: Option<&[u8]>) -> TskReturnValue {
202-
let astate = match ancestral_state {
203-
Some(x) => (std::ffi::CString::new(x).unwrap(), x.len() as tsk_size_t),
204-
None => (std::ffi::CString::new("".to_string()).unwrap(), 0),
205-
};
229+
self.add_site_with_metadata(position, ancestral_state, None)
230+
}
231+
232+
/// Add a row with metadata to the site table
233+
pub fn add_site_with_metadata(
234+
&mut self,
235+
position: f64,
236+
ancestral_state: Option<&[u8]>,
237+
metadata: Option<&dyn MetadataRoundtrip>,
238+
) -> TskReturnValue {
239+
let astate = process_state_input!(ancestral_state);
240+
let md = EncodedMetadata::new(metadata)?;
206241

207242
let rv = unsafe {
208243
ll_bindings::tsk_site_table_add_row(
209244
&mut (*self.as_mut_ptr()).sites,
210245
position,
211-
astate.0.as_ptr(),
246+
astate.0,
212247
astate.1,
213-
std::ptr::null(),
214-
0,
248+
md.as_ptr(),
249+
md.len(),
215250
)
216251
};
217252

@@ -227,10 +262,21 @@ impl TableCollection {
227262
time: f64,
228263
derived_state: Option<&[u8]>,
229264
) -> TskReturnValue {
230-
let dstate = match derived_state {
231-
Some(x) => (std::ffi::CString::new(x).unwrap(), x.len() as tsk_size_t),
232-
None => (std::ffi::CString::new("".to_string()).unwrap(), 0),
233-
};
265+
self.add_mutation_with_metadata(site, node, parent, time, derived_state, None)
266+
}
267+
268+
/// Add a row with metadata to the mutation table.
269+
pub fn add_mutation_with_metadata(
270+
&mut self,
271+
site: tsk_id_t,
272+
node: tsk_id_t,
273+
parent: tsk_id_t,
274+
time: f64,
275+
derived_state: Option<&[u8]>,
276+
metadata: Option<&dyn MetadataRoundtrip>,
277+
) -> TskReturnValue {
278+
let dstate = process_state_input!(derived_state);
279+
let md = EncodedMetadata::new(metadata)?;
234280

235281
let rv = unsafe {
236282
ll_bindings::tsk_mutation_table_add_row(
@@ -239,10 +285,10 @@ impl TableCollection {
239285
node,
240286
parent,
241287
time,
242-
dstate.0.as_ptr(),
288+
dstate.0,
243289
dstate.1,
244-
std::ptr::null(),
245-
0,
290+
md.as_ptr(),
291+
md.len(),
246292
)
247293
};
248294

@@ -251,11 +297,20 @@ impl TableCollection {
251297

252298
/// Add a row to the population_table
253299
pub fn add_population(&mut self) -> TskReturnValue {
300+
self.add_population_with_metadata(None)
301+
}
302+
303+
/// Add a row with metadata to the population_table
304+
pub fn add_population_with_metadata(
305+
&mut self,
306+
metadata: Option<&dyn MetadataRoundtrip>,
307+
) -> TskReturnValue {
308+
let md = EncodedMetadata::new(metadata)?;
254309
let rv = unsafe {
255310
ll_bindings::tsk_population_table_add_row(
256311
&mut (*self.as_mut_ptr()).populations,
257-
std::ptr::null(),
258-
0,
312+
md.as_ptr(),
313+
md.len(),
259314
)
260315
};
261316

@@ -433,6 +488,49 @@ mod test {
433488
);
434489
}
435490

491+
struct F {
492+
x: i32,
493+
y: u32,
494+
}
495+
496+
impl MetadataRoundtrip for F {
497+
fn encode(&self) -> Result<Vec<u8>, MetadataError> {
498+
let mut rv = vec![];
499+
rv.extend(self.x.to_le_bytes().iter().map(|&i| i));
500+
rv.extend(self.y.to_le_bytes().iter().map(|&i| i));
501+
Ok(rv)
502+
}
503+
fn decode(md: &[u8]) -> Result<Self, MetadataError> {
504+
use std::convert::TryInto;
505+
let (x_int_bytes, rest) = md.split_at(std::mem::size_of::<i32>());
506+
let (y_int_bytes, _) = rest.split_at(std::mem::size_of::<u32>());
507+
Ok(Self {
508+
x: i32::from_le_bytes(x_int_bytes.try_into().unwrap()),
509+
y: u32::from_le_bytes(y_int_bytes.try_into().unwrap()),
510+
})
511+
}
512+
}
513+
514+
#[test]
515+
fn test_add_mutation_with_metadata() {
516+
let mut tables = TableCollection::new(1000.).unwrap();
517+
tables
518+
.add_mutation_with_metadata(
519+
0,
520+
0,
521+
crate::TSK_NULL,
522+
1.123,
523+
None,
524+
Some(&F { x: -3, y: 666 }),
525+
)
526+
.unwrap();
527+
// The double unwrap is to first check for error
528+
// and then to process the Option.
529+
let md = tables.mutations().metadata::<F>(0).unwrap().unwrap();
530+
assert_eq!(md.x, -3);
531+
assert_eq!(md.y, 666);
532+
}
533+
436534
#[test]
437535
fn test_add_population() {
438536
let mut tables = TableCollection::new(1000.).unwrap();

0 commit comments

Comments
 (0)