diff --git a/src/_macros.rs b/src/_macros.rs index 21749ed6f..e2e4b5015 100644 --- a/src/_macros.rs +++ b/src/_macros.rs @@ -533,6 +533,49 @@ macro_rules! handle_metadata_return { }; } +macro_rules! build_owned_tables { + ($name: ty, $deref: ident, $llname: ty, $init: ident, $free: ident) => { + impl $name { + fn new() -> Self { + let temp = unsafe { libc::malloc(std::mem::size_of::<$llname>()) as *mut $llname }; + let nonnull = match std::ptr::NonNull::<$llname>::new(temp) { + Some(x) => x, + None => panic!("out of memory"), + }; + let mut table = unsafe { mbox::MBox::from_non_null_raw(nonnull) }; + let rv = unsafe { $init(&mut (*table), 0) }; + assert_eq!(rv, 0); + Self { table } + } + } + + impl Default for $name { + fn default() -> Self { + Self::new() + } + } + + impl std::ops::Deref for $name { + type Target = $deref<'static>; + + fn deref(&self) -> &Self::Target { + // SAFETY: that T* and &T have same layout, + // and Target is repr(transparent). + unsafe { std::mem::transmute(&self.table) } + } + } + + impl Drop for $name { + fn drop(&mut self) { + let rv = unsafe { $free(&mut (*self.table)) }; + if rv != 0 { + panic!("error when calling {}: {}", stringify!(free), rv); + } + } + } + }; +} + #[cfg(test)] mod test { use crate::error::TskitError; diff --git a/src/edge_table.rs b/src/edge_table.rs index 61d61f84c..31ef525a0 100644 --- a/src/edge_table.rs +++ b/src/edge_table.rs @@ -3,6 +3,7 @@ use crate::metadata; use crate::Position; use crate::{tsk_id_t, TskitError}; use crate::{EdgeId, NodeId}; +use ll_bindings::{tsk_edge_table_free, tsk_edge_table_init}; /// Row of an [`EdgeTable`] pub struct EdgeTableRow { @@ -217,21 +218,6 @@ pub struct OwnedEdgeTable { } impl OwnedEdgeTable { - fn new() -> Self { - let temp = unsafe { - libc::malloc(std::mem::size_of::()) - as *mut ll_bindings::tsk_edge_table_t - }; - let nonnull = match std::ptr::NonNull::::new(temp) { - Some(x) => x, - None => panic!("out of memory"), - }; - let mut table = unsafe { mbox::MBox::from_non_null_raw(nonnull) }; - let rv = unsafe { ll_bindings::tsk_edge_table_init(&mut (*table), 0) }; - assert_eq!(rv, 0); - Self { table } - } - pub fn add_row( &mut self, left: impl Into, @@ -279,27 +265,10 @@ impl OwnedEdgeTable { } } -impl std::ops::Deref for OwnedEdgeTable { - type Target = EdgeTable<'static>; - - fn deref(&self) -> &Self::Target { - // SAFETY: that T* and &T have same layout, - // and Target is repr(transparent). - unsafe { std::mem::transmute(&self.table) } - } -} - -impl Default for OwnedEdgeTable { - fn default() -> Self { - Self::new() - } -} - -impl Drop for OwnedEdgeTable { - fn drop(&mut self) { - let rv = unsafe { ll_bindings::tsk_edge_table_free(&mut (*self.table)) }; - if rv != 0 { - panic!("error when calling tsk_edge_table_free: {}", rv); - } - } -} +build_owned_tables!( + OwnedEdgeTable, + EdgeTable, + ll_bindings::tsk_edge_table_t, + tsk_edge_table_init, + tsk_edge_table_free +); diff --git a/src/population_table.rs b/src/population_table.rs index 8dd894bd3..237d6be3f 100644 --- a/src/population_table.rs +++ b/src/population_table.rs @@ -4,6 +4,7 @@ use crate::tsk_id_t; use crate::PopulationId; use crate::SizeType; use crate::TskitError; +use ll_bindings::{tsk_population_table_free, tsk_population_table_init}; /// Row of a [`PopulationTable`] #[derive(Eq)] @@ -164,19 +165,6 @@ pub struct OwnedPopulationTable { } impl OwnedPopulationTable { - fn new() -> Self { - let temp = unsafe { - libc::malloc(std::mem::size_of::()) - as *mut ll_bindings::tsk_population_table_t - }; - let nonnull = match std::ptr::NonNull::::new(temp) { - Some(x) => x, - None => panic!("out of memory"), - }; - let table = unsafe { mbox::MBox::from_non_null_raw(nonnull) }; - Self { table } - } - pub fn add_row(&mut self) -> Result { let rv = unsafe { ll_bindings::tsk_population_table_add_row(&mut (*self.table), std::ptr::null(), 0) @@ -202,18 +190,10 @@ impl OwnedPopulationTable { } } -impl std::ops::Deref for OwnedPopulationTable { - type Target = PopulationTable<'static>; - - fn deref(&self) -> &Self::Target { - // SAFETY: that T* and &T have same layout, - // and Target is repr(transparent). - unsafe { std::mem::transmute(&self.table) } - } -} - -impl Default for OwnedPopulationTable { - fn default() -> Self { - Self::new() - } -} +build_owned_tables!( + OwnedPopulationTable, + PopulationTable, + ll_bindings::tsk_population_table_t, + tsk_population_table_init, + tsk_population_table_free +);