Skip to content

Commit b37a2a1

Browse files
committed
doc: add mdbook
* add gh-pages.yml * Make sure book examples work for MSRV
1 parent f6d3a94 commit b37a2a1

File tree

6 files changed

+215
-0
lines changed

6 files changed

+215
-0
lines changed

.github/workflows/gh-pages.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: github pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
release:
8+
types: [created]
9+
pull_request:
10+
11+
jobs:
12+
deploy:
13+
runs-on: ubuntu-20.04
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Cancel Previous Runs
20+
uses: styfle/cancel-workflow-action@0.11.0
21+
with:
22+
access_token: ${{ secrets.GITHUB_TOKEN }}
23+
24+
- name: Setup mdBook
25+
uses: peaceiris/actions-mdbook@v1
26+
with:
27+
mdbook-version: 'latest'
28+
29+
- run: mdbook build book
30+
31+
- name: Deploy
32+
uses: peaceiris/actions-gh-pages@v3
33+
if: github.event_name == 'release'
34+
with:
35+
github_token: ${{ secrets.GITHUB_TOKEN }}
36+
publish_dir: ./book/book

book/book.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[book]
2+
authors = ["Kevin R. Thornton"]
3+
language = "en"
4+
multilingual = false
5+
src = "src"
6+
title = "The tskit (rust) book"

book/src/SUMMARY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Summary
2+
3+
- [Introduction](./introduction.md)
4+
- [Working with table collections](./working_with_table_collections.md)

book/src/introduction.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Introduction <img align="right" width="73" height="45" src="https://raw.githubusercontent.com/tskit-dev/administrative/main/logos/svg/tskit-rust/Tskit_rust_logo.eps.svg">
2+
3+
## Do you need `tskit-rust`?
4+
5+
The use-cases for `tskit-rust` are the same as for `tskit-c`:
6+
7+
1. Developing a new performance-oriented application.
8+
2. The input/output of this application will be a `.trees` file.
9+
10+
## What does `tskit-rust` add?
11+
12+
Briefly, you get the performance of `C` and the strong safety guarantees of `rust`.
13+
14+
## What is `tskit-rust` missing?
15+
16+
The crate does not cover the entire `C` API.
17+
However, client code can make direct calls to that API via the module `tskit::bindings`.
18+
19+
## Adding `tskit` as a dependency to a rust project
20+
21+
In your `Cargo.toml`:
22+
23+
```{toml}
24+
[dependencies]
25+
tskit = "~X.Y.Z"
26+
```
27+
28+
The latest version to fill in `X.Y.Z` can be found [here](https://crates.io/crates/tskit).
29+
See [here](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html) for how to specify version numbers.
30+
31+
### Feature flags.
32+
33+
`tskit` defines several [cargo features](https://doc.rust-lang.org/cargo/reference/features.html).
34+
These are defined in the [API docs](https://docs.rs/tskit/latest/tskit/#optional-features).
35+
36+
## Conventions used in this document
37+
38+
We assume a working knowledge of rust.
39+
Thus, we skip over the details of things like matching idioms, etc.,
40+
and just `.unwrap()`.
41+
42+
We also assume familiarity with the `tskit` [data model](https://tskit.dev/tskit/docs/stable/data-model.html).
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Creating a TableCollection <img align="right" width="73" height="45" src="https://raw.githubusercontent.com/tskit-dev/administrative/main/logos/svg/tskit-rust/Tskit_rust_logo.eps.svg">
2+
3+
## Creation
4+
5+
We initialize a `TableCollection` with a sequence length.
6+
In `tskit-c`, the genome length is a C `double`.
7+
Here it is a [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html) called `tskit::Position`:
8+
9+
```rust, noplaygound, ignore
10+
{{#include ../../tests/book_table_collection.rs:create_table_collection_with_newtype}}
11+
```
12+
13+
The newtype pattern gives type safety by disallowing you to send a position to a function where a time is required, etc..
14+
However, it can be inconvenient to type out the full type names every time.
15+
Thus, the API defines most functions taking arguments `Into<T>` where `T` is one of our newtypes.
16+
This design means that the following is equivalent to what we wrote above:
17+
18+
```rust, noplaygound, ignore
19+
{{#include ../../tests/book_table_collection.rs:create_table_collection}}
20+
```
21+
22+
## Adding rows to tables
23+
24+
* For each table type (node, edge., etc.), we have a function to add a row.
25+
* We can only add rows to tables in mutable `TableCollection` instances.
26+
27+
For example, to add a node:
28+
29+
```rust, noplaygound, ignore
30+
{{#include ../../tests/book_table_collection.rs:add_node_without_metadata}}
31+
```
32+
33+
We see from the `if let` pattern that functions adding rows return
34+
[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).
35+
In general, errors only occur when the C back-end fails to allocate memory
36+
to expand the table columns.
37+
If we add a row with invalid data, no error is returned!
38+
To catch such errors, we must explicitly check table integrity (see [below](working_with_table_collections.md#checking-table-integrity)).
39+
40+
Again, we can take advantage of being able to pass in any type that is `Into<_>` the required newtype:
41+
42+
```rust, noplaygound, ignore
43+
{{#include ../../tests/book_table_collection.rs:add_node_without_metadata_using_into}}
44+
```
45+
46+
See the [API docs](https://docs.rs/tskit) for more details and examples.
47+
48+
## Checking table integrity
49+
50+
The data model involves lazy checking of inputs.
51+
In other words, we can add invalid row data that is not caught by the "add row" functions.
52+
We inherit this behavior from the C API.
53+
54+
We can check that the tables contain valid data by:
55+
56+
```rust, noplaygound, ignore
57+
{{#include ../../tests/book_table_collection.rs:integrity_check}}
58+
```
59+

tests/book_table_collection.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#[test]
2+
fn simple_table_collection_creation_with_newtype() {
3+
// ANCHOR: create_table_collection_with_newtype
4+
let sequence_length = tskit::Position::from(100.0);
5+
if let Ok(tables) = tskit::TableCollection::new(sequence_length) {
6+
assert_eq!(tables.sequence_length(), sequence_length);
7+
// In tskit, the various newtypes can be compared to
8+
// the low-level types they wrap.
9+
assert_eq!(tables.sequence_length(), 100.0);
10+
} else {
11+
panic!(
12+
"TableCollection creation sequence length = {} failed",
13+
sequence_length
14+
);
15+
}
16+
// ANCHOR_END: create_table_collection_with_newtype
17+
}
18+
19+
#[test]
20+
fn simple_table_collection_creation() {
21+
// ANCHOR: create_table_collection
22+
let tables = tskit::TableCollection::new(100.0).unwrap();
23+
// ANCHOR_END: create_table_collection
24+
assert_eq!(tables.sequence_length(), 100.0);
25+
}
26+
27+
#[test]
28+
fn add_node_without_metadata() {
29+
{
30+
// ANCHOR: add_node_without_metadata
31+
let mut tables = tskit::TableCollection::new(100.0).unwrap();
32+
if let Ok(node_id) = tables.add_node(
33+
0, // Node flags
34+
tskit::Time::from(0.0), // Birth time
35+
tskit::PopulationId::NULL, // Population id
36+
tskit::IndividualId::NULL, // Individual id
37+
) {
38+
assert_eq!(node_id, 0);
39+
}
40+
// ANCHOR_END: add_node_without_metadata
41+
}
42+
{
43+
let mut tables = tskit::TableCollection::new(100.0).unwrap();
44+
// ANCHOR: add_node_without_metadata_using_into
45+
let node_id = tables.add_node(0, 0.0, -1, -1).unwrap();
46+
// ANCHOR_END: add_node_without_metadata_using_into
47+
assert_eq!(node_id, 0);
48+
}
49+
}
50+
51+
#[test]
52+
fn add_node_handle_error() {
53+
// ANCHOR: integrity_check
54+
let mut tables = tskit::TableCollection::new(100.0).unwrap();
55+
// Everything about this edge is wrong...
56+
tables.add_edge(-1.0, 110.0, 0, 1).unwrap();
57+
// ...and we can catch that here
58+
match tables.check_integrity(tskit::TableIntegrityCheckFlags::default()) {
59+
Ok(code) => panic!("expected Err(e) but got code: {}", code),
60+
// tskit::TskitError can be formatted into the same
61+
// error messages that tskit-c/tskit-python give.
62+
Err(e) => println!("{}", e),
63+
}
64+
// ANCHOR_END: integrity_check
65+
assert!(tables
66+
.check_integrity(tskit::TableIntegrityCheckFlags::default())
67+
.is_err());
68+
}

0 commit comments

Comments
 (0)