rtemis-a3
Rust implementation of the Amino Acid Annotation (A3) format — a structured JSON format for amino acid sequences with site, region, PTM, processing, and variant annotations.
Part of the rtemis-org/a3 monorepo, which provides A3 implementations in Python, TypeScript, R, Julia, and Rust.
[!NOTE] The Rust code contains extensive comments and documentation as an educational tool to help learn Rust.
Installation
Add to your Cargo.toml:
[]
= "0.1"
CLI
The a3 binary validates an A3 JSON file and prints a summary.
Install from crates.io:
Usage:
Pass - as <FILE> to read from stdin.
Options:
| Flag | Description |
|---|---|
-l, --limit <N> |
Max sequence residues to display (default: 20) |
-q, --quiet |
Suppress all output; use exit code only |
-j, --json |
Output results in JSON format |
-D, --diagnose |
Full step-by-step diagnostic validation (all errors) |
-h, --help |
Print help |
-V, --version |
Print version |
Example — valid file:
$ a3 tau.json
✓ valid A3 1.0.0 https://schema.rtemis.org/a3/v1/schema.json
Sequence MAEPRQEFEVMEDHAGTYGL… (length = 441)
Annotations
├── site 2
├── region 1
├── ptm 3
├── processing —
└── variant 5
Metadata
├── UniProt ID P10636
├── Description Microtubule-associated protein tau
├── Reference —
└── Organism Homo sapiens
Example — invalid file:
$ a3 bad.json
✗ invalid
├── annotations.site.foo: position 999 is out of bounds for sequence of length 6 (must be 1–6)
└── annotations.region: annotation name must not be empty
Sequence MAEPRQ (length = 6)
...
Exit codes:
| Code | Meaning |
|---|---|
0 |
Valid |
1 |
Invalid (A3 validation errors) |
2 |
Error (bad arguments, file not found, JSON parse failure) |
Use --quiet for scripting:
if ; then
fi
Quick Start
use ;
let json = r#"{
"$schema": "https://schema.rtemis.org/a3/v1/schema.json",
"a3_version": "1.0.0",
"sequence": "MKTAYIAKQR",
"annotations": {
"site": { "Active site": { "index": [3, 5], "type": "activeSite" } },
"region": { "Repeat 1": { "index": [[1, 4]], "type": "" } },
"ptm": { "Phospho": { "index": [7], "type": "" } },
"processing": {},
"variant": [{ "position": 3, "from": "K", "to": "R" }]
},
"metadata": {
"uniprot_id": "P12345",
"description": "Example protein",
"reference": "",
"organism": "Homo sapiens"
}
}"#;
let a3 = a3_from_json.unwrap;
println!; // 10
println!; // compact JSON
println!; // pretty-printed
Parsing JSON
use ;
match a3_from_json
Querying
use ;
// 1-based position; returns Option<char>
if let Some = residue_at
// All variant records at a position
let vars = variants_at;
Wire Format
All five annotation families are always present in output. Each annotation
entry is { index, type } — bare arrays are rejected. Positions are
1-based, sorted, and deduplicated. Ranges are [start, end] pairs
(start < end), sorted by start; overlapping ranges are rejected.
API
Parsing and serialization
| Function | Description |
|---|---|
a3_from_json(text: &str) |
Parse a JSON string into a validated A3 |
a3_to_json(a3: &A3, indent: Option<usize>) |
Serialize to JSON; None = compact, Some(n) = n-space indent |
Queries
| Function | Description |
|---|---|
residue_at(a3: &A3, position: u32) |
Residue at a 1-based position; None if out of bounds |
variants_at<'a>(a3: &'a A3, position: u32) |
All variant records at a 1-based position |
Type hierarchy
A3
├── sequence: String
├── annotations: Annotations
│ ├── site: HashMap<String, SiteEntry> (position index)
│ ├── region: HashMap<String, RegionEntry> (range index)
│ ├── ptm: HashMap<String, FlexEntry> (position or range index)
│ ├── processing: HashMap<String, FlexEntry> (position or range index)
│ └── variant: Vec<VariantRecord>
└── metadata: Metadata
├── uniprot_id, description, reference, organism: String
A3Index is an enum that holds either Positions(Vec<u32>) or Ranges(Vec<[u32; 2]>),
used as the index type inside FlexEntry.
Errors
All violations are collected before returning — you see every problem at once, not just the first one.
License
Validation
Validation is collect-all. A document is checked in four stages — envelope,
structural, intra-field, contextual — and every issue in the earliest failing
stage is reported at once. Each issue carries a stable code and an
RFC 6901 JSON Pointer path, both of
which are identical across the R, Python, Julia, TypeScript, and Rust
implementations of A3. Messages are for humans and are not contractual.
use a3_from_json;
let err = a3_from_json.unwrap_err;
assert_eq!;
for issue in err.issues
The CLI emits the same structure, which makes it usable as the conformance oracle when debugging another implementation:
$ a3 --json broken.a3.json
{
"valid": false,
"stage": 4,
"issues": [
{
"code": "A3E_POS_OUT_OF_BOUNDS",
"path": "/annotations/site/Active site/index/2",
"message": "position 99 is out of bounds for a sequence of length 24 (must be 1-24)"
}
]
}
--diagnose is deprecated and ignored: every run is now a full diagnostic.