macro_rules! general_data_body {
($self: expr, $field: ident, $name: ident, $len: ident, $cast: ty) => {
if $self.$field.$len > 0 {
let size = usize::try_from($self.$field.$len).unwrap();
assert!(!$self.$field.$name.is_null());
Some(unsafe { std::slice::from_raw_parts($self.$field.$name.cast::<$cast>(), size) })
} else {
None
}
};
($self: expr, $name: ident, $len: ident, $cast: ty) => {
if $self.0.$len > 0 {
let size = usize::try_from($self.0.$len).unwrap();
assert!(!$self.0.$name.is_null());
Some(unsafe { std::slice::from_raw_parts($self.0.$name.cast::<$cast>(), size) })
} else {
None
}
};
}
macro_rules! metadata_body {
($self: expr, $field: ident) => {
general_data_body!($self, $field, metadata, metadata_length, u8)
};
($self: expr) => {
general_data_body!($self, metadata, metadata_length, u8)
};
}
#[cfg(feature = "provenance")]
macro_rules! data_to_str {
($self: expr, $name: ident, $len: ident) => {{
assert!($self.row.$len > 0);
assert!(!$self.row.$name.is_null());
let len = usize::try_from($self.row.$len).unwrap();
let bytes = unsafe { std::slice::from_raw_parts($self.row.$name.cast::<u8>(), len) };
std::str::from_utf8(bytes).unwrap()
}};
}
#[derive(Debug)]
#[repr(transparent)]
pub struct SiteRef<'p>(&'p super::bindings::tsk_site_t);
impl<'p> std::cmp::PartialEq for SiteRef<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.position().eq(&other.position())
&& self.ancestral_state().eq(&other.ancestral_state())
&& self.metadata().eq(&other.metadata())
&& self.mutation_iter().eq(other.mutation_iter())
}
}
pub(super) fn new_site_ref<'p>(site: &'p super::bindings::tsk_site_t) -> SiteRef<'p> {
SiteRef(site)
}
pub struct MutationRefIterator<'ts> {
mutations: &'ts [super::bindings::tsk_mutation_t],
}
impl<'ts> Iterator for MutationRefIterator<'ts> {
type Item = super::MutationRef<'ts>;
fn next(&mut self) -> Option<Self::Item> {
if let Some((l, r)) = self.mutations.split_first() {
self.mutations = r;
Some(MutationRef(l))
} else {
None
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.mutations = if n < self.mutations.len() {
&self.mutations[n..]
} else {
&[]
};
self.next()
}
}
impl<'ts> DoubleEndedIterator for MutationRefIterator<'ts> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some((l, r)) = self.mutations.split_last() {
self.mutations = r;
Some(MutationRef(l))
} else {
None
}
}
}
impl<'parent> SiteRef<'parent> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::SiteId {
self.0.id.into()
}
#[inline(always)]
pub fn position(&self) -> super::newtypes::Position {
self.0.position.into()
}
pub fn mutation_iter(&self) -> impl DoubleEndedIterator<Item = MutationRef<'parent>> {
assert!(!self.0.mutations.is_null());
let mslice = unsafe {
std::slice::from_raw_parts(self.0.mutations, self.0.mutations_length as usize)
};
MutationRefIterator { mutations: mslice }
}
pub fn ancestral_state(&self) -> Option<&[u8]> {
general_data_body!(self, ancestral_state, ancestral_state_length, u8)
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self)
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct MutationRef<'p>(&'p super::bindings::tsk_mutation_t);
impl<'p> std::cmp::PartialEq for MutationRef<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.site().eq(&other.site())
&& self.node().eq(&other.node())
&& self.parent().eq(&other.parent())
&& self.edge().eq(&other.edge())
&& self.time().eq(&other.time())
&& self.derived_state().eq(&other.derived_state())
&& self.metadata().eq(&other.metadata())
&& self.inherited_state().eq(&other.inherited_state())
}
}
impl<'parent> MutationRef<'parent> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::MutationId {
self.0.id.into()
}
#[inline(always)]
pub fn site(&self) -> super::newtypes::SiteId {
self.0.site.into()
}
#[inline(always)]
pub fn node(&self) -> super::newtypes::NodeId {
self.0.node.into()
}
#[inline(always)]
pub fn parent(&self) -> super::newtypes::MutationId {
self.0.parent.into()
}
#[inline(always)]
pub fn time(&self) -> super::newtypes::Time {
self.0.time.into()
}
#[inline(always)]
pub fn edge(&self) -> super::newtypes::EdgeId {
self.0.edge.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self)
}
pub fn derived_state(&self) -> Option<&[u8]> {
general_data_body!(self, derived_state, derived_state_length, u8)
}
pub fn inherited_state(&self) -> Option<&[u8]> {
general_data_body!(self, inherited_state, inherited_state_length, u8)
}
}
#[derive(Debug)]
pub struct Site<'p> {
pub(super) row: super::bindings::tsk_site_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Site<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.position().eq(&other.position())
&& self.ancestral_state().eq(&other.ancestral_state())
&& self.metadata().eq(&other.metadata())
}
}
impl<'p> Site<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::SiteId {
self.row.id.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
pub fn ancestral_state(&self) -> Option<&[u8]> {
general_data_body!(self, row, ancestral_state, ancestral_state_length, u8)
}
#[inline(always)]
pub fn position(&self) -> super::newtypes::Position {
self.row.position.into()
}
}
#[derive(Debug)]
pub struct Mutation<'p> {
pub(super) row: super::bindings::tsk_mutation_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Mutation<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.site().eq(&other.site())
&& self.node().eq(&other.node())
&& self.parent().eq(&other.parent())
&& self.edge().eq(&other.edge())
&& self.time().eq(&other.time())
&& self.derived_state().eq(&other.derived_state())
&& self.metadata().eq(&other.metadata())
}
}
impl<'p> Mutation<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::MutationId {
self.row.id.into()
}
#[inline(always)]
pub fn site(&self) -> super::newtypes::SiteId {
self.row.site.into()
}
#[inline(always)]
pub fn node(&self) -> super::newtypes::NodeId {
self.row.node.into()
}
#[inline(always)]
pub fn parent(&self) -> super::newtypes::MutationId {
self.row.parent.into()
}
#[inline(always)]
pub fn time(&self) -> super::newtypes::Time {
self.row.time.into()
}
#[inline(always)]
pub fn edge(&self) -> super::newtypes::EdgeId {
self.row.edge.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
pub fn derived_state(&self) -> Option<&[u8]> {
general_data_body!(self, row, derived_state, derived_state_length, u8)
}
}
#[derive(Debug)]
pub struct Edge<'p> {
pub(super) row: super::bindings::tsk_edge_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Edge<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.parent().eq(&other.parent())
&& self.child().eq(&other.child())
&& self.left().eq(&other.left())
&& self.right().eq(&other.right())
&& self.metadata().eq(&other.metadata())
}
}
impl<'p> Edge<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::EdgeId {
self.row.id.into()
}
#[inline(always)]
pub fn left(&self) -> super::newtypes::Position {
self.row.left.into()
}
#[inline(always)]
pub fn right(&self) -> super::newtypes::Position {
self.row.right.into()
}
#[inline(always)]
pub fn parent(&self) -> super::newtypes::NodeId {
self.row.parent.into()
}
#[inline(always)]
pub fn child(&self) -> super::newtypes::NodeId {
self.row.child.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
}
#[derive(Debug)]
pub struct Migration<'p> {
pub(super) row: super::bindings::tsk_migration_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Migration<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.source().eq(&other.source())
&& self.dest().eq(&other.dest())
&& self.node().eq(&other.node())
&& self.left().eq(&other.left())
&& self.time().eq(&other.time())
&& self.metadata().eq(&other.metadata())
}
}
impl<'p> Migration<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::MigrationId {
self.row.id.into()
}
#[inline(always)]
pub fn left(&self) -> super::newtypes::Position {
self.row.left.into()
}
#[inline(always)]
pub fn right(&self) -> super::newtypes::Position {
self.row.right.into()
}
#[inline(always)]
pub fn source(&self) -> super::newtypes::PopulationId {
self.row.source.into()
}
#[inline(always)]
pub fn dest(&self) -> super::newtypes::PopulationId {
self.row.dest.into()
}
#[inline(always)]
pub fn time(&self) -> super::newtypes::Time {
self.row.time.into()
}
#[inline(always)]
pub fn node(&self) -> super::newtypes::NodeId {
self.row.node.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
}
#[derive(Debug)]
pub struct Individual<'p> {
pub(super) row: super::bindings::tsk_individual_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Individual<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.flags().eq(&other.flags())
&& self.location().eq(&other.location())
&& self.parents().eq(&other.parents())
&& self.metadata().eq(&other.metadata())
&& self.nodes().eq(&other.nodes())
}
}
impl<'p> Individual<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::IndividualId {
self.row.id.into()
}
#[inline(always)]
pub fn flags(&self) -> super::flags::IndividualFlags {
self.row.flags.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
pub fn location(&self) -> Option<&[super::newtypes::Location]> {
general_data_body!(
self,
row,
location,
location_length,
super::newtypes::Location
)
}
pub fn parents(&self) -> Option<&[super::newtypes::IndividualId]> {
general_data_body!(
self,
row,
parents,
parents_length,
super::newtypes::IndividualId
)
}
pub fn nodes(&self) -> Option<&[super::newtypes::NodeId]> {
general_data_body!(self, row, nodes, nodes_length, super::newtypes::NodeId)
}
}
#[derive(Debug)]
pub struct Node<'p> {
pub(super) row: super::bindings::tsk_node_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Node<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.flags().eq(&other.flags())
&& self.time().eq(&other.time())
&& self.population().eq(&other.population())
&& self.individual().eq(&other.individual())
&& self.metadata().eq(&other.metadata())
}
}
impl<'p> Node<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::NodeId {
self.row.id.into()
}
#[inline(always)]
pub fn flags(&self) -> super::flags::NodeFlags {
self.row.flags.into()
}
#[inline(always)]
pub fn time(&self) -> super::newtypes::Time {
self.row.time.into()
}
#[inline(always)]
pub fn population(&self) -> super::newtypes::PopulationId {
self.row.population.into()
}
#[inline(always)]
pub fn individual(&self) -> super::newtypes::IndividualId {
self.row.population.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
}
#[derive(Debug)]
pub struct Population<'p> {
pub(super) row: super::bindings::tsk_population_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
impl<'p> std::cmp::PartialEq for Population<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id()) && self.metadata().eq(&other.metadata())
}
}
impl<'p> Population<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::PopulationId {
self.row.id.into()
}
pub fn metadata(&self) -> Option<&[u8]> {
metadata_body!(self, row)
}
}
#[derive(Debug)]
#[cfg(feature = "provenance")]
pub struct Provenance<'p> {
pub(super) row: super::bindings::tsk_provenance_t,
pub(super) marker: std::marker::PhantomData<&'p ()>,
}
#[cfg(feature = "provenance")]
impl<'p> std::cmp::PartialEq for Provenance<'p> {
fn eq(&self, other: &Self) -> bool {
self.id().eq(&other.id())
&& self.timestamp().eq(other.timestamp())
&& self.record().eq(other.record())
}
}
#[cfg(feature = "provenance")]
impl<'p> Provenance<'p> {
#[inline(always)]
pub fn id(&self) -> super::newtypes::ProvenanceId {
self.row.id.into()
}
pub fn timestamp(&self) -> &str {
data_to_str!(self, timestamp, timestamp_length)
}
pub fn record(&self) -> &str {
data_to_str!(self, record, record_length)
}
}
#[test]
fn test_transmute() {
let mut mutation =
unsafe { std::mem::MaybeUninit::<super::bindings::tsk_mutation_t>::zeroed().assume_init() };
mutation.site = 11;
mutation.edge = -1;
let mref =
unsafe { std::mem::transmute::<super::bindings::tsk_mutation_t, Mutation<'_>>(mutation) };
assert_eq!(mref.id(), 0);
assert_eq!(mref.site(), 11);
assert_eq!(mref.edge(), -1);
let mref2 = super::Mutation::<'_> {
row: mutation,
marker: std::marker::PhantomData,
};
assert_eq!(mref, mref2);
}
#[cfg(test)]
mod test_row_type_wrappers {
use super::super::bindings::*;
use super::super::newtypes::*;
macro_rules! sizeof_and_layout {
($a: ty, $b: ty) => {
assert_eq!(std::mem::size_of::<$a>(), std::mem::size_of::<$b>());
let ll_layout = std::alloc::Layout::new::<$a>();
let wrapper_layout = std::alloc::Layout::new::<$b>();
assert_eq!(ll_layout, wrapper_layout);
};
}
macro_rules! set_scalar_field {
($x: ident, $($field: ident),* ; $($id: literal),*)=> {
$($x.$field = $id;)*
};
}
macro_rules! set_pointer_field {
($x: ident, $($field: ident),* ; $($length: ident),* ; $($cast: ty),*) => {
$(
$x.$field = $field.as_ptr().cast::<$cast>();
$x.$length = u64::try_from($field.len()).unwrap();
)*
};
}
#[test]
fn test_size_of_and_layout() {
sizeof_and_layout!(tsk_mutation_t, super::Mutation<'_>);
sizeof_and_layout!(tsk_mutation_t, super::Mutation<'_>);
sizeof_and_layout!(&tsk_mutation_t, super::MutationRef<'_>);
sizeof_and_layout!(tsk_site_t, super::Site<'_>);
sizeof_and_layout!(&tsk_site_t, super::SiteRef<'_>);
sizeof_and_layout!(tsk_edge_t, super::Edge<'_>);
sizeof_and_layout!(tsk_node_t, super::Node<'_>);
sizeof_and_layout!(tsk_individual_t, super::Individual<'_>);
sizeof_and_layout!(tsk_migration_t, super::Migration<'_>);
#[cfg(feature = "provenance")]
sizeof_and_layout!(tsk_provenance_t, super::Provenance<'_>);
}
#[test]
fn test_tsk_mutation_t_wrappers() {
let mut ll_mutation =
unsafe { std::mem::MaybeUninit::<tsk_mutation_t>::zeroed().assume_init() };
set_scalar_field!(ll_mutation, id, site, node, edge, time ; 10, 11, 12, -1, 50.);
let mutation =
unsafe { std::mem::transmute::<tsk_mutation_t, super::Mutation<'_>>(ll_mutation) };
assert_eq!(mutation, mutation);
assert_eq!(mutation.id(), MutationId::from(10));
assert_eq!(mutation.site(), SiteId::from(11));
assert_eq!(mutation.node(), NodeId::from(12));
assert_eq!(mutation.edge(), EdgeId::NULL);
assert_eq!(mutation.time(), Time::from(50.));
assert!(mutation.metadata().is_none());
assert!(mutation.derived_state().is_none());
{
let mut ll_mutation2 = ll_mutation;
set_scalar_field!(ll_mutation2, site; 100);
let mutation2 =
unsafe { std::mem::transmute::<tsk_mutation_t, super::Mutation<'_>>(ll_mutation2) };
assert_ne!(mutation, mutation2);
}
{
let metadata = b"I is metadatum".to_vec();
let derived_state = b"G".to_vec();
let inherited_state = b"CAGT".to_vec();
set_pointer_field!(ll_mutation, metadata, derived_state, inherited_state ;
metadata_length, derived_state_length, inherited_state_length ;
libc::c_char, libc::c_char, libc::c_char);
let mutation =
unsafe { std::mem::transmute::<tsk_mutation_t, super::Mutation<'_>>(ll_mutation) };
assert_eq!(mutation.metadata(), Some(metadata.as_slice()));
assert_eq!(mutation.derived_state(), Some(derived_state.as_slice()));
let mutation_ref = super::MutationRef(&ll_mutation);
assert_eq!(mutation.metadata(), Some(metadata.as_slice()));
assert_eq!(mutation.derived_state(), Some(derived_state.as_slice()));
assert_eq!(
mutation_ref.inherited_state(),
Some(inherited_state.as_slice())
);
}
}
}