Skip to content

Commit b5946a4

Browse files
authored
Redesign provenance feature: (#207)
* Remove Provenance trait * Functions from the removed trait are now part of TableAccess. * Reorganize the docs. Closes #190
1 parent 5699aab commit b5946a4

File tree

5 files changed

+145
-140
lines changed

5 files changed

+145
-140
lines changed

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,20 +426,20 @@ pub use traits::TskitTypeAccess;
426426
pub use trees::{NodeTraversalOrder, Tree, TreeSequence};
427427

428428
// Optional features
429-
#[cfg(any(doc, feature = "provenance"))]
429+
#[cfg(feature = "provenance")]
430430
pub mod provenance;
431431

432432
/// A provenance ID
433433
///
434434
/// This is an integer referring to a row of a [``provenance::ProvenanceTable``].
435435
///
436436
/// The features for this type follow the same pattern as for [``NodeId``]
437-
#[cfg(any(doc, feature = "provenance"))]
437+
#[cfg(feature = "provenance")]
438438
#[repr(transparent)]
439439
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, std::hash::Hash)]
440440
pub struct ProvenanceId(tsk_id_t);
441441

442-
#[cfg(any(doc, feature = "provenance"))]
442+
#[cfg(feature = "provenance")]
443443
impl_id_traits!(ProvenanceId);
444444

445445
/// Handles return codes from low-level tskit functions.

src/provenance.rs

Lines changed: 15 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -3,106 +3,21 @@
33
//! This module is enabled via the `"provenance"` feature and provides
44
//! the following:
55
//!
6-
//! * trait [`Provenance`], which enables populating and accessing
7-
//! [`ProvenanceTable`].
6+
//! * [`crate::TableCollection::add_provenance`]
7+
//! * [`crate::TableCollection::provenances`]
8+
//! * [`crate::TableCollection::provenances_iter`]
9+
//! * [`crate::TreeSequence::add_provenance`]
10+
//! * [`crate::TreeSequence::provenances`]
11+
//! * [`crate::TreeSequence::provenances_iter`]
12+
//! * [`ProvenanceTable`].
813
//! * [`ProvenanceTableRow`], which is the value type returned by
914
//! [`ProvenanceTable::iter`].
1015
//!
11-
//! See [`Provenance`] for examples.
1216
1317
use crate::bindings as ll_bindings;
1418
use crate::SizeType;
1519
use crate::{tsk_id_t, tsk_size_t, ProvenanceId, TskitError};
1620

17-
/// Enable provenance table access.
18-
///
19-
/// `tskit` provides implementations of this trait
20-
/// for [`crate::TableCollection`] and [`crate::TreeSequence`].
21-
#[cfg_attr(
22-
feature = "provenance",
23-
doc = r##"
24-
# Examples
25-
26-
## For table collections
27-
28-
```
29-
use tskit::provenance::Provenance;
30-
let mut tables = tskit::TableCollection::new(1000.).unwrap();
31-
tables.add_provenance(&String::from("Some provenance")).unwrap();
32-
33-
// Get reference to the table
34-
let prov_ref = tables.provenances();
35-
36-
// Get the first row
37-
let row_0 = prov_ref.row(0).unwrap();
38-
39-
assert_eq!(row_0.record, "Some provenance");
40-
41-
// Get the first record
42-
let record_0 = prov_ref.record(0).unwrap();
43-
assert_eq!(record_0, row_0.record);
44-
45-
// Get the first time stamp
46-
let timestamp = prov_ref.timestamp(0).unwrap();
47-
assert_eq!(timestamp, row_0.timestamp);
48-
49-
// You can get the `humantime::Timestamp` object back from the `String`:
50-
use core::str::FromStr;
51-
let timestamp_string = humantime::Timestamp::from_str(&timestamp).unwrap();
52-
53-
// Provenance transfers to the tree sequences
54-
let treeseq = tables.tree_sequence(tskit::TreeSequenceFlags::BUILD_INDEXES).unwrap();
55-
assert_eq!(treeseq.provenances().record(0).unwrap(), "Some provenance");
56-
// We can still compare to row_0 because it is a copy of the row data:
57-
assert_eq!(treeseq.provenances().record(0).unwrap(), row_0.record);
58-
```
59-
60-
## For tree sequences
61-
62-
```
63-
use tskit::provenance::Provenance;
64-
let mut tables = tskit::TableCollection::new(1000.).unwrap();
65-
let mut treeseq = tables.tree_sequence(tskit::TreeSequenceFlags::BUILD_INDEXES).unwrap();
66-
treeseq.add_provenance(&String::from("All your provenance r belong 2 us.")).unwrap();
67-
68-
let prov_ref = treeseq.provenances();
69-
let row_0 = prov_ref.row(0).unwrap();
70-
assert_eq!(row_0.record, "All your provenance r belong 2 us.");
71-
let record_0 = prov_ref.record(0).unwrap();
72-
assert_eq!(record_0, row_0.record);
73-
let timestamp = prov_ref.timestamp(0).unwrap();
74-
assert_eq!(timestamp, row_0.timestamp);
75-
use core::str::FromStr;
76-
let dt_utc = humantime::Timestamp::from_str(&timestamp).unwrap();
77-
println!("utc = {}", dt_utc);
78-
```
79-
80-
"##
81-
)]
82-
pub trait Provenance: crate::TableAccess {
83-
/// Add provenance record with a time stamp.
84-
///
85-
/// All implementation of this trait provided by `tskit` use
86-
/// an `ISO 8601` format time stamp
87-
/// written using the [RFC 3339](https://tools.ietf.org/html/rfc3339)
88-
/// specification.
89-
/// This formatting approach has been the most straightforward method
90-
/// for supporting round trips to/from a [`ProvenanceTable`].
91-
/// The implementations used here use the [`chrono`](https://docs.rs/chrono) crate.
92-
///
93-
/// # Parameters
94-
///
95-
/// * `record`: the provenance record
96-
fn add_provenance(&mut self, record: &str) -> Result<ProvenanceId, TskitError>;
97-
/// Return an immutable reference to the table, type [`ProvenanceTable`]
98-
fn provenances(&self) -> ProvenanceTable;
99-
/// Return an iterator over the rows of the [`ProvenanceTable`].
100-
/// See [`ProvenanceTable::iter`] for details.
101-
fn provenances_iter(&self) -> ProvenanceTableIterator {
102-
crate::table_iterator::make_table_iterator::<ProvenanceTable>(self.provenances())
103-
}
104-
}
105-
10621
#[derive(Eq)]
10722
/// Row of a [`ProvenanceTable`].
10823
pub struct ProvenanceTableRow {
@@ -130,7 +45,7 @@ impl std::fmt::Display for ProvenanceTableRow {
13045
}
13146
}
13247

133-
fn make_provenance_table_row(table: &ProvenanceTable, pos: tsk_id_t) -> Option<ProvenanceTableRow> {
48+
fn make_provenance_row(table: &ProvenanceTable, pos: tsk_id_t) -> Option<ProvenanceTableRow> {
13449
// panic is okay here, as we are handling a bad
13550
// input value before we first call this to
13651
// set up the iterator
@@ -153,7 +68,7 @@ impl<'a> Iterator for ProvenanceTableRefIterator<'a> {
15368
type Item = ProvenanceTableRow;
15469

15570
fn next(&mut self) -> Option<Self::Item> {
156-
let rv = make_provenance_table_row(self.table, self.pos);
71+
let rv = make_provenance_row(self.table, self.pos);
15772
self.pos += 1;
15873
rv
15974
}
@@ -163,7 +78,7 @@ impl<'a> Iterator for ProvenanceTableIterator<'a> {
16378
type Item = ProvenanceTableRow;
16479

16580
fn next(&mut self) -> Option<Self::Item> {
166-
let rv = make_provenance_table_row(&self.table, self.pos);
81+
let rv = make_provenance_row(&self.table, self.pos);
16782
self.pos += 1;
16883
rv
16984
}
@@ -172,7 +87,8 @@ impl<'a> Iterator for ProvenanceTableIterator<'a> {
17287
/// An immutable view of a provenance table.
17388
///
17489
/// These are not created directly.
175-
/// Instead, use [`Provenance::provenances`]
90+
/// Instead, use [`crate::TableCollection::provenances`]
91+
/// or [`crate::TreeSequence::provenances`]
17692
/// to get a reference to an existing node table;
17793
///
17894
/// # Notes
@@ -250,7 +166,7 @@ impl<'a> ProvenanceTable<'a> {
250166
if row.into() < 0 {
251167
Err(TskitError::IndexError)
252168
} else {
253-
match make_provenance_table_row(self, row.into().0) {
169+
match make_provenance_row(self, row.into().0) {
254170
Some(x) => Ok(x),
255171
None => Err(TskitError::IndexError),
256172
}
@@ -265,10 +181,10 @@ impl<'a> ProvenanceTable<'a> {
265181
}
266182

267183
#[cfg(test)]
268-
mod test_provenance_tables {
184+
mod test_provenances {
269185
use super::*;
270186
use crate::test_fixtures::make_empty_table_collection;
271-
use Provenance;
187+
use crate::TableAccess;
272188

273189
#[test]
274190
fn test_empty_record_string() {

src/table_collection.rs

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,67 @@ impl TableCollection {
769769
};
770770
handle_tsk_return_value!(rv)
771771
}
772+
773+
#[cfg(feature = "provenance")]
774+
/// Add provenance record with a time stamp.
775+
///
776+
/// All implementation of this trait provided by `tskit` use
777+
/// an `ISO 8601` format time stamp
778+
/// written using the [RFC 3339](https://tools.ietf.org/html/rfc3339)
779+
/// specification.
780+
/// This formatting approach has been the most straightforward method
781+
/// for supporting round trips to/from a [`crate::provenance::ProvenanceTable`].
782+
/// The implementations used here use the [`humantime`](https://docs.rs/humantime/latest/humantime/) crate.
783+
///
784+
/// # Parameters
785+
///
786+
/// * `record`: the provenance record
787+
///
788+
/// # Examples
789+
/// ```
790+
/// use tskit::TableAccess;
791+
/// let mut tables = tskit::TableCollection::new(1000.).unwrap();
792+
/// tables.add_provenance(&String::from("Some provenance")).unwrap();
793+
///
794+
/// // Get reference to the table
795+
/// let prov_ref = tables.provenances();
796+
///
797+
/// // Get the first row
798+
/// let row_0 = prov_ref.row(0).unwrap();
799+
///
800+
/// assert_eq!(row_0.record, "Some provenance");
801+
///
802+
/// // Get the first record
803+
/// let record_0 = prov_ref.record(0).unwrap();
804+
/// assert_eq!(record_0, row_0.record);
805+
///
806+
/// // Get the first time stamp
807+
/// let timestamp = prov_ref.timestamp(0).unwrap();
808+
/// assert_eq!(timestamp, row_0.timestamp);
809+
///
810+
/// // You can get the `humantime::Timestamp` object back from the `String`:
811+
/// use core::str::FromStr;
812+
/// let timestamp_string = humantime::Timestamp::from_str(&timestamp).unwrap();
813+
///
814+
/// // Provenance transfers to the tree sequences
815+
/// let treeseq = tables.tree_sequence(tskit::TreeSequenceFlags::BUILD_INDEXES).unwrap();
816+
/// assert_eq!(treeseq.provenances().record(0).unwrap(), "Some provenance");
817+
/// // We can still compare to row_0 because it is a copy of the row data:
818+
/// assert_eq!(treeseq.provenances().record(0).unwrap(), row_0.record);
819+
/// ```
820+
pub fn add_provenance(&mut self, record: &str) -> Result<crate::ProvenanceId, TskitError> {
821+
let timestamp = humantime::format_rfc3339(std::time::SystemTime::now()).to_string();
822+
let rv = unsafe {
823+
ll_bindings::tsk_provenance_table_add_row(
824+
&mut (*self.inner).provenances,
825+
timestamp.as_ptr() as *mut i8,
826+
timestamp.len() as tsk_size_t,
827+
record.as_ptr() as *mut i8,
828+
record.len() as tsk_size_t,
829+
)
830+
};
831+
handle_tsk_return_value!(rv, crate::ProvenanceId::from(rv))
832+
}
772833
}
773834

774835
impl TableAccess for TableCollection {
@@ -799,31 +860,15 @@ impl TableAccess for TableCollection {
799860
fn populations(&self) -> PopulationTable {
800861
PopulationTable::new_from_table(&(*self.inner).populations)
801862
}
802-
}
803-
804-
impl crate::traits::NodeListGenerator for TableCollection {}
805-
806-
#[cfg(any(doc, feature = "provenance"))]
807-
impl crate::provenance::Provenance for TableCollection {
808-
fn add_provenance(&mut self, record: &str) -> Result<crate::ProvenanceId, TskitError> {
809-
let timestamp = humantime::format_rfc3339(std::time::SystemTime::now()).to_string();
810-
let rv = unsafe {
811-
ll_bindings::tsk_provenance_table_add_row(
812-
&mut (*self.inner).provenances,
813-
timestamp.as_ptr() as *mut i8,
814-
timestamp.len() as tsk_size_t,
815-
record.as_ptr() as *mut i8,
816-
record.len() as tsk_size_t,
817-
)
818-
};
819-
handle_tsk_return_value!(rv, crate::ProvenanceId::from(rv))
820-
}
821863

864+
#[cfg(feature = "provenance")]
822865
fn provenances(&self) -> crate::provenance::ProvenanceTable {
823866
crate::provenance::ProvenanceTable::new_from_table(&(*self.inner).provenances)
824867
}
825868
}
826869

870+
impl crate::traits::NodeListGenerator for TableCollection {}
871+
827872
#[cfg(test)]
828873
mod test {
829874
use super::*;

src/traits.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,20 @@ pub trait TableAccess {
112112
) -> Box<dyn Iterator<Item = crate::individual_table::IndividualTableRow> + '_> {
113113
Box::new(make_table_iterator::<IndividualTable>(self.individuals()))
114114
}
115+
116+
#[cfg(feature = "provenance")]
117+
/// Get reference to the [``ProvenanceTable``](crate::provenance::ProvenanceTable)
118+
fn provenances(&self) -> crate::provenance::ProvenanceTable;
119+
120+
#[cfg(feature = "provenance")]
121+
/// Return an iterator over provenances
122+
fn provenances_iter(
123+
&self,
124+
) -> Box<dyn Iterator<Item = crate::provenance::ProvenanceTableRow> + '_> {
125+
Box::new(crate::table_iterator::make_table_iterator::<
126+
crate::provenance::ProvenanceTable,
127+
>(self.provenances()))
128+
}
115129
}
116130

117131
/// Interface for returning lists of node ids from

0 commit comments

Comments
 (0)