use delegate::delegate;
use std::vec;
use crate::bindings as ll_bindings;
use crate::error::TskitError;
use crate::types::Bookmark;
use crate::IndividualTableSortOptions;
use crate::Position;
use crate::SimplificationOptions;
use crate::TableClearOptions;
use crate::TableEqualityOptions;
use crate::TableIntegrityCheckFlags;
use crate::TableOutputOptions;
use crate::TableSortOptions;
use crate::TreeSequenceFlags;
use crate::TskReturnValue;
use crate::{tsk_id_t, tsk_size_t};
use crate::{EdgeId, NodeId};
use ll_bindings::tsk_table_collection_free;
use mbox::MBox;
/// A table collection.
///
/// This is a thin wrapper around the C type
/// [`tsk_table_collection_t`](crate::bindings::tsk_table_collection_t).
///
/// # See also
///
/// * [`metadata`](crate::metadata)
///
/// # Examples
///
/// ```
///
/// let mut tables = tskit::TableCollection::new(100.).unwrap();
/// assert_eq!(tables.sequence_length(), 100.);
///
/// // Adding edges:
///
/// let rv = tables.add_edge(0., 53., 1, 11).unwrap();
///
/// // Add node:
///
/// let rv = tables.add_node(0, 3.2, tskit::PopulationId::NULL, tskit::IndividualId::NULL).unwrap();
///
/// // Get immutable reference to edge table
/// let edges = tables.edges();
/// assert_eq!(edges.num_rows(), 1);
///
/// // Get immutable reference to node table
/// let nodes = tables.nodes();
/// assert_eq!(nodes.num_rows(), 1);
/// ```
///
pub struct TableCollection {
inner: MBox<ll_bindings::tsk_table_collection_t>,
idmap: Vec<NodeId>,
views: crate::table_views::TableViews,
}
impl Drop for TableCollection {
fn drop(&mut self) {
let rv = unsafe { tsk_table_collection_free(self.as_mut_ptr()) };
assert_eq!(rv, 0);
}
}
/// Returns a pointer to an uninitialized tsk_table_collection_t
pub(crate) fn uninit_table_collection() -> MBox<ll_bindings::tsk_table_collection_t> {
let temp = unsafe {
libc::malloc(std::mem::size_of::<ll_bindings::tsk_table_collection_t>())
as *mut ll_bindings::tsk_table_collection_t
};
let nonnull = match std::ptr::NonNull::<ll_bindings::tsk_table_collection_t>::new(temp) {
Some(x) => x,
None => panic!("out of memory"),
};
unsafe { MBox::from_non_null_raw(nonnull) }
}
impl TableCollection {
/// Create a new table collection with a sequence length.
///
/// # Examples
///
/// ```
/// let tables = tskit::TableCollection::new(55.0).unwrap();
/// ```
///
/// Negative sequence lengths are errors:
///
/// ```{should_panic}
/// let tables = tskit::TableCollection::new(-55.0).unwrap();
/// ```
pub fn new<P: Into<Position>>(sequence_length: P) -> Result<Self, TskitError> {
let sequence_length = sequence_length.into();
if sequence_length <= 0. {
return Err(TskitError::ValueError {
got: f64::from(sequence_length).to_string(),
expected: "sequence_length >= 0.0".to_string(),
});
}
let mut mbox = uninit_table_collection();
let rv = unsafe { ll_bindings::tsk_table_collection_init(&mut *mbox, 0) };
if rv < 0 {
return Err(crate::error::TskitError::ErrorCode { code: rv });
}
let views = crate::table_views::TableViews::new_from_mbox_table_collection(&mut mbox)?;
// AHA?
assert!(std::ptr::eq(
&mbox.as_ref().edges as *const ll_bindings::tsk_edge_table_t,
views.edges().as_ref() as *const ll_bindings::tsk_edge_table_t
));
let mut tables = Self {
inner: mbox,
idmap: vec![],
views,
};
unsafe {
(*tables.as_mut_ptr()).sequence_length = f64::from(sequence_length);
}
Ok(tables)
}
/// # Safety
///
/// It is possible that the mbox's inner pointer has not be run through
/// tsk_table_collection_init, meaning that it is in an uninitialized state.
/// Or, it may be initialized and about to be used in a part of the C API
/// requiring an uninitialized table collection.
/// Consult the C API docs before using!
pub(crate) unsafe fn new_from_mbox(
mbox: MBox<ll_bindings::tsk_table_collection_t>,
) -> Result<Self, TskitError> {
let mut mbox = mbox;
let views = crate::table_views::TableViews::new_from_mbox_table_collection(&mut mbox)?;
Ok(Self {
inner: mbox,
idmap: vec![],
views,
})
}
pub(crate) fn into_raw(self) -> Result<*mut ll_bindings::tsk_table_collection_t, TskitError> {
let mut tables = self;
// rust won't let use move inner out b/c this type implements Drop.
// So we have to replace the existing pointer with a new one.
let table_ptr = unsafe {
libc::malloc(std::mem::size_of::<ll_bindings::tsk_table_collection_t>())
as *mut ll_bindings::tsk_table_collection_t
};
let rv = unsafe { ll_bindings::tsk_table_collection_init(table_ptr, 0) };
let mut temp = unsafe { MBox::from_raw(table_ptr) };
std::mem::swap(&mut temp, &mut tables.inner);
handle_tsk_return_value!(rv, MBox::into_raw(temp))
}
/// Load a table collection from a file.
///
/// # Examples
///
/// The function is generic over references to `str`:
///
/// ```
/// # let empty_tables = tskit::TableCollection::new(100.).unwrap();
/// # empty_tables.dump("trees.file", tskit::TableOutputOptions::default()).unwrap();
/// let tables = tskit::TableCollection::new_from_file("trees.file").unwrap();
///
/// let filename = String::from("trees.file");
/// // Pass filename by reference
/// let tables = tskit::TableCollection::new_from_file(&filename).unwrap();
///
/// // Move filename
/// let tables = tskit::TableCollection::new_from_file(filename).unwrap();
///
/// // Boxed String are an unlikely use case, but can be made to work:
/// let filename = Box::new(String::from("trees.file"));
/// let tables = tskit::TableCollection::new_from_file(&*filename.as_ref()).unwrap();
/// # std::fs::remove_file("trees.file").unwrap();
/// ```
///
/// # Panics
///
/// This function allocates a `CString` to pass the file name to the C API.
/// A panic will occur if the system runs out of memory.
pub fn new_from_file(filename: impl AsRef<str>) -> Result<Self, TskitError> {
// Arbitrary sequence_length.
let mut tables = match TableCollection::new(1.0) {
Ok(t) => t,
Err(e) => return Err(e),
};
let c_str = std::ffi::CString::new(filename.as_ref()).map_err(|_| {
TskitError::LibraryError("call to ffi::CString::new failed".to_string())
})?;
let rv = unsafe {
ll_bindings::tsk_table_collection_load(
tables.as_mut_ptr(),
c_str.as_ptr(),
ll_bindings::TSK_NO_INIT,
)
};
handle_tsk_return_value!(rv, tables)
}
/// Length of the sequence/"genome".
/// # Examples
///
/// ```
/// let tables = tskit::TableCollection::new(100.).unwrap();
/// assert_eq!(tables.sequence_length(), 100.0);
/// ```
pub fn sequence_length(&self) -> Position {
unsafe { (*self.as_ptr()).sequence_length }.into()
}
/// Add a row to the edge table
///
/// # Examples
///
/// ```
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
///
/// // left, right, parent, child
/// match tables.add_edge(0., 53., 1, 11) {
/// // This is the first edge, so its id will be
/// // zero (0).
/// Ok(edge_id) => assert_eq!(edge_id, 0),
/// Err(e) => panic!("{:?}", e),
/// }
/// ```
///
/// You may also use [`Position`] and [`NodeId`] as inputs.
///
/// ```
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// let left = tskit::Position::from(0.0);
/// let right = tskit::Position::from(53.0);
/// let parent = tskit::NodeId::from(1);
/// let child = tskit::NodeId::from(11);
/// match tables.add_edge(left, right, parent, child) {
/// Ok(edge_id) => assert_eq!(edge_id, 0),
/// Err(e) => panic!("{:?}", e),
/// }
/// ```
///
/// Adding invalid data is allowed at this point:
///
/// ```
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// assert!(tables.add_edge(0., 53.,
/// tskit::NodeId::NULL,
/// tskit::NodeId::NULL).is_ok());
/// # assert!(tables.check_integrity(tskit::TableIntegrityCheckFlags::default()).is_err());
/// ```
///
/// See [`TableCollection::check_integrity`] for how to catch these data model
/// violations.
pub fn add_edge<L, R, P, C>(
&mut self,
left: L,
right: R,
parent: P,
child: C,
) -> Result<crate::EdgeId, crate::TskitError>
where
L: Into<crate::Position>,
R: Into<crate::Position>,
P: Into<crate::NodeId>,
C: Into<crate::NodeId>,
{
self.edges_mut().add_row(left, right, parent, child)
}
/// Add a row with optional metadata to the edge table
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::EdgeMetadata)]
/// # #[serializer("serde_json")]
/// # struct EdgeMetadata {
/// # x: i32,
/// # }
/// let metadata = EdgeMetadata{x: 1};
/// assert!(tables.add_edge_with_metadata(0., 53., 1, 11, &metadata).is_ok());
/// # }
/// ```
pub fn add_edge_with_metadata<L, R, P, C, M>(
&mut self,
left: L,
right: R,
parent: P,
child: C,
metadata: &M,
) -> Result<crate::EdgeId, crate::TskitError>
where
L: Into<crate::Position>,
R: Into<crate::Position>,
P: Into<crate::NodeId>,
C: Into<crate::NodeId>,
M: crate::metadata::EdgeMetadata,
{
self.edges_mut()
.add_row_with_metadata(left, right, parent, child, metadata)
}
/// Add a row to the individual table
///
/// # Examples
///
/// ## No flags, location, nor parents
///
/// ```
/// #
/// # let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// tables.add_individual(0, None, None).unwrap();
/// # assert!(tables.individuals().location(0).is_none());
/// # assert!(tables.individuals().parents(0).is_none());
/// ```
///
/// ## No flags, a 3d location, no parents
///
/// ```
/// #
/// # let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// tables.add_individual(0, &[-0.5, 0.3, 10.0], None).unwrap();
/// # match tables.individuals().location(0) {
/// # Some(loc) => loc.iter().zip([-0.5, 0.3, 10.0].iter()).for_each(|(a,b)| assert_eq!(a, b)),
/// # None => panic!("expected a location"),
/// # }
/// ```
///
/// ## No flags, no location, two parents
/// ```
/// # let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// #
/// tables.add_individual(0, None, &[1, 11]);
/// # match tables.individuals().parents(0) {
/// # Some(parents) => parents.iter().zip([1, 11].iter()).for_each(|(a,b)| assert_eq!(a, b)),
/// # None => panic!("expected parents"),
/// # }
/// ```
pub fn add_individual<F, L, P>(
&mut self,
flags: F,
location: L,
parents: P,
) -> Result<crate::IndividualId, crate::TskitError>
where
F: Into<crate::IndividualFlags>,
L: crate::IndividualLocation,
P: crate::IndividualParents,
{
self.individuals_mut().add_row(flags, location, parents)
}
/// Add a row with metadata to the individual table
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
///
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::IndividualMetadata)]
/// # #[serializer("serde_json")]
/// # struct IndividualMetadata {
/// # x: i32,
/// # }
/// let metadata = IndividualMetadata{x: 1};
/// assert!(tables.add_individual_with_metadata(0, None, None,
/// &metadata).is_ok());
/// # let decoded = tables.individuals().metadata::<IndividualMetadata>(0.into()).unwrap().unwrap();
/// # assert_eq!(decoded.x, 1);
/// # }
pub fn add_individual_with_metadata<F, L, P, M>(
&mut self,
flags: F,
location: L,
parents: P,
metadata: &M,
) -> Result<crate::IndividualId, crate::TskitError>
where
F: Into<crate::IndividualFlags>,
L: crate::IndividualLocation,
P: crate::IndividualParents,
M: crate::metadata::IndividualMetadata,
{
self.individuals_mut()
.add_row_with_metadata(flags, location, parents, metadata)
}
/// Add a row to the migration table
///
/// # Warnings
///
/// Migration tables are not currently supported
/// by tree sequence simplification.
/// # Examples
///
/// ```
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// assert!(tables.add_migration((0.5, 100.0),
/// 3,
/// (0, 1),
/// 53.5).is_ok());
/// ```
pub fn add_migration<L, R, N, S, D, T>(
&mut self,
span: (L, R),
node: N,
source_dest: (S, D),
time: T,
) -> Result<crate::MigrationId, TskitError>
where
L: Into<Position>,
R: Into<Position>,
N: Into<NodeId>,
S: Into<crate::PopulationId>,
D: Into<crate::PopulationId>,
T: Into<crate::Time>,
{
self.migrations_mut().add_row(span, node, source_dest, time)
}
/// Add a row with optional metadata to the migration table
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::MigrationMetadata)]
/// # #[serializer("serde_json")]
/// # struct MigrationMetadata {
/// # x: i32,
/// # }
/// let metadata = MigrationMetadata{x: 1};
/// assert!(tables.add_migration_with_metadata((0.5, 100.0),
/// 3,
/// (0, 1),
/// 53.5,
/// &metadata).is_ok());
/// # }
/// ```
///
/// # Warnings
///
/// Migration tables are not currently supported
/// by tree sequence simplification.
pub fn add_migration_with_metadata<L, R, N, S, D, T, M>(
&mut self,
span: (L, R),
node: N,
source_dest: (S, D),
time: T,
metadata: &M,
) -> Result<crate::MigrationId, TskitError>
where
L: Into<Position>,
R: Into<Position>,
N: Into<NodeId>,
S: Into<crate::PopulationId>,
D: Into<crate::PopulationId>,
T: Into<crate::Time>,
M: crate::metadata::MigrationMetadata,
{
self.migrations_mut()
.add_row_with_metadata(span, node, source_dest, time, metadata)
}
/// Add a row to the node table
pub fn add_node<F, T, P, I>(
&mut self,
flags: F,
time: T,
population: P,
individual: I,
) -> Result<NodeId, TskitError>
where
F: Into<crate::NodeFlags>,
T: Into<crate::Time>,
P: Into<crate::PopulationId>,
I: Into<crate::IndividualId>,
{
self.views
.nodes_mut()
.add_row(flags, time, population, individual)
}
/// Add a row with optional metadata to the node table
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::NodeMetadata)]
/// # #[serializer("serde_json")]
/// # struct NodeMetadata {
/// # x: i32,
/// # }
/// let metadata = NodeMetadata{x: 1};
/// assert!(tables.add_node_with_metadata(0, 0.0, -1, -1, &metadata).is_ok());
/// # }
/// ```
pub fn add_node_with_metadata<F, T, P, I, M>(
&mut self,
flags: F,
time: T,
population: P,
individual: I,
metadata: &M,
) -> Result<NodeId, TskitError>
where
F: Into<crate::NodeFlags>,
T: Into<crate::Time>,
P: Into<crate::PopulationId>,
I: Into<crate::IndividualId>,
M: crate::metadata::NodeMetadata,
{
self.views
.nodes_mut()
.add_row_with_metadata(flags, time, population, individual, metadata)
}
/// Add a row to the site table
pub fn add_site<P>(
&mut self,
position: P,
ancestral_state: Option<&[u8]>,
) -> Result<crate::SiteId, TskitError>
where
P: Into<Position>,
{
self.sites_mut().add_row(position, ancestral_state)
}
/// Add a row with optional metadata to the site table
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::SiteMetadata)]
/// # #[serializer("serde_json")]
/// # struct SiteMetadata {
/// # x: i32,
/// # }
/// let metadata = SiteMetadata{x: 1};
/// assert!(tables.add_site_with_metadata(tskit::Position::from(111.0),
/// Some(&[111]),
/// &metadata).is_ok());
/// # }
/// ```
pub fn add_site_with_metadata<P, M>(
&mut self,
position: P,
ancestral_state: Option<&[u8]>,
metadata: &M,
) -> Result<crate::SiteId, TskitError>
where
P: Into<Position>,
M: crate::metadata::SiteMetadata,
{
self.sites_mut()
.add_row_with_metadata(position, ancestral_state, metadata)
}
/// Add a row to the mutation table.
pub fn add_mutation<S, N, P, T>(
&mut self,
site: S,
node: N,
parent: P,
time: T,
derived_state: Option<&[u8]>,
) -> Result<crate::MutationId, crate::TskitError>
where
S: Into<crate::SiteId>,
N: Into<crate::NodeId>,
P: Into<crate::MutationId>,
T: Into<crate::Time>,
{
self.mutations_mut()
.add_row(site, node, parent, time, derived_state)
}
/// Add a row with optional metadata to the mutation table.
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::MutationMetadata)]
/// # #[serializer("serde_json")]
/// # struct MutationMetadata {
/// # x: i32,
/// # }
/// let metadata = MutationMetadata{x: 1};
/// assert!(tables.add_mutation_with_metadata(0, 0, 0, 100.0, None,
/// &metadata).is_ok());
/// # }
/// ```
pub fn add_mutation_with_metadata<S, N, P, T, M>(
&mut self,
site: S,
node: N,
parent: P,
time: T,
derived_state: Option<&[u8]>,
metadata: &M,
) -> Result<crate::MutationId, crate::TskitError>
where
S: Into<crate::SiteId>,
N: Into<crate::NodeId>,
P: Into<crate::MutationId>,
T: Into<crate::Time>,
M: crate::metadata::MutationMetadata,
{
self.mutations_mut().add_row_with_metadata(
site,
node,
parent,
time,
derived_state,
metadata,
)
}
/// Add a row to the population_table
///
/// # Examples
///
/// ```
/// # let mut tables = tskit::TableCollection::new(55.0).unwrap();
/// tables.add_population().unwrap();
/// ```
pub fn add_population(&mut self) -> Result<crate::PopulationId, crate::TskitError> {
self.populations_mut().add_row()
}
/// Add a row with optional metadata to the population_table
///
/// # Examples
///
/// See [`metadata`](crate::metadata) for more details about required
/// trait implementations.
/// Those details have been omitted from this example.
///
/// ```
/// # #[cfg(feature = "derive")] {
/// # let mut tables = tskit::TableCollection::new(100.).unwrap();
/// # #[derive(serde::Serialize, serde::Deserialize, tskit::metadata::PopulationMetadata)]
/// # #[serializer("serde_json")]
/// # struct PopulationMetadata {
/// # x: i32,
/// # }
/// let metadata = PopulationMetadata{x: 1};
/// assert!(tables.add_population_with_metadata(&metadata).is_ok());
/// # }
pub fn add_population_with_metadata<M>(
&mut self,
metadata: &M,
) -> Result<crate::PopulationId, crate::TskitError>
where
M: crate::metadata::PopulationMetadata,
{
self.populations_mut().add_row_with_metadata(metadata)
}
/// Build the "input" and "output"
/// indexes for the edge table.
///
/// # Note
///
/// The `C API` call behind this takes a `flags` argument
/// that is currently unused. A future release may break `API`
/// here if the `C` library is updated to use flags.
pub fn build_index(&mut self) -> TskReturnValue {
let rv = unsafe { ll_bindings::tsk_table_collection_build_index(self.as_mut_ptr(), 0) };
handle_tsk_return_value!(rv)
}
/// Return `true` if tables are indexed.
pub fn is_indexed(&self) -> bool {
unsafe { ll_bindings::tsk_table_collection_has_index(self.as_ptr(), 0) }
}
/// If `self.is_indexed()` is `true`, return a non-owning
/// slice containing the edge insertion order.
/// Otherwise, return `None`.
pub fn edge_insertion_order(&self) -> Option<&[EdgeId]> {
if self.is_indexed() {
Some(unsafe {
std::slice::from_raw_parts(
(*self.as_ptr()).indexes.edge_insertion_order as *const EdgeId,
usize::try_from((*self.as_ptr()).indexes.num_edges).ok()?,
)
})
} else {
None
}
}
/// If `self.is_indexed()` is `true`, return a non-owning
/// slice containing the edge removal order.
/// Otherwise, return `None`.
pub fn edge_removal_order(&self) -> Option<&[EdgeId]> {
if self.is_indexed() {
Some(unsafe {
std::slice::from_raw_parts(
(*self.as_ptr()).indexes.edge_removal_order as *const EdgeId,
usize::try_from((*self.as_ptr()).indexes.num_edges).ok()?,
)
})
} else {
None
}
}
/// Sort the tables.
/// The [``bookmark``](crate::types::Bookmark) can
/// be used to affect where sorting starts from for each table.
///
/// # Details
///
/// See [`full_sort`](crate::TableCollection::full_sort)
/// for more details about which tables are sorted.
pub fn sort<O: Into<TableSortOptions>>(
&mut self,
start: &Bookmark,
options: O,
) -> TskReturnValue {
let rv = unsafe {
ll_bindings::tsk_table_collection_sort(
self.as_mut_ptr(),
&start.offsets,
options.into().bits(),
)
};
handle_tsk_return_value!(rv)
}
/// Fully sort all tables.
/// Implemented via a call to [``sort``](crate::TableCollection::sort).
///
/// # Details
///
/// This function only sorts the tables that have a strict sortedness
/// requirement according to the `tskit` [data
/// model](https://tskit.dev/tskit/docs/stable/data-model.html).
///
/// These tables are:
///
/// * edges
/// * mutations
/// * sites
///
/// For some use cases it is desirable to have the individual table
/// sorted so that parents appear before offspring. See
/// [``topological_sort_individuals``](crate::TableCollection::topological_sort_individuals).
pub fn full_sort<O: Into<TableSortOptions>>(&mut self, options: O) -> TskReturnValue {
let b = Bookmark::new();
self.sort(&b, options)
}
/// Sorts the individual table in place, so that parents come before children,
/// and the parent column is remapped as required. Node references to individuals
/// are also updated.
///
/// This function is needed because neither [``sort``](crate::TableCollection::sort) nor
/// [``full_sort``](crate::TableCollection::full_sort) sorts
/// the individual table!
///
/// # Examples
///
/// ```
/// // Parent comes AFTER the child
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let i0 = tables.add_individual(0, None, &[1]).unwrap();
/// assert_eq!(i0, 0);
/// let i1 = tables.add_individual(0, None, None).unwrap();
/// assert_eq!(i1, 1);
/// let n0 = tables.add_node(0, 0.0, -1, i1).unwrap();
/// assert_eq!(n0, 0);
/// let n1 = tables.add_node(0, 1.0, -1, i0).unwrap();
/// assert_eq!(n1, 1);
///
/// // Testing for valid individual order will Err:
/// match tables.check_integrity(tskit::TableIntegrityCheckFlags::CHECK_INDIVIDUAL_ORDERING) {
/// Ok(_) => panic!("expected Err"),
/// Err(_) => (),
/// };
///
/// // The standard sort doesn't fix the Err...:
/// tables.full_sort(tskit::TableSortOptions::default()).unwrap();
/// match tables.check_integrity(tskit::TableIntegrityCheckFlags::CHECK_INDIVIDUAL_ORDERING) {
/// Ok(_) => panic!("expected Err"),
/// Err(_) => (),
/// };
///
/// // ... so we need to intentionally sort the individuals.
/// let _ = tables.topological_sort_individuals(tskit::IndividualTableSortOptions::default()).unwrap();
/// tables.check_integrity(tskit::TableIntegrityCheckFlags::CHECK_INDIVIDUAL_ORDERING).unwrap();
/// ```
///
/// # Errors
///
/// Will return an error code if the underlying `C` function returns an error.
pub fn topological_sort_individuals<O: Into<IndividualTableSortOptions>>(
&mut self,
options: O,
) -> TskReturnValue {
let rv = unsafe {
ll_bindings::tsk_table_collection_individual_topological_sort(
self.as_mut_ptr(),
options.into().bits(),
)
};
handle_tsk_return_value!(rv)
}
/// Dump the table collection to file.
///
/// # Panics
///
/// This function allocates a `CString` to pass the file name to the C API.
/// A panic will occur if the system runs out of memory.
pub fn dump<O: Into<TableOutputOptions>>(&self, filename: &str, options: O) -> TskReturnValue {
let c_str = std::ffi::CString::new(filename).map_err(|_| {
TskitError::LibraryError("call to ffi::CString::new failed".to_string())
})?;
let rv = unsafe {
ll_bindings::tsk_table_collection_dump(
self.as_ptr(),
c_str.as_ptr(),
options.into().bits(),
)
};
handle_tsk_return_value!(rv)
}
/// Clear the contents of all tables.
/// Does not release memory.
/// Memory will be released when the object goes out
/// of scope.
pub fn clear<O: Into<TableClearOptions>>(&mut self, options: O) -> TskReturnValue {
let rv = unsafe {
ll_bindings::tsk_table_collection_clear(self.as_mut_ptr(), options.into().bits())
};
handle_tsk_return_value!(rv)
}
/// Free all memory allocated on the C side.
/// Not public b/c not very safe.
#[allow(dead_code)]
fn free(&mut self) -> TskReturnValue {
let rv = unsafe { ll_bindings::tsk_table_collection_free(self.as_mut_ptr()) };
handle_tsk_return_value!(rv)
}
/// Return ``true`` if ``self`` contains the same
/// data as ``other``, and ``false`` otherwise.
pub fn equals<O: Into<TableEqualityOptions>>(
&self,
other: &TableCollection,
options: O,
) -> bool {
unsafe {
ll_bindings::tsk_table_collection_equals(
self.as_ptr(),
other.as_ptr(),
options.into().bits(),
)
}
}
/// Return a "deep" copy of the tables.
pub fn deepcopy(&self) -> Result<TableCollection, TskitError> {
// The output is UNINITIALIZED tables,
// else we leak memory
let mut inner = uninit_table_collection();
let rv = unsafe { ll_bindings::tsk_table_collection_copy(self.as_ptr(), &mut *inner, 0) };
// SAFETY: we just initialized it.
// The C API doesn't free NULL pointers.
handle_tsk_return_value!(rv, unsafe { Self::new_from_mbox(inner)? })
}
/// Return a [`crate::TreeSequence`] based on the tables.
/// This function will raise errors if tables are not sorted,
/// not indexed, or invalid in any way.
pub fn tree_sequence(
self,
flags: TreeSequenceFlags,
) -> Result<crate::TreeSequence, TskitError> {
crate::TreeSequence::new(self, flags)
}
/// Simplify tables in place.
///
/// # Parameters
///
/// * `samples`: a slice containing non-null node ids.
/// The tables are simplified with respect to the ancestry
/// of these nodes.
/// * `options`: A [`SimplificationOptions`] bit field controlling
/// the behavior of simplification.
/// * `idmap`: if `true`, the return value contains a vector equal
/// in length to the input node table. For each input node,
/// this vector either contains the node's new index or [`NodeId::NULL`]
/// if the input node is not part of the simplified history.
pub fn simplify<O: Into<SimplificationOptions>>(
&mut self,
samples: &[NodeId],
options: O,
idmap: bool,
) -> Result<Option<&[NodeId]>, TskitError> {
if idmap {
self.idmap.resize(
usize::try_from(self.views.nodes().num_rows())?,
NodeId::NULL,
);
}
let rv = unsafe {
ll_bindings::tsk_table_collection_simplify(
self.as_mut_ptr(),
samples.as_ptr().cast::<tsk_id_t>(),
samples.len() as tsk_size_t,
options.into().bits(),
match idmap {
true => self.idmap.as_mut_ptr().cast::<tsk_id_t>(),
false => std::ptr::null_mut(),
},
)
};
handle_tsk_return_value!(
rv,
match idmap {
true => Some(&self.idmap),
false => None,
}
)
}
/// Validate the contents of the table collection
///
/// # Parameters
///
/// `flags` is an instance of [`TableIntegrityCheckFlags`]
///
/// # Return value
///
/// `0` upon success, or an error code.
/// However, if `flags` contains [`TableIntegrityCheckFlags::CHECK_TREES`],
/// and no error is returned, then the return value is the number
/// of trees.
///
/// # Note
///
/// Creating a [`crate::TreeSequence`] from a table collection will automatically
/// run an integrity check.
/// See [`TableCollection::tree_sequence`].
///
/// # Examples
///
/// There are many ways for a table colletion to be invalid.
/// These examples are just the tip of the iceberg.
///
/// ```should_panic
/// let mut tables = tskit::TableCollection::new(10.0).unwrap();
/// // Right position is > sequence_length
/// tables.add_edge(0.0, 11.0, 0, 0);
/// tables.check_integrity(tskit::TableIntegrityCheckFlags::default()).unwrap();
/// ```
///
/// ```should_panic
/// # let mut tables = tskit::TableCollection::new(10.0).unwrap();
/// // Left position is < 0.0
/// tables.add_edge(-1., 10.0, 0, 0);
/// tables.check_integrity(tskit::TableIntegrityCheckFlags::default()).unwrap();
/// ```
///
/// ```should_panic
/// # let mut tables = tskit::TableCollection::new(10.0).unwrap();
/// // Edges cannot have null node ids
/// tables.add_edge(0., 10.0, tskit::NodeId::NULL, 0);
/// tables.check_integrity(tskit::TableIntegrityCheckFlags::default()).unwrap();
/// ```
pub fn check_integrity(&self, flags: TableIntegrityCheckFlags) -> TskReturnValue {
let rv = unsafe {
ll_bindings::tsk_table_collection_check_integrity(self.as_ptr(), flags.bits())
};
handle_tsk_return_value!(rv)
}
/// Add provenance record with a time stamp.
///
/// All implementation of this trait provided by `tskit` use
/// an `ISO 8601` format time stamp
/// written using the [RFC 3339](https://tools.ietf.org/html/rfc3339)
/// specification.
/// This formatting approach has been the most straightforward method
/// for supporting round trips to/from a [`crate::provenance::ProvenanceTable`].
/// The implementations used here use the [`humantime`](https://docs.rs/humantime/latest/humantime/) crate.
///
/// # Parameters
///
/// * `record`: the provenance record
///
/// # Examples
/// ```
///
/// let mut tables = tskit::TableCollection::new(1000.).unwrap();
/// # #[cfg(feature = "provenance")] {
/// tables.add_provenance(&String::from("Some provenance")).unwrap();
///
/// // Get reference to the table
/// let prov_ref = tables.provenances();
///
/// // Get the first row
/// let row_0 = prov_ref.row(0).unwrap();
///
/// assert_eq!(row_0.record, "Some provenance");
///
/// // Get the first record
/// let record_0 = prov_ref.record(0).unwrap();
/// assert_eq!(record_0, row_0.record);
///
/// // Get the first time stamp
/// let timestamp = prov_ref.timestamp(0).unwrap();
/// assert_eq!(timestamp, row_0.timestamp);
///
/// // You can get the `humantime::Timestamp` object back from the `String`:
/// use core::str::FromStr;
/// let timestamp_string = humantime::Timestamp::from_str(×tamp).unwrap();
///
/// // Provenance transfers to the tree sequences
/// let treeseq = tables.tree_sequence(tskit::TreeSequenceFlags::BUILD_INDEXES).unwrap();
/// assert_eq!(treeseq.provenances().record(0).unwrap(), "Some provenance");
/// // We can still compare to row_0 because it is a copy of the row data:
/// assert_eq!(treeseq.provenances().record(0).unwrap(), row_0.record);
/// # }
/// ```
#[cfg(feature = "provenance")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "provenance")))]
pub fn add_provenance(&mut self, record: &str) -> Result<crate::ProvenanceId, TskitError> {
self.provenances_mut().add_row(record)
}
/// Set the edge table from an [`OwningEdgeTable`](`crate::OwningEdgeTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut edges = tskit::OwningEdgeTable::default();
/// edges.add_row(0., 1., 0, 12).unwrap();
/// tables.set_edges(&edges).unwrap();
/// assert_eq!(tables.edges().num_rows(), 1);
/// assert_eq!(tables.edges().child(0).unwrap(), 12);
/// # edges.clear().unwrap();
/// # assert_eq!(edges.num_rows(), 0);
/// ```
pub fn set_edges(&mut self, edges: &crate::OwningEdgeTable) -> TskReturnValue {
// SAFETY: neither self nor edges are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_edge_table_set_columns(
&mut self.inner.edges,
(*edges.as_ptr()).num_rows,
(*edges.as_ptr()).left,
(*edges.as_ptr()).right,
(*edges.as_ptr()).parent,
(*edges.as_ptr()).child,
(*edges.as_ptr()).metadata,
(*edges.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
/// Set the node table from an [`OwningNodeTable`](`crate::OwningNodeTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut nodes = tskit::OwningNodeTable::default();
/// nodes.add_row(0, 10.0, -1, -1).unwrap();
/// tables.set_nodes(&nodes).unwrap();
/// assert_eq!(tables.nodes().num_rows(), 1);
/// assert_eq!(tables.nodes().time(0).unwrap(), 10.0);
/// # nodes.clear().unwrap();
/// # assert_eq!(nodes.num_rows(), 0);
/// ```
pub fn set_nodes(&mut self, nodes: &crate::OwningNodeTable) -> TskReturnValue {
// SAFETY: neither self nor nodes are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_node_table_set_columns(
&mut self.inner.nodes,
(*nodes.as_ptr()).num_rows,
(*nodes.as_ptr()).flags,
(*nodes.as_ptr()).time,
(*nodes.as_ptr()).population,
(*nodes.as_ptr()).individual,
(*nodes.as_ptr()).metadata,
(*nodes.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
/// Set the site table from an [`OwningSiteTable`](`crate::OwningSiteTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut sites = tskit::OwningSiteTable::default();
/// sites.add_row(11.0, None).unwrap();
/// tables.set_sites(&sites).unwrap();
/// assert_eq!(tables.sites().num_rows(), 1);
/// assert_eq!(tables.sites().position(0).unwrap(), 11.0);
/// # sites.clear().unwrap();
/// # assert_eq!(sites.num_rows(), 0);
/// ```
pub fn set_sites(&mut self, sites: &crate::OwningSiteTable) -> TskReturnValue {
// SAFETY: neither self nor nodes are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_site_table_set_columns(
&mut self.inner.sites,
(*sites.as_ptr()).num_rows,
(*sites.as_ptr()).position,
(*sites.as_ptr()).ancestral_state,
(*sites.as_ptr()).ancestral_state_offset,
(*sites.as_ptr()).metadata,
(*sites.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
/// Set the mutation table from an [`OwningMutationTable`](`crate::OwningSiteTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut mutations = tskit::OwningMutationTable::default();
/// mutations.add_row(14, 12, -1, 11.3, None).unwrap();
/// tables.set_mutations(&mutations).unwrap();
/// assert_eq!(tables.mutations().num_rows(), 1);
/// assert_eq!(tables.mutations().site(0).unwrap(), 14);
/// # mutations.clear().unwrap();
/// # assert_eq!(mutations.num_rows(), 0);
/// ```
pub fn set_mutations(&mut self, mutations: &crate::OwningMutationTable) -> TskReturnValue {
// SAFETY: neither self nor nodes are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_mutation_table_set_columns(
&mut self.inner.mutations,
(*mutations.as_ptr()).num_rows,
(*mutations.as_ptr()).site,
(*mutations.as_ptr()).node,
(*mutations.as_ptr()).parent,
(*mutations.as_ptr()).time,
(*mutations.as_ptr()).derived_state,
(*mutations.as_ptr()).derived_state_offset,
(*mutations.as_ptr()).metadata,
(*mutations.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
/// Set the individual table from an [`OwningIndividualTable`](`crate::OwningSiteTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut individuals = tskit::OwningIndividualTable::default();
/// individuals.add_row(0, [0.1, 10.0], None).unwrap();
/// tables.set_individuals(&individuals).unwrap();
/// assert_eq!(tables.individuals().num_rows(), 1);
/// let expected = vec![tskit::Location::from(0.1), tskit::Location::from(10.0)];
/// assert_eq!(tables.individuals().location(0), Some(expected.as_slice()));
/// # individuals.clear().unwrap();
/// # assert_eq!(individuals.num_rows(), 0);
/// ```
pub fn set_individuals(
&mut self,
individuals: &crate::OwningIndividualTable,
) -> TskReturnValue {
// SAFETY: neither self nor nodes are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_individual_table_set_columns(
&mut self.inner.individuals,
(*individuals.as_ptr()).num_rows,
(*individuals.as_ptr()).flags,
(*individuals.as_ptr()).location,
(*individuals.as_ptr()).location_offset,
(*individuals.as_ptr()).parents,
(*individuals.as_ptr()).parents_offset,
(*individuals.as_ptr()).metadata,
(*individuals.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
/// Set the migration table from an [`OwningMigrationTable`](`crate::OwningSiteTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut migrations = tskit::OwningMigrationTable::default();
/// migrations.add_row((0.25, 0.37), 1, (0, 1), 111.0).unwrap();
/// tables.set_migrations(&migrations).unwrap();
/// assert_eq!(tables.migrations().num_rows(), 1);
/// assert_eq!(tables.migrations().time(0).unwrap(), 111.0);
/// # migrations.clear().unwrap();
/// # assert_eq!(migrations.num_rows(), 0);
/// ```
pub fn set_migrations(&mut self, migrations: &crate::OwningMigrationTable) -> TskReturnValue {
// SAFETY: neither self nor edges are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_migration_table_set_columns(
&mut self.inner.migrations,
(*migrations.as_ptr()).num_rows,
(*migrations.as_ptr()).left,
(*migrations.as_ptr()).right,
(*migrations.as_ptr()).node,
(*migrations.as_ptr()).source,
(*migrations.as_ptr()).dest,
(*migrations.as_ptr()).time,
(*migrations.as_ptr()).metadata,
(*migrations.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
/// Set the population table from an [`OwningPopulationTable`](`crate::OwningSiteTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut populations = tskit::OwningPopulationTable::default();
/// populations.add_row().unwrap();
/// tables.set_populations(&populations).unwrap();
/// assert_eq!(tables.populations().num_rows(), 1);
/// # populations.clear().unwrap();
/// # assert_eq!(populations.num_rows(), 0);
/// ```
pub fn set_populations(
&mut self,
populations: &crate::OwningPopulationTable,
) -> TskReturnValue {
// SAFETY: neither self nor edges are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_population_table_set_columns(
&mut self.inner.populations,
(*populations.as_ptr()).num_rows,
(*populations.as_ptr()).metadata,
(*populations.as_ptr()).metadata_offset,
)
};
handle_tsk_return_value!(rv)
}
#[cfg(feature = "provenance")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "provenance")))]
/// Set the provenance table from an
/// [`OwningProvenanceTable`](`crate::provenance::OwningProvenanceTable`)
///
/// # Errors
///
/// Any errors from the C API propagate.
///
/// # Example
///
/// ```rust
/// # #[cfg(feature="provenance")] {
/// #
/// let mut tables = tskit::TableCollection::new(1.0).unwrap();
/// let mut provenances = tskit::provenance::OwningProvenanceTable::default();
/// provenances.add_row("I like pancakes").unwrap();
/// tables.set_provenances(&provenances).unwrap();
/// assert_eq!(tables.provenances().num_rows(), 1);
/// assert_eq!(tables.provenances().record(0).unwrap(), "I like pancakes");
/// # provenances.clear().unwrap();
/// # assert_eq!(provenances.num_rows(), 0);
/// # }
/// ```
pub fn set_provenances(
&mut self,
provenances: &crate::provenance::OwningProvenanceTable,
) -> TskReturnValue {
// SAFETY: neither self nor edges are possible
// to create with null pointers.
let rv = unsafe {
ll_bindings::tsk_provenance_table_set_columns(
&mut self.inner.provenances,
(*provenances.as_ptr()).num_rows,
(*provenances.as_ptr()).timestamp,
(*provenances.as_ptr()).timestamp_offset,
(*provenances.as_ptr()).record,
(*provenances.as_ptr()).record_offset,
)
};
handle_tsk_return_value!(rv)
}
delegate! {
to self.views {
/// Get mutable reference to the [``NodeTable``](crate::NodeTable).
pub fn nodes_mut(&mut self) -> &mut crate::NodeTable;
/// Get mutable reference to the [``EdgeTable``](crate::EdgeTable).
pub fn edges_mut(&mut self) -> &mut crate::EdgeTable;
/// Get mutable reference to the [``SiteTable``](crate::SiteTable).
pub fn sites_mut(&mut self) -> &mut crate::SiteTable;
/// Get mutable reference to the [``MutationTable``](crate::MutationTable).
pub fn mutations_mut(&mut self) -> &mut crate::MutationTable;
/// Get mutable reference to the [``IndividualTable``](crate::IndividualTable).
pub fn individuals_mut(&mut self) -> &mut crate::IndividualTable;
/// Get mutable reference to the [``PopulationTable``](crate::PopulationTable).
pub fn populations_mut(&mut self) -> &mut crate::PopulationTable;
/// Get mutable reference to the [``MigrationTable``](crate::PopulationTable).
pub fn migrations_mut(&mut self) -> &mut crate::MigrationTable;
#[cfg(feature="provenance")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "provenance")))]
/// Get mutable reference to the [``ProvenanceTable``](crate::ProvenanceTable).
pub fn provenances_mut(&mut self) -> &mut crate::provenance::ProvenanceTable;
}
}
delegate_table_view_api!();
/// Pointer to the low-level C type.
pub fn as_ptr(&self) -> *const ll_bindings::tsk_table_collection_t {
&*self.inner
}
/// Mutable pointer to the low-level C type.
pub fn as_mut_ptr(&mut self) -> *mut ll_bindings::tsk_table_collection_t {
&mut *self.inner
}
}
#[test]
fn test_mutable_node_references() {
let mut tables = crate::TableCollection::new(10.0).unwrap();
let _nodes: &mut crate::NodeTable = tables.nodes_mut();
let _edges: &mut crate::EdgeTable = tables.edges_mut();
let _sites: &mut crate::SiteTable = tables.sites_mut();
let _mutations: &mut crate::MutationTable = tables.mutations_mut();
let _individuals: &mut crate::IndividualTable = tables.individuals_mut();
let _populations: &mut crate::PopulationTable = tables.populations_mut();
let _migrations: &mut crate::MigrationTable = tables.migrations_mut();
#[cfg(feature = "provenance")]
let _provenances: &mut crate::provenance::ProvenanceTable = tables.provenances_mut();
}