11use crate :: bindings as ll_bindings;
22use crate :: error:: TskitError ;
3- use crate :: ffi:: WrapTskitType ;
43use crate :: types:: Bookmark ;
54use crate :: EdgeTable ;
65use crate :: IndividualTable ;
@@ -60,14 +59,38 @@ use mbox::MBox;
6059/// ```
6160///
6261pub struct TableCollection {
63- pub ( crate ) inner : MBox < ll_bindings:: tsk_table_collection_t > ,
62+ inner : MBox < ll_bindings:: tsk_table_collection_t > ,
6463}
6564
66- build_tskit_type ! (
67- TableCollection ,
68- ll_bindings:: tsk_table_collection_t,
69- tsk_table_collection_free
70- ) ;
65+ impl TskitTypeAccess < ll_bindings:: tsk_table_collection_t > for TableCollection {
66+ fn as_ptr ( & self ) -> * const ll_bindings:: tsk_table_collection_t {
67+ & * self . inner
68+ }
69+
70+ fn as_mut_ptr ( & mut self ) -> * mut ll_bindings:: tsk_table_collection_t {
71+ & mut * self . inner
72+ }
73+ }
74+
75+ impl Drop for TableCollection {
76+ fn drop ( & mut self ) {
77+ let rv = unsafe { tsk_table_collection_free ( self . as_mut_ptr ( ) ) } ;
78+ assert_eq ! ( rv, 0 ) ;
79+ }
80+ }
81+
82+ /// Returns a pointer to an uninitialized tsk_table_collection_t
83+ pub ( crate ) fn uninit_table_collection ( ) -> MBox < ll_bindings:: tsk_table_collection_t > {
84+ let temp = unsafe {
85+ libc:: malloc ( std:: mem:: size_of :: < ll_bindings:: tsk_table_collection_t > ( ) )
86+ as * mut ll_bindings:: tsk_table_collection_t
87+ } ;
88+ let nonnull = match std:: ptr:: NonNull :: < ll_bindings:: tsk_table_collection_t > :: new ( temp) {
89+ Some ( x) => x,
90+ None => panic ! ( "out of memory" ) ,
91+ } ;
92+ unsafe { MBox :: from_non_null_raw ( nonnull) }
93+ }
7194
7295impl TableCollection {
7396 /// Create a new table collection with a sequence length.
@@ -91,19 +114,27 @@ impl TableCollection {
91114 expected : "sequence_length >= 0.0" . to_string ( ) ,
92115 } ) ;
93116 }
94- let mut tables = Self :: wrap ( ) ;
95- let rv = unsafe { ll_bindings:: tsk_table_collection_init ( tables . as_mut_ptr ( ) , 0 ) } ;
117+ let mut mbox = uninit_table_collection ( ) ;
118+ let rv = unsafe { ll_bindings:: tsk_table_collection_init ( & mut * mbox , 0 ) } ;
96119 if rv < 0 {
97120 return Err ( crate :: error:: TskitError :: ErrorCode { code : rv } ) ;
98121 }
122+ let mut tables = Self { inner : mbox } ;
99123 unsafe {
100124 ( * tables. as_mut_ptr ( ) ) . sequence_length = sequence_length. 0 ;
101125 }
102126 Ok ( tables)
103127 }
104128
105- pub ( crate ) fn new_uninit ( ) -> Self {
106- Self :: wrap ( )
129+ /// # Safety
130+ ///
131+ /// It is possible that the mbox's inner pointer has not be run through
132+ /// tsk_table_collection_init, meaning that it is in an uninitialized state.
133+ /// Or, it may be initialized and about to be used in a part of the C API
134+ /// requiring an uninitialized table collection.
135+ /// Consult the C API docs before using!
136+ pub ( crate ) unsafe fn new_from_mbox ( mbox : MBox < ll_bindings:: tsk_table_collection_t > ) -> Self {
137+ Self { inner : mbox }
107138 }
108139
109140 pub ( crate ) fn into_raw ( self ) -> Result < * mut ll_bindings:: tsk_table_collection_t , TskitError > {
@@ -694,12 +725,13 @@ impl TableCollection {
694725 pub fn deepcopy ( & self ) -> Result < TableCollection , TskitError > {
695726 // The output is UNINITIALIZED tables,
696727 // else we leak memory
697- let mut copy = Self :: new_uninit ( ) ;
728+ let mut inner = uninit_table_collection ( ) ;
698729
699- let rv =
700- unsafe { ll_bindings:: tsk_table_collection_copy ( self . as_ptr ( ) , copy. as_mut_ptr ( ) , 0 ) } ;
730+ let rv = unsafe { ll_bindings:: tsk_table_collection_copy ( self . as_ptr ( ) , & mut * inner, 0 ) } ;
701731
702- handle_tsk_return_value ! ( rv, copy)
732+ // SAFETY: we just initialized it.
733+ // The C API doesn't free NULL pointers.
734+ handle_tsk_return_value ! ( rv, unsafe { Self :: new_from_mbox( inner) } )
703735 }
704736
705737 /// Return a [`crate::TreeSequence`] based on the tables.
0 commit comments