Skip to content

Commit d7ca90a

Browse files
committed
Add macro to aid returning from MetadataRoundtrip functions.
Add example to MetadataRoundtrip docs.
1 parent 79adaa1 commit d7ca90a

File tree

3 files changed

+83
-24
lines changed

3 files changed

+83
-24
lines changed

src/_macros.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,18 @@ macro_rules! tree_array_slice {
236236
};
237237
}
238238

239+
/// Convenience macro to handle implementing
240+
/// [`crate::metadata::MetadataRoundtrip`]
241+
#[macro_export]
242+
macro_rules! handle_metadata_return {
243+
($e: expr) => {
244+
match $e {
245+
Ok(x) => Ok(x),
246+
Err(e) => Err($crate::metadata::MetadataError::RoundtripError { value: Box::new(e) }),
247+
}
248+
};
249+
}
250+
239251
#[cfg(test)]
240252
mod test {
241253
use crate::error::TskitError;

src/metadata.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,73 @@
1+
//! Support for table row metadata
2+
13
use crate::bindings::{tsk_id_t, tsk_size_t};
24
use thiserror::Error;
35

6+
/// Enable a type to be used as table metadata
7+
///
8+
/// See [`handle_metadata_return`] for a macro to help implement this trait,
9+
/// and its use in examples below.
10+
///
11+
/// We strongly recommend the use of the [serde](https://serde.rs/) ecosystem
12+
/// for row metadata.
13+
/// For many use cases, we imagine that
14+
/// [bincode](https://crates.io/crates/bincode) will be one of
15+
/// the more useful `serde`-related crates.
16+
///
17+
/// # Examples
18+
///
19+
/// ## Mutation metadata
20+
///
21+
/// ```
22+
/// use tskit::handle_metadata_return;
23+
/// use tskit::TableAccess;
24+
///
25+
/// #[derive(serde::Serialize, serde::Deserialize)]
26+
/// pub struct MyMutation {
27+
/// origin_time: i32,
28+
/// effect_size: f64,
29+
/// dominance: f64,
30+
/// }
31+
///
32+
/// impl tskit::metadata::MetadataRoundtrip for MyMutation {
33+
/// fn encode(&self) -> Result<Vec<u8>, tskit::metadata::MetadataError> {
34+
/// handle_metadata_return!(bincode::serialize(&self))
35+
/// }
36+
///
37+
/// fn decode(md: &[u8]) -> Result<Self, tskit::metadata::MetadataError> {
38+
/// handle_metadata_return!(bincode::deserialize(md))
39+
/// }
40+
/// }
41+
///
42+
/// let mut tables = tskit::TableCollection::new(100.).unwrap();
43+
/// let mutation = MyMutation{origin_time: 100,
44+
/// effect_size: -1e-4,
45+
/// dominance: 0.25};
46+
///
47+
/// // Add table row with metadata.
48+
/// tables.add_mutation_with_metadata(0, 0, tskit::TSK_NULL, 100., None,
49+
/// Some(&mutation)).unwrap();
50+
///
51+
/// // Decode the metadata
52+
/// // The two unwraps are:
53+
/// // 1. Handle Errors vs Option.
54+
/// // 2. Handle the option for the case of no error.
55+
/// let decoded = tables.mutations().metadata::<MyMutation>(0).unwrap().unwrap();
56+
/// assert_eq!(mutation.origin_time, decoded.origin_time);
57+
/// match decoded.effect_size.partial_cmp(&mutation.effect_size) {
58+
/// Some(std::cmp::Ordering::Greater) => assert!(false),
59+
/// Some(std::cmp::Ordering::Less) => assert!(false),
60+
/// Some(std::cmp::Ordering::Equal) => (),
61+
/// None => panic!("bad comparison"),
62+
/// };
63+
/// match decoded.dominance.partial_cmp(&mutation.dominance) {
64+
/// Some(std::cmp::Ordering::Greater) => assert!(false),
65+
/// Some(std::cmp::Ordering::Less) => assert!(false),
66+
/// Some(std::cmp::Ordering::Equal) => (),
67+
/// None => panic!("bad comparison"),
68+
/// };
69+
///
70+
/// ```
471
pub trait MetadataRoundtrip {
572
fn encode(&self) -> Result<Vec<u8>, MetadataError>;
673
fn decode(md: &[u8]) -> Result<Self, MetadataError>

src/test_fixtures.rs

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -86,41 +86,21 @@ pub mod bad_metadata {
8686

8787
impl crate::metadata::MetadataRoundtrip for F {
8888
fn encode(&self) -> Result<Vec<u8>, crate::metadata::MetadataError> {
89-
match bincode::serialize(&self) {
90-
Ok(v) => Ok(v),
91-
Err(e) => {
92-
Err(crate::metadata::MetadataError::RoundtripError { value: Box::new(e) })
93-
}
94-
}
89+
handle_metadata_return!(bincode::serialize(&self))
9590
}
9691

9792
fn decode(md: &[u8]) -> Result<Self, crate::metadata::MetadataError> {
98-
match bincode::deserialize(md) {
99-
Ok(x) => Ok(x),
100-
Err(e) => {
101-
Err(crate::metadata::MetadataError::RoundtripError { value: Box::new(e) })
102-
}
103-
}
93+
handle_metadata_return!(bincode::deserialize(md))
10494
}
10595
}
10696

10797
impl crate::metadata::MetadataRoundtrip for Ff {
10898
fn encode(&self) -> Result<Vec<u8>, crate::metadata::MetadataError> {
109-
match bincode::serialize(&self) {
110-
Ok(v) => Ok(v),
111-
Err(e) => {
112-
Err(crate::metadata::MetadataError::RoundtripError { value: Box::new(e) })
113-
}
114-
}
99+
handle_metadata_return!(bincode::serialize(&self))
115100
}
116101

117102
fn decode(md: &[u8]) -> Result<Self, crate::metadata::MetadataError> {
118-
match bincode::deserialize(md) {
119-
Ok(x) => Ok(x),
120-
Err(e) => {
121-
Err(crate::metadata::MetadataError::RoundtripError { value: Box::new(e) })
122-
}
123-
}
103+
handle_metadata_return!(bincode::deserialize(md))
124104
}
125105
}
126106
}

0 commit comments

Comments
 (0)