result-transformer
Composable, type‑safe transforms for
Result<T, E>– with matching sync and async APIs.
result-transformer lets you describe how a Result should be rewritten without coupling that logic to your domain
types or execution model.
Implement a tiny trait – or let a one‑line macro do it for you – and drop the transformer anywhere you need it.
Current version is 0.0.1. The API is not yet stable and may change.
Table of contents
- Why use result-transformer?
- Crate overview
- Quick start
- Feature matrix
- Project status
- License
- Contributing
Why use result‑transformer?
- Decoupled by design – success (
OkTransformer) and error (ErrTransformer) paths are isolated, keeping concerns clear and testable. - Symmetric sync / async – every concept exists in twin flavours. You can reuse the same design, but switching to
asyncrequires the corresponding_asynctraits and macros. - Macro‑assisted ergonomics – declarative
impl_*_transformer!andimpl_*_transformer_via_*_flow!macros generate the boring glue while you focus on behaviour. - Optional “flow / step” DSL – chain lightweight steps into a flow when you want a quick inline pipeline. (It’s a helper, not a requirement.)
- Tiny & feature‑gated – pull in only the capabilities and dependencies you actually use.
Crate overview
| crate | purpose | notes |
|---|---|---|
| result-transformer | facade crate reexporting the individual components | enable only the features you need |
| result-transformer-core | foundational traits and "raw" implementation macros | provides synchronous and asynchronous APIs |
| result-transformer-flow | optional step-based DSL used to compose transformers via macros | map/tap/inspect steps, optional logging |
| result-transformer-macros | reserved placeholder for future procedural macros | not used yet |
| result-transformer-dependencies | consolidates external crates behind feature flags (tokio, log, …) |
internal helper crate |
| result-transformer-test | integration tests and doc examples that serve as real-world recipes | not intended for production |
Quick start
1. Add the dependency
# Cargo.toml
= { = "0.0.1", = ["core-sync", "core-sync-macros"] }
2. A minimal synchronous transformer
use *;
;
/// doubles on success and prefixes errors – nothing more.
impl_ok_transformer!
impl_err_transformer!
impl_result_transformer_via_self_parts!
use ResultTransformer; // needed to access the `transform` method
assert_eq!;
assert_eq!;
To use these transformers in an asynchronous context, enable the core-async feature and import items from the async_ module. The examples above will need to be rewritten with async/await and cannot be copied verbatim. The following snippet shows how to reuse the synchronous transformer by wrapping it with an asynchronous implementation.
Async example
use *;
impl_async_result_transformer_via_self_result_transformer!
async
Manual implementation (no macros)
This approach is handy when macros are unavailable or you need finer-grained control.
use ;
;
assert_eq!;
assert_eq!;
The manual route makes the separation of concerns crystal‑clear – each trait lives on its own – and it requires zero compiler magic. In larger codebases you’ll probably reach for the macros to avoid repetition, but both styles interoperate seamlessly.
3. (Optional) Build a transformer via a flow
Note: To use flows, enable the
flow-syncandflow-sync-macrosfeatures.
When you do want a small pipeline the flow / step DSL has your back.
The example below chains two steps and then turns the resulting flow into a reusable transformer with
impl_result_transformer_via_result_flow!.
use ;
// any value implementing `ResultFlow` can be used – a single step is already a valid flow!
let flow = new
// chaining the steps with `.then_result`
.then_result;
;
impl_result_transformer_via_result_flow!
Feature matrix
| feature | effect |
|---|---|
default |
enables core-sync |
core-sync |
enables the synchronous core API |
core-sync-macros |
helper macros for the synchronous model |
core-sync-all |
core-sync + core-sync-macros |
core-async |
enables the asynchronous core API |
core-async-macros |
helper macros for the asynchronous model |
core-async-all |
core-async + core-async-macros |
core-all |
all features from result-transformer-core |
flow-sync |
enables the synchronous flow / step DSL |
flow-sync-macros |
helper macros for synchronous flows |
flow-sync-log-step |
adds a logging step for synchronous flows |
flow-sync-all |
flow-sync + flow-sync-log-step + flow-sync-macros |
flow-async |
enables the asynchronous flow / step DSL |
flow-async-macros |
helper macros for asynchronous flows |
flow-async-log-step |
adds a logging step for asynchronous flows |
flow-async-all |
flow-async + flow-async-log-step + flow-async-macros |
flow-all |
all features from result-transformer-flow |
sync-all |
core-sync-all + flow-sync-all |
async-all |
core-async-all + flow-async-all |
all |
every feature in this crate |
Pick exactly what you need and keep compile times down.
Only core-sync is enabled by default. Combine features as needed.
Some features automatically enable their dependencies. For example,
flow-async-macroswill automatically enableflow-asyncandcore-async. You can still list them explicitly if you want to be more precise.
Example: enabling the async execution model, flow DSL, and flow macros:
= { = "0.0.1", = ["flow-async-macros"] }
Or, if you prefer to list everything explicitly:
= { = "0.0.1", = ["core-async", "flow-async", "flow-async-macros"] }
Project status
This project is currently in early development (0.0.1) and not yet stable.
APIs — especially in the flow crate — are subject to change.
License
Licensed under either of
- MIT license (LICENSE-MIT)
- Apache‑2.0 license (LICENSE-APACHE)
at your option.
Contributing
Bug reports, feature requests, and pull requests are always welcome.
I'm still new to GitHub and not very confident in English. For now, I'm doing my best with the help of ChatGPT, so I might misunderstand something. Thanks for your understanding!