Skip to main content

Crate wavefst

Crate wavefst 

Source
Expand description

§wavefst

Crates.io Documentation CI License

Safe, fast Rust reader and writer for GTKWave’s Fast Signal Trace (FST) format.

wavefst reads existing FST waveforms and writes files accepted by GTKWave and the reference libfst implementation. It supports indexed signal and time-range selection for interactive viewers, bounded streaming for simulators, and the standard FST compression formats.

§Why wavefst?

  • Bidirectional compatibility – a pinned libfst oracle verifies every supported disk layout in both directions.
  • Selective access – load chosen handles and time windows without decompressing unrelated signal chains or value-change blocks.
  • Reader and writer – one crate covers waveform analysis, viewers, converters, and simulators.
  • Controlled resources – streaming block checkpoints and configurable allocation limits keep large traces bounded.
  • Explicit performance controls – serial execution is the default; parallel codecs, async I/O, serde, FastLZ, and SIMD helpers are feature-selected.

§Installation

cargo add wavefst

Default features include the reader, writer, libdeflate-backed gzip/zlib, LZ4, and the SSE2 packed bit writer path. The gzip feature builds bundled libdeflate and therefore requires a C compiler.

§Quick start

§Read selected signals and time

use wavefst::ReaderBuilder;

fn read_window(path: &str) -> wavefst::Result<()> {
    let file = std::fs::File::open(path)?;
    let mut reader = ReaderBuilder::new(file)
        .include_handles([1, 7, 42])
        .time_range(1_000..=2_000)
        .build()?;

    while let Some(changes) = reader.next_value_changes()? {
        changes.try_for_each_parts(|time, handle, alias_of, value| {
            println!("{time} {handle} {alias_of:?} {value:?}");
        })?;
    }
    Ok(())
}

Omit either filter to read every handle or timestamp. Handles are one-based and time ranges are inclusive. Applications that already know their handles can add .load_hierarchy(false).

§Write a trace

use wavefst::{FstWriter, GeomEntry, Header, ScopeType, SignalValue, VarDir, VarType};

fn write_trace(path: &str) -> wavefst::Result<()> {
    let file = std::fs::File::create(path)?;
    let mut writer = FstWriter::builder(file).build()?;

    writer.begin_scope(ScopeType::VcdModule, "tb", None)?;
    let signal = writer.add_variable(
        VarType::VcdWire,
        VarDir::Implicit,
        "valid",
        GeomEntry::Fixed(1),
    )?;
    writer.end_scope()?;
    writer.write_header(Header::default())?;
    writer.emit_change(0, signal, SignalValue::Bit('0'))?;
    writer.emit_change(10, signal, SignalValue::Bit('1'))?;
    writer.finish()?;
    Ok(())
}

Dense binary simulators can submit a whole timestamp through emit_binary_batch, avoiding per-event type dispatch.

§Features

FeatureDefaultPurpose
readeryesFST metadata, hierarchy, indexed selection, and value traversal
writeryesStreaming FST creation and chain deduplication
gzipyeslibdeflate-backed gzip wrappers/hierarchies and zlib chains
lz4yesLZ4 hierarchy blocks and value chains
simdyesSSE2 ASCII-to-bit packing; implies writer
fastlznoFastLZ value-chain compression and decompression
parallelnoRayon codec and traversal support; runtime policy remains serial
async-read / async-writenoTokio-backed async front ends
serdenoSerializable hierarchy and value-change snapshots

Features are additive. Minimal reader-only and writer-only builds are supported:

cargo add wavefst --no-default-features --features "reader gzip lz4"

§Performance

The checked-in benchmark suite measures wall time, physical and logical I/O, peak RSS, CPU cycles, output size, and delivered event counts. The headline selective-access workload contains 500,000 signals, 100 timestamps, and 50 million changes:

Querywavefstlibfstfst-reader 0.17Wellen 0.25.6
10 signals0.365 s0.435 s0.697 s1.160 s
100 signals0.363 s0.444 s0.803 s1.192 s
1% time0.041 s0.473 s2.525 s130.959 s
100 signals × 1% time0.022 s0.030 s0.024 s1.215 s
100 dragged viewports0.398 s0.707 s0.805 s1.206 s

These are reproducible workload results, not universal claims. In a paired cold-cache run, libfst led the combined signal/time query by 0.6 ms while wavefst read fewer bytes and used fewer cycles. See BENCHMARKS.md for complete tables, methodology, limitations, pinned revisions, raw CSV links, and reproduction commands.

§Compatibility and quality

The compatibility matrix maps every libfst disk tag to reader/writer support. CI compiles the pinned C reference implementation and verifies a generated corpus bidirectionally, in addition to running:

  • Rustfmt, Clippy with all features, and rustdoc with warnings denied;
  • stable tests on Linux, macOS, and Windows, plus beta Rust;
  • reader/writer feature combinations and a selective-access smoke benchmark;
  • package verification before release.

Useful entry points:

§License

Licensed under the standard MIT License.

Re-exports§

pub use async_support::AsyncReader;
pub use async_support::read_all as async_read_all;
pub use async_support::AsyncWriter;
pub use async_support::AsyncWriterBuilder;
pub use block::BlackoutBlock;
pub use block::BlackoutEvent;
pub use block::GeomEntry;
pub use block::GeomInfo;
pub use block::Header;
pub use block::HierarchyBlock;
pub use block::HierarchyCompression;
pub use block::ScopeEntry;
pub use block::TimeSection;
pub use block::VarEntry;
pub use block::VcBlock;
pub use error::Error;
pub use error::Result;
pub use reader::ChainData;
pub use reader::ChainIndex;
pub use reader::ChainPayload;
pub use reader::ChainSlot;
pub use reader::FstReader;
pub use reader::ReaderBuilder;
pub use reader::ReaderOptions;
pub use reader::VcBlockMeta;
pub use serde_support::AttributeNode;
pub use serde_support::HierarchySnapshot;
pub use serde_support::OwnedSignalValue;
pub use serde_support::OwnedValueChange;
pub use serde_support::ScopeNode;
pub use serde_support::VariableNode;
pub use serde_support::collect_value_changes;
pub use serde_support::snapshot_hierarchy;
pub use writer::AttributeId;
pub use writer::ChainCompression;
pub use writer::DynamicAliasEncoding;
pub use writer::FstWriter;
pub use writer::ScopeId;
pub use writer::SupplementalVariableMetadata;
pub use writer::TimeCompression;
pub use writer::WriterBuilder;
pub use writer::WriterOptions;
pub use types::*;

Modules§

async_support
Async helpers that wrap the synchronous reader and writer APIs.
block
Block-level data structures mapping raw FST sections into typed records. Structured representations of the different FST block types.
encoding
Encoding helpers such as variable-length integer codecs. Encoding helpers (varints, zig-zag encoding, etc.).
error
Shared error and result types.
io
Buffered I/O backends and reader/writer traits. I/O backends used by the reader and writer implementations.
reader
Streaming reader front-end for FST files. High-level streaming reader for FST files.
serde_support
Helper utilities for exporting FST metadata and value changes through serde.
types
Enumerations and value abstractions used across the crate. Core type definitions used across the crate.
writer
Streaming writer for constructing FST traces. Incremental writer producing FST output streams.