Skip to main content

openmassspec-core

openmassspec-core is the shared Rust foundation every vendor parser in the stack builds on. It defines the vendor-neutral records, the SpectrumSource trait, the canonical mzML 1.1.0 writer, and the cross-vendor conformance harness. The Apache Arrow bridge is the separate openmassspec-arrow crate.

Install​

[dependencies]
openmassspec-core = "3"

# Optional: Arrow RecordBatch builder.
openmassspec-arrow = "3"

The SpectrumSource trait​

Every vendor parser (opentfraw, opentimstdf, openwraw, openaraw, opensxraw, openszraw) implements this trait. Anything downstream of a parser - the canonical mzML writer, the Arrow batch builder, the conformance harness, the openmassspec-io umbrella, the vendor2mzml CLI - operates against &mut dyn SpectrumSource.

use openmassspec_core::{ChromatogramIter, CvTerm, RunMetadata, SpectrumIter};

pub trait SpectrumSource {
fn run_metadata(&self) -> RunMetadata;
// Box<dyn Iterator<Item = openmassspec_core::Result<SpectrumRecord>> + 'a>
fn iter_spectra<'a>(&'a mut self) -> SpectrumIter<'a>;
fn iter_chromatograms<'a>(&'a mut self) -> ChromatogramIter<'a> {
Box::new(std::iter::empty())
}
fn spectrum_count_hint(&self) -> Option<usize> { None }
fn additional_processing_steps(&self) -> Vec<CvTerm> { Vec::new() }
}

Boxed iterators (rather than RPITIT) keep the trait dyn-compatible so the rest of the stack can hold &mut dyn SpectrumSource. Items are Results: a record the parser cannot decode is an Err, never skipped.

Public API​

SymbolModulePurpose
SpectrumRecordtypesDecoded spectrum: id, ms level, polarity, rt, peaks, precursor.
PrecursorInfotypesSelected / isolated precursor, charge, activation, scan window.
ChromatogramRecordtypesTIC / BPC / SRM trace.
RunMetadatatypesRun-level CV terms: instrument, source format, native id format.
CvTermtypesA PSI-MS controlled-vocabulary term.
Polarity, Analyzer, ScanMode, MsPower, ActivationenumsStandard enumerations.
MobilityArrayKindenumsPer-peak inverse-mobility / drift-time array kind.
SpectrumSourcesourceTrait every parser implements.
write_mzmlmzmlStream a SpectrumSource to a plain mzML 1.1.0 document.
write_indexed_mzmlmzmlSame, with <indexList> + SHA-1 footer for byte-offset indexing.
write_mzml_with_options, WriteOptionsmzmlCompression and RecordErrorPolicy (fail or skip unreadable records).
WriteSummarymzmlRecords written and skipped by a write.
conformance::assert_source_invariantsconformanceCheck a live SpectrumSource for cross-vendor invariants.
conformance::assert_iter_invariantsconformanceSame, but from any IntoIterator<Item = SpectrumRecord>.
ErrorerrorAggregate thiserror-based error type.

mzML writer​

use openmassspec_core::{write_indexed_mzml, SpectrumSource};

fn export<S: SpectrumSource>(mut src: S, path: &std::path::Path)
-> openmassspec_core::Result<()>
{
let mut out = std::fs::File::create(path)?;
let summary = write_indexed_mzml(&mut src, &mut out)?;
println!("{} spectra", summary.spectra_written);
Ok(())
}

write_indexed_mzml emits a standards-compliant <indexList> plus a SHA-1 footer so downstream tools (mzML2HDF, ProteoWizard msconvert, MzIdentML builders, ...) can index-jump into the file.

Conformance harness​

The harness enforces the cross-vendor invariants every parser must satisfy, surfaced as structured ConformanceError variants (PeakArrayLengthMismatch, MobilityArrayLengthMismatch, RetentionTimeNonMonotonic, MissingPrecursor, IndexSequence, EmptySpectrum, ...).

use openmassspec_core::conformance::assert_iter_invariants;

let count = assert_iter_invariants(records)?;
println!("validated {count} spectra");
# Ok::<(), openmassspec_core::conformance::ConformanceError>(())

The vendor2mzml validate subcommand runs this harness on any vendor input or pre-existing mzML.

Arrow bridge (crate: openmassspec-arrow)​

# fn _doc() -> Result<arrow_array::RecordBatch, arrow_schema::ArrowError> {
use openmassspec_arrow::SpectrumBatchBuilder;

// Pass the source's mobility_array_kind (None for instruments without
// ion mobility); it applies to every row in the batch.
let mut b = SpectrumBatchBuilder::new(None);
for s in /* SpectrumSource iter_spectra */ std::iter::empty() {
b.push(&s);
}
let batch = b.finish()?;
# Ok(batch)
# }

The canonical schema is documented in Arrow schema.

Where it sits in the stack​