@@ -65,6 +65,7 @@ impl<'a> Iterator for PopulationTableIterator<'a> {
6565/// These are not created directly.
6666/// Instead, use [`TableAccess::populations`](crate::TableAccess::populations)
6767/// to get a reference to an existing population table;
68+ #[ repr( transparent) ]
6869pub struct PopulationTable < ' a > {
6970 table_ : & ' a ll_bindings:: tsk_population_table_t ,
7071}
@@ -114,3 +115,105 @@ impl<'a> PopulationTable<'a> {
114115 table_row_access ! ( ri. 0 , self , make_population_table_row)
115116 }
116117}
118+
119+ /// A standalone population table that owns its data.
120+ ///
121+ /// # Examples
122+ ///
123+ /// ```
124+ /// use tskit::OwnedPopulationTable;
125+ ///
126+ /// let mut populations = OwnedPopulationTable::default();
127+ /// let rowid = populations.add_row().unwrap();
128+ /// assert_eq!(rowid, 0);
129+ /// assert_eq!(populations.num_rows(), 1);
130+ /// ```
131+ ///
132+ /// An example with metadata.
133+ /// This requires the cargo feature `"derive"` for `tskit`.
134+ ///
135+ /// ```
136+ /// # #[cfg(any(feature="doc", feature="derive"))] {
137+ /// use tskit::OwnedPopulationTable;
138+ ///
139+ /// #[derive(serde::Serialize,
140+ /// serde::Deserialize,
141+ /// tskit::metadata::PopulationMetadata)]
142+ /// #[serializer("serde_json")]
143+ /// struct PopulationMetadata {
144+ /// name: String,
145+ /// }
146+ ///
147+ /// let metadata = PopulationMetadata{name: "YRB".to_string()};
148+ ///
149+ /// let mut populations = OwnedPopulationTable::default();
150+ ///
151+ /// let rowid = populations.add_row_with_metadata(&metadata).unwrap();
152+ /// assert_eq!(rowid, 0);
153+ ///
154+ /// if let Some(decoded) = populations.metadata::<PopulationMetadata>(rowid).unwrap() {
155+ /// assert_eq!(&decoded.name, "YRB");
156+ /// } else {
157+ /// panic!("hmm...we expected some metadata!");
158+ /// }
159+ ///
160+ /// # }
161+ /// ```
162+ pub struct OwnedPopulationTable {
163+ table : mbox:: MBox < ll_bindings:: tsk_population_table_t > ,
164+ }
165+
166+ impl OwnedPopulationTable {
167+ fn new ( ) -> Self {
168+ let temp = unsafe {
169+ libc:: malloc ( std:: mem:: size_of :: < ll_bindings:: tsk_population_table_t > ( ) )
170+ as * mut ll_bindings:: tsk_population_table_t
171+ } ;
172+ let nonnull = match std:: ptr:: NonNull :: < ll_bindings:: tsk_population_table_t > :: new ( temp) {
173+ Some ( x) => x,
174+ None => panic ! ( "out of memory" ) ,
175+ } ;
176+ let table = unsafe { mbox:: MBox :: from_non_null_raw ( nonnull) } ;
177+ Self { table }
178+ }
179+
180+ pub fn add_row ( & mut self ) -> Result < PopulationId , TskitError > {
181+ let rv = unsafe {
182+ ll_bindings:: tsk_population_table_add_row ( & mut ( * self . table ) , std:: ptr:: null ( ) , 0 )
183+ } ;
184+
185+ handle_tsk_return_value ! ( rv, PopulationId :: from( rv) )
186+ }
187+
188+ pub fn add_row_with_metadata < M : crate :: metadata:: PopulationMetadata > (
189+ & mut self ,
190+ metadata : & M ,
191+ ) -> Result < PopulationId , TskitError > {
192+ let md = crate :: metadata:: EncodedMetadata :: new ( metadata) ?;
193+ let rv = unsafe {
194+ ll_bindings:: tsk_population_table_add_row (
195+ & mut ( * self . table ) ,
196+ md. as_ptr ( ) ,
197+ md. len ( ) . into ( ) ,
198+ )
199+ } ;
200+
201+ handle_tsk_return_value ! ( rv, PopulationId :: from( rv) )
202+ }
203+ }
204+
205+ impl std:: ops:: Deref for OwnedPopulationTable {
206+ type Target = PopulationTable < ' static > ;
207+
208+ fn deref ( & self ) -> & Self :: Target {
209+ // SAFETY: that T* and &T have same layout,
210+ // and Target is repr(transparent).
211+ unsafe { std:: mem:: transmute ( & self . table ) }
212+ }
213+ }
214+
215+ impl Default for OwnedPopulationTable {
216+ fn default ( ) -> Self {
217+ Self :: new ( )
218+ }
219+ }
0 commit comments