Skip to content

Commit 9a664f8

Browse files
authored
feat: add tskit::OwnedPopulationTable (#267)
1 parent a0d9fce commit 9a664f8

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ pub use individual_table::{IndividualTable, IndividualTableRow};
429429
pub use migration_table::{MigrationTable, MigrationTableRow};
430430
pub use mutation_table::{MutationTable, MutationTableRow};
431431
pub use node_table::{NodeTable, NodeTableRow};
432-
pub use population_table::{PopulationTable, PopulationTableRow};
432+
pub use population_table::{OwnedPopulationTable, PopulationTable, PopulationTableRow};
433433
pub use site_table::{SiteTable, SiteTableRow};
434434
pub use table_collection::TableCollection;
435435
pub use traits::IndividualLocation;

src/population_table.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
6869
pub 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

Comments
 (0)