Skip to content

Commit a780068

Browse files
committed
feat: add tskit::OwnedEdgeTable
1 parent 9a664f8 commit a780068

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

src/edge_table.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ impl<'a> Iterator for EdgeTableIterator<'a> {
7474
/// These are not created directly.
7575
/// Instead, use [`TableAccess::edges`](crate::TableAccess::edges)
7676
/// to get a reference to an existing edge table;
77+
#[repr(transparent)]
7778
pub struct EdgeTable<'a> {
7879
table_: &'a ll_bindings::tsk_edge_table_t,
7980
}
@@ -167,3 +168,129 @@ impl<'a> EdgeTable<'a> {
167168
table_row_access!(ri.0, self, make_edge_table_row)
168169
}
169170
}
171+
172+
/// A standalone edge table that owns its data.
173+
///
174+
/// # Examples
175+
///
176+
/// ```
177+
/// use tskit::OwnedEdgeTable;
178+
///
179+
/// let mut edges = OwnedEdgeTable::default();
180+
/// let rowid = edges.add_row(1., 2., 0, 1).unwrap();
181+
/// assert_eq!(rowid, 0);
182+
/// assert_eq!(edges.num_rows(), 1);
183+
/// ```
184+
///
185+
/// An example with metadata.
186+
/// This requires the cargo feature `"derive"` for `tskit`.
187+
///
188+
/// ```
189+
/// # #[cfg(any(feature="doc", feature="derive"))] {
190+
/// use tskit::OwnedEdgeTable;
191+
///
192+
/// #[derive(serde::Serialize,
193+
/// serde::Deserialize,
194+
/// tskit::metadata::EdgeMetadata)]
195+
/// #[serializer("serde_json")]
196+
/// struct EdgeMetadata {
197+
/// value: i32,
198+
/// }
199+
///
200+
/// let metadata = EdgeMetadata{value: 42};
201+
///
202+
/// let mut edges = OwnedEdgeTable::default();
203+
///
204+
/// let rowid = edges.add_row_with_metadata(0., 1., 5, 10, &metadata).unwrap();
205+
/// assert_eq!(rowid, 0);
206+
///
207+
/// if let Some(decoded) = edges.metadata::<EdgeMetadata>(rowid).unwrap() {
208+
/// assert_eq!(decoded.value, 42);
209+
/// } else {
210+
/// panic!("hmm...we expected some metadata!");
211+
/// }
212+
///
213+
/// # }
214+
/// ```
215+
pub struct OwnedEdgeTable {
216+
table: mbox::MBox<ll_bindings::tsk_edge_table_t>,
217+
}
218+
219+
impl OwnedEdgeTable {
220+
fn new() -> Self {
221+
let temp = unsafe {
222+
libc::malloc(std::mem::size_of::<ll_bindings::tsk_edge_table_t>())
223+
as *mut ll_bindings::tsk_edge_table_t
224+
};
225+
let nonnull = match std::ptr::NonNull::<ll_bindings::tsk_edge_table_t>::new(temp) {
226+
Some(x) => x,
227+
None => panic!("out of memory"),
228+
};
229+
let mut table = unsafe { mbox::MBox::from_non_null_raw(nonnull) };
230+
let rv = unsafe { ll_bindings::tsk_edge_table_init(&mut (*table), 0) };
231+
assert_eq!(rv, 0);
232+
Self { table }
233+
}
234+
235+
pub fn add_row(
236+
&mut self,
237+
left: impl Into<Position>,
238+
right: impl Into<Position>,
239+
parent: impl Into<NodeId>,
240+
child: impl Into<NodeId>,
241+
) -> Result<EdgeId, TskitError> {
242+
let rv = unsafe {
243+
ll_bindings::tsk_edge_table_add_row(
244+
&mut (*self.table),
245+
left.into().0,
246+
right.into().0,
247+
parent.into().0,
248+
child.into().0,
249+
std::ptr::null(),
250+
0,
251+
)
252+
};
253+
254+
handle_tsk_return_value!(rv, EdgeId::from(rv))
255+
}
256+
257+
pub fn add_row_with_metadata<M: crate::metadata::EdgeMetadata>(
258+
&mut self,
259+
left: impl Into<Position>,
260+
right: impl Into<Position>,
261+
parent: impl Into<NodeId>,
262+
child: impl Into<NodeId>,
263+
metadata: &M,
264+
) -> Result<EdgeId, TskitError> {
265+
let md = crate::metadata::EncodedMetadata::new(metadata)?;
266+
let rv = unsafe {
267+
ll_bindings::tsk_edge_table_add_row(
268+
&mut (*self.table),
269+
left.into().0,
270+
right.into().0,
271+
parent.into().0,
272+
child.into().0,
273+
md.as_ptr(),
274+
md.len().into(),
275+
)
276+
};
277+
278+
handle_tsk_return_value!(rv, EdgeId::from(rv))
279+
}
280+
}
281+
282+
impl std::ops::Deref for OwnedEdgeTable {
283+
type Target = EdgeTable<'static>;
284+
285+
fn deref(&self) -> &Self::Target {
286+
// SAFETY: that T* and &T have same layout,
287+
// and Target is repr(transparent).
288+
unsafe { std::mem::transmute(&self.table) }
289+
}
290+
}
291+
292+
impl Default for OwnedEdgeTable {
293+
fn default() -> Self {
294+
Self::new()
295+
}
296+
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ impl_time_position_arithmetic!(Position, Time);
422422
/// "Null" identifier value.
423423
pub(crate) const TSK_NULL: tsk_id_t = -1;
424424

425-
pub use edge_table::{EdgeTable, EdgeTableRow};
425+
pub use edge_table::{EdgeTable, EdgeTableRow, OwnedEdgeTable};
426426
pub use error::TskitError;
427427
pub use flags::*;
428428
pub use individual_table::{IndividualTable, IndividualTableRow};

0 commit comments

Comments
 (0)