Skip to content

Commit 25cc8b6

Browse files
authored
refactor: provenance table getters now return Option (#369)
* empty provenance records are now errors BREAKING CHANGE: return types and behavior for empty data.
1 parent 704924b commit 25cc8b6

File tree

3 files changed

+59
-33
lines changed

3 files changed

+59
-33
lines changed

src/_macros.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ macro_rules! unsafe_tsk_ragged_column_access {
104104
#[allow(unused_macros)]
105105
macro_rules! unsafe_tsk_ragged_char_column_access {
106106
($i: expr, $lo: expr, $hi: expr, $owner: expr, $array: ident, $offset_array: ident, $offset_array_len: ident) => {{
107-
let i = $crate::SizeType::try_from($i)?;
107+
let i = $crate::SizeType::try_from($i).ok()?;
108108
if $i < $lo || i >= $hi {
109-
Err(TskitError::IndexError {})
109+
None
110110
} else if $owner.$offset_array_len == 0 {
111-
Ok(None)
111+
None
112112
} else {
113113
assert!(!$owner.$array.is_null());
114114
assert!(!$owner.$offset_array.is_null());
@@ -119,13 +119,13 @@ macro_rules! unsafe_tsk_ragged_char_column_access {
119119
$owner.$offset_array_len as tsk_size_t
120120
};
121121
if start == stop {
122-
Ok(None)
122+
None
123123
} else {
124124
let mut buffer = String::new();
125125
for i in start..stop {
126126
buffer.push(unsafe { *$owner.$array.offset(i as isize) as u8 as char });
127127
}
128-
Ok(Some(buffer))
128+
Some(buffer)
129129
}
130130
}
131131
}};
@@ -1028,6 +1028,9 @@ macro_rules! provenance_table_add_row {
10281028
($(#[$attr:meta])* => $name: ident, $self: ident, $table: expr) => {
10291029
$(#[$attr])*
10301030
pub fn $name(&mut $self, record: &str) -> Result<$crate::ProvenanceId, $crate::TskitError> {
1031+
if record.is_empty() {
1032+
return Err($crate::TskitError::ValueError{got: "empty string".to_string(), expected: "provenance record".to_string()})
1033+
}
10311034
let timestamp = humantime::format_rfc3339(std::time::SystemTime::now()).to_string();
10321035
let rv = unsafe {
10331036
$crate::bindings::tsk_provenance_table_add_row(

src/provenance.rs

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
use crate::bindings as ll_bindings;
1616
use crate::SizeType;
17-
use crate::{tsk_id_t, tsk_size_t, ProvenanceId, TskitError};
17+
use crate::{tsk_id_t, tsk_size_t, ProvenanceId};
1818
use ll_bindings::{tsk_provenance_table_free, tsk_provenance_table_init};
1919

2020
#[derive(Eq)]
@@ -47,8 +47,8 @@ impl std::fmt::Display for ProvenanceTableRow {
4747
fn make_provenance_row(table: &ProvenanceTable, pos: tsk_id_t) -> Option<ProvenanceTableRow> {
4848
Some(ProvenanceTableRow {
4949
id: pos.into(),
50-
timestamp: table.timestamp(pos).ok()?,
51-
record: table.record(pos).ok()?,
50+
timestamp: table.timestamp(pos)?,
51+
record: table.record(pos)?,
5252
})
5353
}
5454

@@ -103,47 +103,66 @@ impl<'a> ProvenanceTable<'a> {
103103

104104
/// Get the ISO-formatted time stamp for row `row`.
105105
///
106-
/// # Errors
106+
/// # Returns
107+
///
108+
/// * `Some(String)` if `row` is valid.
109+
/// * `None` otherwise.
107110
///
108-
/// [`TskitError::IndexError`] if `r` is out of range.
109-
pub fn timestamp<P: Into<ProvenanceId> + Copy>(&'a self, row: P) -> Result<String, TskitError> {
110-
match unsafe_tsk_ragged_char_column_access!(
111+
/// # Examples
112+
///
113+
/// ```
114+
/// use tskit::TableAccess;
115+
/// let mut tables = tskit::TableCollection::new(10.).unwrap();
116+
/// assert!(tables.add_provenance("foo").is_ok());
117+
/// if let Some(timestamp) = tables.provenances().timestamp(0) {
118+
/// // then 0 is a valid row in the provenance table
119+
/// }
120+
/// # else {
121+
/// # panic!("Expected Some(timestamp)");
122+
/// # }
123+
/// ```
124+
pub fn timestamp<P: Into<ProvenanceId> + Copy>(&'a self, row: P) -> Option<String> {
125+
unsafe_tsk_ragged_char_column_access!(
111126
row.into().0,
112127
0,
113128
self.num_rows(),
114129
self.table_,
115130
timestamp,
116131
timestamp_offset,
117132
timestamp_length
118-
) {
119-
Ok(Some(string)) => Ok(string),
120-
Ok(None) => Err(crate::TskitError::ValueError {
121-
got: String::from("None"),
122-
expected: String::from("String"),
123-
}),
124-
Err(e) => Err(e),
125-
}
133+
)
126134
}
127135

128136
/// Get the provenance record for row `row`.
129137
///
130-
/// # Errors
138+
/// # Returns
139+
///
140+
/// * `Some(String)` if `row` is valid.
141+
/// * `None` otherwise.
142+
///
143+
/// # Examples
131144
///
132-
/// [`TskitError::IndexError`] if `r` is out of range.
133-
pub fn record<P: Into<ProvenanceId> + Copy>(&'a self, row: P) -> Result<String, TskitError> {
134-
match unsafe_tsk_ragged_char_column_access!(
145+
/// ```
146+
/// use tskit::TableAccess;
147+
/// let mut tables = tskit::TableCollection::new(10.).unwrap();
148+
/// assert!(tables.add_provenance("foo").is_ok());
149+
/// if let Some(record) = tables.provenances().record(0) {
150+
/// // then 0 is a valid row in the provenance table
151+
/// # assert_eq!(record, "foo");
152+
/// }
153+
/// # else {
154+
/// # panic!("Expected Some(timestamp)");
155+
/// # }
156+
pub fn record<P: Into<ProvenanceId> + Copy>(&'a self, row: P) -> Option<String> {
157+
unsafe_tsk_ragged_char_column_access!(
135158
row.into().0,
136159
0,
137160
self.num_rows(),
138161
self.table_,
139162
record,
140163
record_offset,
141164
record_length
142-
) {
143-
Ok(Some(string)) => Ok(string),
144-
Ok(None) => Ok(String::from("")),
145-
Err(e) => Err(e),
146-
}
165+
)
147166
}
148167

149168
/// Obtain a [`ProvenanceTableRow`] for row `row`.
@@ -201,16 +220,14 @@ mod test_provenances {
201220
// check for tables...
202221
let mut tables = crate::TableCollection::new(10.).unwrap();
203222
let s = String::from("");
204-
let row_id = tables.add_provenance(&s).unwrap();
205-
let _ = tables.provenances().row(row_id).unwrap();
223+
assert!(tables.add_provenance(&s).is_err());
206224

207225
// and for tree sequences...
208226
tables.build_index().unwrap();
209227
let mut ts = tables
210228
.tree_sequence(crate::TreeSequenceFlags::default())
211229
.unwrap();
212-
let row_id = ts.add_provenance(&s).unwrap();
213-
let _ = ts.provenances().row(row_id).unwrap();
230+
assert!(ts.add_provenance(&s).is_err())
214231
}
215232

216233
#[test]

src/trees.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,12 @@ impl TreeSequence {
502502
/// # }
503503
/// ```
504504
pub fn add_provenance(&mut self, record: &str) -> Result<crate::ProvenanceId, TskitError> {
505+
if record.is_empty() {
506+
return Err(TskitError::ValueError {
507+
got: "empty string".to_string(),
508+
expected: "provenance record".to_string(),
509+
});
510+
}
505511
let timestamp = humantime::format_rfc3339(std::time::SystemTime::now()).to_string();
506512
let rv = unsafe {
507513
ll_bindings::tsk_provenance_table_add_row(

0 commit comments

Comments
 (0)