All notable changes to this project are documented here. The format is based on Keep a Changelog and the project adheres to Semantic Versioning.
1.0.0 - 2026-05-19
Stable API. The public surface is frozen. Backwards-
incompatible changes after 1.0.0 require a major version bump
per Semantic Versioning. See REPS.md section 8 for
the binding policy and docs/API.md for the
complete public-symbol reference.
No source-level changes from v0.9.0. 1.0.0 is a freeze, a
documentation polish, and the CI gate that protects the
guarantee going forward.
Behind the line: the journey from v0.1.0 (scaffold) to v1.0.0
landed the full REPS.md section 4 surface - Source, Stage,
Sink, Emit, the typed builder with closure adapters, count /
byte / age batching, tumbling / sliding / session windowing
behind a pluggable Clock, the FailFast / Continue /
DeadLetter error policies with shared-handle dead-letter
routing, both SyncDriver and ThreadedDriver, the open
Driver trait for custom executors, an 84-test suite covering
unit, integration, property, and doctest paths, and four
cargo-fuzz harnesses.
The CI semver-checks job no longer runs with || true.
Backwards-incompatible additions to the public surface fail CI
before they can ship.
The section was previously "Stability begins at 1.0.0,
governed by [...]". It now declares the public API frozen and
enumerates the patch / minor / major rules in full, plus the
#[non_exhaustive] reminder for Error and StageFailure.
The 7 placeholder ("To be specified at 0.4.0") is replaced
with the headline numbers from docs/BENCH.md plus a note that
they are indicative, not contractual.
The .buffer(capacity) builder method was listed in the locked
surface but never implemented. Section 4.9 records it as
post-1.0 minor-release roadmap material; section 4.10 keeps the
feature-flag table accurate.
All 0.x releases listed as shipped. Forward-looking work
(.buffer, per-stage threading, pipe-io-tokio,
StageFailure::input) explicitly marked as post-1.0 minor
releases.
Hero block, feature highlights grouped by concern (pipeline composition / backpressure-batching-windowing / error isolation / runtime / reliability), installation block with feature-flag table, quick-start snippets per surface (basic / batching / windowing / dead-letter / threaded / custom driver), examples table, status section declaring 1.0.0 stable, documentation links, version compatibility, contributing notes, license.
The intro now points at the 1.0.0 freeze and the
Stability section spells out the SemVer
rules and the #[non_exhaustive] reminder. The duplicated
feature-flag tables are harmonized.
Pure version marker; no source changes required.
There are no source-level changes to the crate code between
v0.9.0 and v1.0.0. The package contents on crates.io are
functionally identical; the version bump signals API stability.
0.9.0 - 2026-05-19
Pre-1.0 stabilization release. No public API changes. Adds the
hardening infrastructure that gates the path to 1.0.0: property
tests, fuzz harnesses, a cargo-semver-checks CI job (advisory
until 1.0.0), a documentation audit, and a per-version migration
guide.
tests/property.rs- 11 property tests usingproptest(new dev-dependency, std-only). Covers length-preservation formap, predicate semantics forfilter, order preservation for trivial pipelines, batching losslessness, batch size caps, tumbling- window losslessness, monotonic window time bounds,Continue-policy never-fails,DeadLetterpartitioning, and agreement betweenrun/run_with(SyncDriver)/run_threaded.fuzz/workspace (excluded from the main workspace) with fourcargo-fuzztargets:batching_count- count-triggered batching is lossless.batching_bytes- byte-triggered batching is lossless.try_map_continue-Continuenever produces run-level errors.window_tumbling- tumbling windows are lossless under a fake clock. Requires nightly +cargo install cargo-fuzz.
- CI gains a
semver-checksjob that runscargo-semver-checks check-release. Advisory (|| true) until a1.0.0baseline lands on crates.io; flips to a hard gate at release time. docs/MIGRATION.md- per-version upgrade notes coveringv0.1.0 -> v0.3.0throughv0.8.0 -> v0.9.0, plus the1.0.0stability commitment.proptest = "1"added as a dev-dependency. Dev-only; the published crate ships zero runtime dependencies.
Cargo.tomladdsworkspace.exclude = ["fuzz"]so the fuzz crate stays out of the main build.docs/README.mdindexesMIGRATION.md.
- No public API changes. Existing source compiles identically.
- Documentation audit pass:
cargo doc --all-features --no-depswithRUSTDOCFLAGS=-D warnings -D rustdoc::broken-intra-doc-linkspasses clean. Every public item has rustdoc;# Errors/# Panicssections present where applicable.
0.8.0 - 2026-05-19
Examples and guide release. Pure documentation and example
expansion. No public API changes from 0.7.0.
- 8 runnable examples under
examples/:basic- smallest map/filter pipeline.batching- count-triggered batching withBatchPolicy.windowing- tumbling rollup with a deterministic clock.dead_letter-try_map+.dead_letter(sink)for failure routing.threaded-ThreadedDriverviaPipeline::run_threaded.custom_driver- implementing theDrivertrait, wrappingSyncDriverwith timing instrumentation.custom_source- implementingSourcefor a stateful Fibonacci producer.etl- multi-stage ETL withErrorPolicy::Continue, enrichment lookup, batching, and a counting sink.
[[example]]entries inCargo.tomlwithrequired-features = ["std"]for all eight.docs/GUIDE.md- 11-section user guide covering the mental model, all closure adapters, custom stage / source / sink / driver implementations, batching, windowing, error policies, dead-letter routing, picking a driver, and common pitfalls.README.mdgains a Quick start snippet and a Documentation section linking to the guide, API reference, REPS, benches, and examples directory.docs/README.mdupdated to index the new documentation.
- All 8 examples build cleanly under
cargo clippy --all-targets --all-features -- -D warningsand run end-to-end with the expected output. - No changes to
src/ortests/; this release is documentation and examples only. Existing 73 tests continue to pass.
0.7.0 - 2026-05-19
Driver trait release. Closes the third (and last) deferral from
the 0.3.0 design lock. All locked surfaces from the original
design lock are now shipped.
pub trait Driverinpipe_io::driver, re-exported aspipe_io::Driver. Generic executor abstraction withSendbounds on the source and its item/error types. Not sealed; external executors (tokio, rayon, custom thread farms) can implement it.impl Driver for SyncDriverand (understd)impl Driver for ThreadedDriver. Both delegate to their existing inherentrunmethods.Pipeline::run_with<D: Driver>(driver: D)builder-terminal method. Lets callers select anyDriverimpl explicitly.- 6 integration tests in
tests/driver_trait.rs: sync via trait, threaded via trait,run_with(SyncDriver),run_with(ThreadedDriver), a customCountingDriverimpl, and a static check that the built-in and custom drivers all satisfyDriver.
REPS.mdsection 4.8 un-defers theDrivertrait; the trait-based abstraction is now part of the locked surface.docs/API.mddocuments the trait and thePipeline::run_withmethod.SyncDriver::run(inherent method) keeps its looser bound (noSendrequirement on the source). The trait impl uses the stricter bound. Both compile to the same call.
- The trait deliberately carries the stricter
Sendbound so that anyDriverimpl can be a threaded executor. To drive a non-Sendsource on the calling thread, callSyncDriver::rundirectly (inherent method); the trait method is unavailable for non-Sendsources by design. - This is the last design-lock deferral. The locked
1.0.0surface inREPS.mdis now fully implemented except forPipelineBuilder::buffer(capacity), which was listed in §4.9 but is not yet shipped; it lands in a future release alongside per-stage threading or as a separate0.8.xslot.
0.6.0 - 2026-05-19
Dead-letter routing release. Wires up ErrorPolicy::DeadLetter
(reserved since 0.3.0) to a Sink<Item = StageFailure> installed
via the new .dead_letter(sink) builder method. Closes the second
of the three deferrals from the 0.3.0 design lock.
PipelineBuilder::dead_letter(sink)(std-only): installs aSink<Item = StageFailure>that receives the failures produced by stages running underErrorPolicy::DeadLetter. Cloneable shared handle internally, so the sink can be installed before or after the failing stages; installation order does not matter. Callingdead_lettermore than once replaces the previous sink.StageFailure::new(stage, source)constructor.- 6 integration tests in
tests/dead_letter.rs: routing, install order independence, no-sink fallback to Continue, sink-error bubble-up, FailFast override, Continue does not route.
ErrorPolicy::DeadLetternow routes to the installed dead-letter sink instead of behaving identically toContinue. If no sink is installed, it still degrades toContinue(silent drop) - this is documented as the no-sink fallback rather than a stub.- Errors raised by the dead-letter sink itself bubble up from
Pipeline::runasError::Sink { stage: StageId("dead_letter"), .. }. - The dead-letter sink receives
FlushandCloseafter the main chain completes, so users can install a buffered or batching sink for failures. REPS.mdsections 4.7 and 4.9 un-defer dead-letter routing and mark the builder method as(std).docs/API.mdupdates the signature.
- The locked
StageFailurecarriesstageandsourceonly; it does not capture the failing input. Carrying the input would require type erasure (Box<dyn Any + Send>) at every failure site, which is a significant complexity trade-off. The struct is#[non_exhaustive]so a future release can add aninputfield without breaking SemVer. - Under
no_std,ErrorPolicy::DeadLettercontinues to behave identically toErrorPolicy::Continue(the routing handle requiresstd::sync::Mutex).
0.5.0 - 2026-05-19
Windowing release. Lands the window module that was deferred at
0.3.0. Closes one of the three locked-but-not-shipped surfaces
from the design lock.
pipe_io::windowmodule (std, default-on).trait Clock: Sendwith a singlefn now(&self) -> Instantmethod.struct SystemClock- defaultClockimpl wrappingstd::time::Instant::now.enum WindowPolicywithTumbling { size },Sliding { size, slide }, andSession { idle }variants.struct Window<T>withitems,len,is_empty,start,end,into_inneraccessors;IntoIteratorforWindow<T>and&Window<T>.PipelineBuilder::window(policy)using the defaultSystemClock.PipelineBuilder::window_with(policy, clock)for user-supplied clocks (deterministic tests, embedded time sources).- 5 unit tests in
src/window.rswith a deterministic in-memory clock (tumbling boundary emission, session idle close, sliding overlap, tumbling flush of partial window,Window::into_inner). - 4 integration tests in
tests/window.rs(tumbling rollup, session boundary, sliding overlap, empty-source no-emit).
REPS.mdsection 4.6 un-defers thewindowmodule and documents theT: Clonerequirement plus the no-background-timer semantics.docs/API.mdadds apipe_io::windowsection and listsWindow,WindowPolicy,Clock,SystemClockin the crate root table.
- Both window builder methods require
T: Clonebecause sliding windows duplicate items across overlapping windows. Consumers with non-Clonetypes and tumbling semantics can use.batch()withBatchPolicy::max_ageas a substitute. - The pure synchronous core does not run a background timer. A
session window that goes idle with no further items waiting will
close only when
Pipeline::runreaches end-of-stream and flushes the chain. This is documented in the module-level rustdoc.
0.4.0 - 2026-05-19
Polish and benchmarking release. No public API changes from 0.3.0;
this version adds a benchmark harness, measured numbers, and a
performance section in the docs.
benches/pipeline.rs- hand-rolled (no Criterion) throughput benches covering source-only, single map, three-stage chain, filter-drop, batch(100),try_maphappy path,try_mapwith 50% errors underErrorPolicy::Continue, and the threaded driver. Runs viacargo bench --bench pipeline.docs/BENCH.mddocuments methodology, hardware, measured numbers, the per-stage architectural cost (one vtable dispatch per stage edge through the boxed chain), and how to reproduce.- Performance summary added to
docs/API.md, cross-linked toBENCH.md. [[bench]] name = "pipeline"entry inCargo.tomlwithharness = falseandrequired-features = ["std"].
- Headline numbers on a developer laptop (Windows, x86_64, release
with
lto = "thin", 200,000 items per run): source-only at ~500 M items / s, single map at ~260 M items / s, three-stage chain at ~170 M items / s, batch(100) at ~140 M items / s, threaded driver at ~21 M items / s. - No optimization pass landed in this release; measured per-stage
cost (~1-2 ns per item per stage) matches the architectural
model (one boxed-dyn vtable hop per stage edge). Closing the gap
to the raw-iterator baseline would require full type-state
monomorphization, which is deferred past
1.0.0.
0.3.0 - 2026-05-19
First substantive release. Lands the design lock from the prior documentation push plus a minimum viable implementation of the locked public surface.
REPS.mdsection 4 locks the public API surface. Modules: crate root,source,stage,sink,batch,window(std, deferred past0.3.0),error,driver. Builder methods, feature flags, MSRV, and runtime dependency posture are now binding.REPS.mdsections 3 (Scope), 10 (Testing requirements), and 12 (Out of scope) filled in..dev/DESIGN.mddocuments the major design trade-offs: synchronous core, hybrid pull/push viaEmit, bounded buffers for backpressure, per-stage error policy,Clocktrait for windowing, dual-driver model (SyncDriverandThreadedDriver),&'static strstage identity, and the typed builder. Includes boundaries withIterator,futures::Stream,crossbeam,rayon, distributed processors, and the siblinglog-iocrate, plus four consumer use cases.
- Core traits:
Source,Stage,Sink,Emit. - Error model:
Error,Result,StageError(blanket impl overDebug + Display + Send + Sync + 'static),BoxError,StageId,StageFailure,BufferErrorKind,ErrorPolicy. - Source adapters:
IterSource,FnSource, plusChannelSourceandReaderSourceunderstd. - Sink adapters:
NullSink,FnSink, plusVecSink(with cloneableSharedHandle),ChannelSink, andWriterSinkunderstd. - Builder closure adapters:
map,filter,filter_map,flat_map,inspect,try_map, and the genericstagemethod for plugging in any customStageimplementation. - Batching:
Batch<T>,BatchPolicy(count, byte, and age triggers; age requiresstd),ByteSizetrait with blanket impls for&str,String,Vec<u8>,&[u8]. - Builder methods:
stage_id,on_error,batch,batch_bytes,sink. Pipeline::from_source,Pipeline::from_iter,Pipeline::run,Pipeline::run_threaded.- Drivers:
SyncDriver(no_std-compatible),ThreadedDriver(std-only). RunStatsreturned by every run, withitems_inalways present anddurationunderstd.- Crate version constant
pipe_io::VERSION. docs/API.mdrewritten as the offline mirror of the public surface.- 50 tests pass under
--all-features: 27 unit tests, 15 integration tests covering map / filter / filter_map / flat_map / inspect / batching / byte-batching / error policies / driver variants / a log-shipper shape / an ETL continue-on-failure shape, and 8 doctests.
REPS.mdsection 8 narrows the stability statement to point at the1.0.0policy and thecargo-semver-checksCI gate that arrives at0.9.0.REPS.mdsection 4.7 records thatStageErroruses aDebug + Display + Send + Sync + 'staticbound rather thancore::error::Error(which stabilized in Rust 1.81, post-MSRV).REPS.mdsection 4.8:Drivertrait deferred past0.3.xpending reconciliation ofSendbounds betweenSyncDriverandThreadedDriver. Pipelines pick a driver viaPipeline::run/Pipeline::run_threaded.REPS.mdsection 4.6:windowmodule deferred past0.3.0; the locked surface is preserved for the version that ships it.VecSinkisstd-only because itsSharedHandlerequiresArc<Mutex<_>>; no_std variant deferred.WriterSink<W>pinsItem = String; consumers convert from anyDisplayvia an upstream.map(|x| x.to_string()).
0.1.0 - 2026-05-12
- Initial repository scaffold.
- Apache-2.0 license, README, REPS specification stub, CI workflow,
.dev/planning structure (DIRECTIVES, ROADMAP, PROMPTS). - Crate name reserved on crates.io.