1
1
use crate :: bindings as ll_bindings;
2
2
use crate :: error:: TskitError ;
3
- use crate :: ffi:: WrapTskitType ;
4
3
use crate :: types:: Bookmark ;
5
4
use crate :: EdgeTable ;
6
5
use crate :: IndividualTable ;
@@ -60,14 +59,38 @@ use mbox::MBox;
60
59
/// ```
61
60
///
62
61
pub struct TableCollection {
63
- pub ( crate ) inner : MBox < ll_bindings:: tsk_table_collection_t > ,
62
+ inner : MBox < ll_bindings:: tsk_table_collection_t > ,
64
63
}
65
64
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
+ }
71
94
72
95
impl TableCollection {
73
96
/// Create a new table collection with a sequence length.
@@ -91,19 +114,27 @@ impl TableCollection {
91
114
expected : "sequence_length >= 0.0" . to_string ( ) ,
92
115
} ) ;
93
116
}
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 ) } ;
96
119
if rv < 0 {
97
120
return Err ( crate :: error:: TskitError :: ErrorCode { code : rv } ) ;
98
121
}
122
+ let mut tables = Self { inner : mbox } ;
99
123
unsafe {
100
124
( * tables. as_mut_ptr ( ) ) . sequence_length = sequence_length. 0 ;
101
125
}
102
126
Ok ( tables)
103
127
}
104
128
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 }
107
138
}
108
139
109
140
pub ( crate ) fn into_raw ( self ) -> Result < * mut ll_bindings:: tsk_table_collection_t , TskitError > {
@@ -694,12 +725,13 @@ impl TableCollection {
694
725
pub fn deepcopy ( & self ) -> Result < TableCollection , TskitError > {
695
726
// The output is UNINITIALIZED tables,
696
727
// else we leak memory
697
- let mut copy = Self :: new_uninit ( ) ;
728
+ let mut inner = uninit_table_collection ( ) ;
698
729
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 ) } ;
701
731
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) } )
703
735
}
704
736
705
737
/// Return a [`crate::TreeSequence`] based on the tables.
0 commit comments