diff --git a/src/population_table.rs b/src/population_table.rs index e5c06d4f3..ab462cd50 100644 --- a/src/population_table.rs +++ b/src/population_table.rs @@ -24,7 +24,7 @@ fn make_population_table_row(table: &PopulationTable, pos: tsk_id_t) -> Option

Option

= - crate::table_iterator::TableIterator<&'a PopulationTable<'a>>; -pub(crate) type PopulationTableIterator<'a> = - crate::table_iterator::TableIterator>; + crate::table_iterator::TableIterator<&'a PopulationTable>; +pub(crate) type PopulationTableIterator<'a> = crate::table_iterator::TableIterator; impl<'a> Iterator for PopulationTableRefIterator<'a> { type Item = PopulationTableRow; @@ -65,25 +64,32 @@ impl<'a> Iterator for PopulationTableIterator<'a> { /// These are not created directly. /// Instead, use [`TableAccess::populations`](crate::TableAccess::populations) /// to get a reference to an existing population table; -pub struct PopulationTable<'a> { - table_: &'a ll_bindings::tsk_population_table_t, +pub struct PopulationTable { + pub(crate) table_: *const ll_bindings::tsk_population_table_t, } -impl<'a> PopulationTable<'a> { - pub(crate) fn new_from_table(mutations: &'a ll_bindings::tsk_population_table_t) -> Self { - PopulationTable { table_: mutations } +impl PopulationTable { + fn ll_table_ref(&self) -> &ll_bindings::tsk_population_table_t { + unsafe { &(*self.table_) } + } + + pub(crate) fn new_from_table(populations: *const ll_bindings::tsk_population_table_t) -> Self { + // assert!(!populations.is_null()); + PopulationTable { + table_: populations, + } } /// Return the number of rows. - pub fn num_rows(&'a self) -> SizeType { - self.table_.num_rows.into() + pub fn num_rows(&self) -> SizeType { + self.ll_table_ref().num_rows.into() } pub fn metadata( - &'a self, + &self, row: PopulationId, ) -> Result, TskitError> { - let table_ref = self.table_; + let table_ref = unsafe { *self.table_ }; let buffer = metadata_to_vector!(table_ref, row.0)?; decode_metadata_row!(T, buffer) } @@ -91,7 +97,7 @@ impl<'a> PopulationTable<'a> { /// Return an iterator over rows of the table. /// The value of the iterator is [`PopulationTableRow`]. pub fn iter(&self) -> impl Iterator + '_ { - crate::table_iterator::make_table_iterator::<&PopulationTable<'a>>(self) + crate::table_iterator::make_table_iterator::<&PopulationTable>(self) } /// Return row `r` of the table. @@ -114,3 +120,74 @@ impl<'a> PopulationTable<'a> { table_row_access!(ri.0, self, make_population_table_row) } } + +pub struct OwningPopulationTable { + pointer: mbox::MBox, + deref_target: PopulationTable, +} + +impl OwningPopulationTable { + fn new() -> Self { + let pointer = unsafe { + libc::malloc(std::mem::size_of::()) + as *mut ll_bindings::tsk_population_table_t + }; + // Gotta validate this code + let code = unsafe { ll_bindings::tsk_population_table_init(pointer, 0) }; + assert!(!pointer.is_null()); // Should Err here if true! + let deref_target = PopulationTable::new_from_table(std::ptr::null()); + let nonnull = match std::ptr::NonNull::::new(pointer) { + Some(x) => x, + None => panic!("out of memory"), + }; + let mbox = unsafe { mbox::MBox::from_non_null_raw(nonnull) }; + let mut rv = Self { + pointer: mbox, + deref_target, + }; + rv.deref_target.table_ = &(*rv.pointer) as *const ll_bindings::tsk_population_table_t; + rv + } +} + +impl OwningPopulationTable { + fn add_row(&mut self) -> Result { + let rv = unsafe { + ll_bindings::tsk_population_table_add_row(&mut (*self.pointer), std::ptr::null(), 0) + }; + handle_tsk_return_value!(rv, rv.into()) + } +} + +impl std::ops::Deref for OwningPopulationTable { + type Target = PopulationTable; + fn deref(&self) -> &Self::Target { + &self.deref_target + } +} + +impl Drop for OwningPopulationTable { + fn drop(&mut self) { + let rv = unsafe { + ll_bindings::tsk_population_table_free( + &mut (*self.pointer) as *mut ll_bindings::tsk_population_table_t, + ) + }; + assert_eq!(rv, 0); + //assert!(!self.pointer.is_null()); + //unsafe { libc::free(self.pointer as *mut libc::c_void) }; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_population() { + let mut p = OwningPopulationTable::new(); + let x = p.add_row().unwrap(); + assert_eq!(x, 0); + assert_eq!(p.num_rows(), 1); + } +} diff --git a/src/table_collection.rs b/src/table_collection.rs index ec34c20f1..44a16cc46 100644 --- a/src/table_collection.rs +++ b/src/table_collection.rs @@ -67,13 +67,36 @@ use mbox::MBox; /// pub struct TableCollection { pub(crate) inner: MBox, + populations: PopulationTable, } -build_tskit_type!( - TableCollection, - ll_bindings::tsk_table_collection_t, - tsk_table_collection_free -); +//build_tskit_type!( +// TableCollection, +// ll_bindings::tsk_table_collection_t, +// tsk_table_collection_free +//); +impl crate::ffi::WrapTskitType for TableCollection { + fn wrap() -> Self { + let temp = unsafe { + libc::malloc(std::mem::size_of::()) + as *mut ll_bindings::tsk_table_collection_t + }; + let nonnull = match std::ptr::NonNull::::new(temp) { + Some(x) => x, + None => panic!("out of memory"), + }; + let mbox = unsafe { MBox::from_non_null_raw(nonnull) }; + let populations = PopulationTable::new_from_table(std::ptr::null()); + let rv = Self { + inner: mbox, + populations, + }; + rv + } +} + +drop_for_tskit_type!(TableCollection, tsk_table_collection_free); +tskit_type_access!(TableCollection, ll_bindings::tsk_table_collection_t); impl TableCollection { /// Create a new table collection with a sequence length. @@ -102,6 +125,9 @@ impl TableCollection { if rv < 0 { return Err(crate::error::TskitError::ErrorCode { code: rv }); } + + // NOTE: gotta be like this + tables.populations.table_ = &(*tables.inner).populations; unsafe { (*tables.as_mut_ptr()).sequence_length = sequence_length.0; } @@ -1222,8 +1248,8 @@ impl TableAccess for TableCollection { MutationTable::new_from_table(&(*self.inner).mutations) } - fn populations(&self) -> PopulationTable { - PopulationTable::new_from_table(&(*self.inner).populations) + fn populations(&self) -> &PopulationTable { + &self.populations } #[cfg(any(feature = "provenance", doc))] diff --git a/src/traits.rs b/src/traits.rs index 2e59dbc6c..a67b8ccde 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -84,13 +84,13 @@ pub trait TableAccess { } /// Get reference to the [``PopulationTable``](crate::PopulationTable). - fn populations(&self) -> PopulationTable; + fn populations(&self) -> &PopulationTable; /// Return an iterator over the populations. fn populations_iter( &self, ) -> Box + '_> { - Box::new(make_table_iterator::(self.populations())) + Box::new(make_table_iterator::<&PopulationTable>(self.populations())) } /// Get reference to the [``MigrationTable``](crate::MigrationTable). diff --git a/src/trees.rs b/src/trees.rs index 7f66e5faf..b0661d046 100644 --- a/src/trees.rs +++ b/src/trees.rs @@ -959,9 +959,32 @@ iterator_for_nodeiterator!(SamplesIterator<'_>); /// ``` pub struct TreeSequence { pub(crate) inner: MBox, + populations: PopulationTable, } +impl crate::ffi::WrapTskitType for TreeSequence { + fn wrap() -> Self { + let temp = unsafe { + libc::malloc(std::mem::size_of::()) + as *mut ll_bindings::tsk_treeseq_t + }; + let nonnull = match std::ptr::NonNull::::new(temp) { + Some(x) => x, + None => panic!("out of memory"), + }; + let mbox = unsafe { MBox::from_non_null_raw(nonnull) }; + let populations = PopulationTable::new_from_table(std::ptr::null()); + let mut rv = Self { + inner: mbox, + populations, + }; + rv + } +} + +drop_for_tskit_type!(TreeSequence, tsk_treeseq_free); +tskit_type_access!(TreeSequence, ll_bindings::tsk_treeseq_t); -build_tskit_type!(TreeSequence, ll_bindings::tsk_treeseq_t, tsk_treeseq_free); +//build_tskit_type!(TreeSequence, ll_bindings::tsk_treeseq_t, tsk_treeseq_free); impl TreeSequence { /// Create a tree sequence from a [`TableCollection`]. @@ -1017,6 +1040,7 @@ impl TreeSequence { let raw_tables_ptr = tables.into_raw()?; let rv = unsafe { ll_bindings::tsk_treeseq_init(treeseq.as_mut_ptr(), raw_tables_ptr, flags) }; + treeseq.populations.table_ = &unsafe { *(*treeseq.inner).tables }.populations; handle_tsk_return_value!(rv, treeseq) } @@ -1308,8 +1332,8 @@ impl TableAccess for TreeSequence { MutationTable::new_from_table(unsafe { &(*(*self.inner).tables).mutations }) } - fn populations(&self) -> PopulationTable { - PopulationTable::new_from_table(unsafe { &(*(*self.inner).tables).populations }) + fn populations(&self) -> &PopulationTable { + &self.populations } #[cfg(any(feature = "provenance", doc))]