1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
# Transformation Pipeline
Middleware-esque API for transforming data.
## Features
- Define a custom data type passed between stages
- Simple pipeline flow exposed to stages: Abort, Finish (early), Skip
- Wrapper functions to run the entire pipeline
### Potential Future Features
- Sub-pipelines (e.g. Routers)
## Usage
### Installation
Add `transformation-pipeline` to your `Cargo.toml` file, and add it as an external crate.
```rust
extern crate transformation_pipeline;
```
### Define Data
Identify or define a datatype that will be passed between stages.
This can be a built-in, such as `String`, or a custom `struct`.
However, the datatype must have the `Clone` trait defined.
```rust
use std::clone::Clone;
struct User {
name: String,
}
impl Clone for User {
fn clone(&self) -> Self {
User {
name: self.name.clone(),
}
}
}
```
### Creating Stages
Create `struct`s for each stage of the pipeline, and implement the `PipelineStage` trait for each stage.
```rust
use transformation_pipeline::PipelineStage;
use transformation_pipeline::StageResult;
use transformation_pipeline::StageActions;
struct MyPipelineStage {}
impl TransformationStage<User> for MyPipelineStage {
fn run(&self, previous: User) -> StageResult<User> {
let mut name: String = "John ".to_owned();
name.push_str(&previous.name);
Ok(StageActions::Next(User {
name: name,
}))
}
}
```
See [stage actions](#stage-actions) for more information about the different actions that can be returned.
### Create a Pipeline
Now you can assemble a pipeline out of the created stages.
Each stage must be put in a `Box`, which is a built-in type.
```rust
use transformation_pipeline::TransformationPipeline;
let pipeline: TransformationPipeline<User> = TransformationPipeline::new(vec![
Box::new(MyPipelineStage {}),
// Add other stages here:
// Box::new(MyOtherPipelineStage {})
]);
```
### Using the Pipeline
Now you can pass data into the pipeline:
```rust
let input: User = User {
name: "Doe"
};
let output = pipeline.run(input).unwrap();
assert_eq!(output.name, "John Doe");
```
## Documentation
### Stage Actions
Each stage of the pipeline must complete with some "Action".
#### Next Action
The standard action is "Next", which passes the given data to the next pipeline stage.
If the stage is the final stage in the pipeline, the given data is returned as the pipeline result.
```rust
Ok(StageActions::Next( /* data for next stage */ ))
```
#### Skip Action
A stage can complete with "Skip", which starts the next pipeline stage as if the current stage never existed.
This is equivalent to calling:
```rust
return Ok(StageActions::Next(previous));
```
But it can be a little more explicit to what is happening:
```rust
if /* action is already completed */ {
return Ok(StageActions::Skip);
}
/* Do action */
Ok(StageActions::Next( /* ... */ ))
```
#### Finish Action
A stage can cause the pipeline to immediately complete with the "Finish" action.
This returns the given data as the pipeline result, and does not run any further stages.
```rust
Ok(StageActions::Finish(/* final data */ ))
```
#### Jump Action
A stage can skip subsequent steps in the pipeline with the "Jump" action.
This passes the given data to a stage further down the pipeline, and doesn't run any stages in between.
```rust
// SAME AS Next():
return Ok(StageActions::Skip(0, /* next data */ ));
// Skips 1 stage:
return Ok(StageActions::Skip(1, /* data to pass to the 2nd stage */ ));
```
#### Abort Action
A stage can complete with the "Abort" action, causing the entire pipeline to abort with an error.
```rust
Ok(StageActions::Abort)
```
## (Anti-)Purpose/Alternatives
This package is not designed to:
- Handle different data types between stages (e.g. successive maps)
- Have multiple functions exposed by pipeline stages (e.g. fancy plugins)
[cargo-plugin](https://github.com/Geal/cargo-plugin) may be a better alternative for general-purpose plugins.
|