COOLJAPAN
← All posts

PandRS 0.3.1 Released — Pure Rust Excel I/O Backed by OxiARC, Zero C Compression Libs

High-performance DataFrame library for Rust — pandas-class API with SIMD, parallel, and distributed processing. 0.3.1 swaps the Excel/xlsx C-dependency chain (zip/flate2/miniz_oxide via calamine + simple_excel_writer) for an in-tree OxiARC-backed xlsx engine, removes the dirs -sys crate, and pins datafusion/parquet/arrow to drop liblzma/zstd-sys/lz4-sys. 1809 tests + 117 doc tests passing, zero clippy warnings. The DataFrame layer of the COOLJAPAN scientific stack.

release pandrs dataframe pure-rust oxiarc excel parquet scirs2

The DataFrame layer of the COOLJAPAN scientific stack just went a lot more Pure Rust.

Today we released PandRS 0.3.1 — a patch release that rips the hidden C-dependency chain out of DataFrame Excel and compression I/O and replaces it with an in-tree, OxiARC-backed xlsx engine.

No C. No Cython. No bundled zlib/xz/zstd C libs. No Python GIL.
Just a pandas-class DataFrame API — SIMD, parallel, and distributed — that compiles to a single static binary (or WASM) and runs everywhere, from laptops to edge devices to cloud clusters.

Why PandRS 0.3.1 matters

DataFrame Excel and compression stacks have a quiet C-dependency creep problem. Read an .xlsx file and you usually drag in zip, which drags in flate2, which drags in miniz_oxide or worse, a system zlib. Read a Parquet file and you can quietly pull zstd-sys, lz4-sys, and liblzma-sys (C libxz) through DataFusion and Arrow defaults. None of that shows up in your code — it shows up in your build, your supply chain, and your cross-compilation pain.

PandRS 0.3.1 closes those holes:

The public xlsx API is fully preserved — ExcelCell, ExcelCellFormat, NamedRange, and friends are all kept. This is a swap of the engine, not the interface.

Technical Deep Dive: A Pure Rust xlsx engine behind a preserved facade

1. The in-tree src/io/xlsx/ engine (OxiARC + quick-xml).
.xlsx is a ZIP container of XML parts. The old path used calamine (read) and simple_excel_writer (write), both of which lean on the zip/flate2/miniz_oxide C-flavored compression chain. We replaced both with a from-scratch reader/writer split across a new module — reader.rs, writer.rs, cell.rs, schema.rs, error.rs, mod.rs — built on oxiarc-archive for the Pure Rust ZIP layer and quick-xml for the XML. src/io/excel.rs is now a thin facade that forwards to crate::io::xlsx, so the public surface is unchanged. Advanced features behave as before; formula and named-range tracking is deferred to a follow-up. A new tests/excel_roundtrip_test.rs guards the write-then-read cycle. The net dependency change: oxiarc-archive 0.2.6 + quick-xml 0.39.2 added under excel; calamine and simple_excel_writer removed.

2. The -sys purge.
The dirs crate pulled dirs-sys for config-directory lookups. We replaced it with an inline user_config_dir() in src/config/loader.rs honoring XDG / macOS / Windows conventions, returning Option<PathBuf> with identical semantics. After this, cargo build --no-default-features has zero -sys crates outside the unavoidable OS-API set — the only survivor is core-foundation-sys, pulled by iana-time-zone/chrono for macOS timezone resolution, which is genuine OS FFI.

3. Pinning datafusion / parquet / arrow to drop C libs.

4. Honest tech debt and intentional regressions.
We are not pretending this is free. Two regressions are deliberate under the Pure Rust policy: zstd-compressed Parquet is no longer readable on --features stable/parquet (Snappy — the pandas default — gzip, brotli, and lz4 still work), and DataFusion’s built-in xz/bz2/zstd auto-decompression for CSV/JSON readers is disabled on distributed/flight/serving (plain + gzip still work). And some feature-gated debt remains upstream: parquet/distributed/flight still transitively pull flate2/lz4_flex/snap/brotli/miniz_oxide via Arrow/Parquet/DataFusion; --features distributed/flight still pull zstd-sys/miniz_oxide because DataFusion 53.1.0’s own Cargo.toml hardcodes default-features = true on parquet (Cargo features are additive — we can’t suppress upstream; this needs an upstream fix); and cloud-storage pulls ring (C+asm) via object_store 0.13.2. The default build pulls none of these.

Getting Started

cargo add pandrs --features excel
use pandrs::{DataFrame, Series};

fn main() -> pandrs::error::Result<()> {
    let mut df = DataFrame::new();
    df.add_column(
        "quarter".to_string(),
        Series::from_vec(vec!["Q1", "Q2", "Q3", "Q4"], Some("quarter")),
    )?;
    df.add_column(
        "revenue".to_string(),
        Series::from_vec(vec![120.5, 138.2, 151.0, 169.8], Some("revenue")),
    )?;

    // xlsx I/O is now Pure Rust — backed by OxiARC, no zip/flate2/miniz_oxide
    df.to_excel("report.xlsx", None)?;
    let reloaded = DataFrame::from_excel("report.xlsx", None)?;
    println!("round-tripped {} rows", reloaded.shape().0);
    Ok(())
}

What’s New in 0.3.1

Tips

This is the foundation

PandRS is the DataFrame layer of the COOLJAPAN scientific stack — it pairs with NumRS2 for arrays and SciRS2 for the broader scientific/AI primitives (now on 0.4.2). With 0.3.1, the data-loading floor of that stack leans on OxiARC for Pure Rust archive and compression — the same OxiARC ZIP and codec work that backs the rest of the ecosystem. Around it sit period-accurate siblings: OptiRS for optimization, SkleaRS for classical ML, TenfloweRS and TrustformeRS for deep learning, OxiMedia for media/CV, and the lower-level OxiFFT / OxiZ / OxiBLAS / OxiCode crates. The point is sovereignty: every layer compiles from source, with no C/Cython/bundled-codec baggage.

Repository: https://github.com/cool-japan/pandrs

Star the repo if you want a pandas-class DataFrame without the hidden C compression libs or the Python GIL.

The era of “pip install pandas” — dragging in zlib, xz, and zstd C libraries you never asked for — is ending.

Pure Rust DataFrames are here — fast, safe, and sovereign.

KitaSan at COOLJAPAN OÜ April 19, 2026

↑ Back to all posts