@@ -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) ]
7778pub struct EdgeTable < ' a > {
7879 table_ : & ' a ll_bindings:: tsk_edge_table_t ,
7980}
@@ -167,3 +168,138 @@ 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+ }
297+
298+ impl Drop for OwnedEdgeTable {
299+ fn drop ( & mut self ) {
300+ let rv = unsafe { ll_bindings:: tsk_edge_table_free ( & mut ( * self . table ) ) } ;
301+ if rv != 0 {
302+ panic ! ( "error when calling tsk_edge_table_free: {}" , rv) ;
303+ }
304+ }
305+ }
0 commit comments