forked from katzen-cafe/iowo
prowocessing: refactor trait based experiment to individual files
This commit is contained in:
parent
26996fbd00
commit
dddbcccf72
10 changed files with 362 additions and 341 deletions
|
@ -56,7 +56,6 @@ fn main() {
|
||||||
|
|
||||||
mod dev {
|
mod dev {
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
use prowocessing::experimental::trait_based::DataType;
|
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub(crate) enum DevCommands {
|
pub(crate) enum DevCommands {
|
||||||
|
@ -81,7 +80,7 @@ mod dev {
|
||||||
println!("Lwr: {}", lwr.run(test_str.clone()));
|
println!("Lwr: {}", lwr.run(test_str.clone()));
|
||||||
}
|
}
|
||||||
DevCommands::Add { num0, num1 } => {
|
DevCommands::Add { num0, num1 } => {
|
||||||
use prowocessing::experimental::trait_based::PipelineBuilder;
|
use prowocessing::experimental::trait_based::pipeline::PipelineBuilder;
|
||||||
|
|
||||||
let pipe = PipelineBuilder::new().add(1).stringify().build();
|
let pipe = PipelineBuilder::new().add(1).stringify().build();
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -1,339 +1,4 @@
|
||||||
use self::{
|
pub mod data;
|
||||||
numops::{Add, Stringify, Subtract},
|
pub mod element;
|
||||||
strops::{Concatenate, Lower, Upper},
|
pub mod ops;
|
||||||
};
|
pub mod pipeline;
|
||||||
|
|
||||||
trait PipelineElement {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs;
|
|
||||||
fn signature(&self) -> ElementIo;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ElementIo {
|
|
||||||
pub inputs: Vec<DataType>,
|
|
||||||
pub outputs: Vec<DataType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - Bind additional inputs if instruction has more then one and is passd without any additional
|
|
||||||
// - allow binding to pointers to other pipelines?
|
|
||||||
// - allow referencing earlier data
|
|
||||||
pub struct PipelineBuilder {
|
|
||||||
elements: Vec<Box<dyn PipelineElement>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Pipeline {
|
|
||||||
runners: Vec<fn(&Inputs) -> Outputs>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pipeline {
|
|
||||||
pub fn run(&self, inputs: Inputs) -> Outputs {
|
|
||||||
let mut out: Outputs = inputs.into();
|
|
||||||
|
|
||||||
for runner in &self.runners {
|
|
||||||
out = runner(&(&out).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PipelineBuilder {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
elements: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert<T: PipelineElement + 'static>(mut self, el: T) -> Self {
|
|
||||||
if let Some(previous_item) = self.elements.last() {
|
|
||||||
assert_eq!(
|
|
||||||
previous_item.signature().outputs[0],
|
|
||||||
el.signature().inputs[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.elements.push(Box::new(el));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn concatenate(self, sec: String) -> Self {
|
|
||||||
self.insert(Concatenate(sec))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn upper(self) -> Self {
|
|
||||||
self.insert(Upper)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn lower(self) -> Self {
|
|
||||||
self.insert(Lower)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
#[allow(
|
|
||||||
clippy::should_implement_trait,
|
|
||||||
reason = "is not equivalent to addition"
|
|
||||||
)]
|
|
||||||
pub fn add(self, sec: i32) -> Self {
|
|
||||||
self.insert(Add(sec))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn subtract(self, sec: i32) -> Self {
|
|
||||||
self.insert(Subtract(sec))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn stringify(self) -> Self {
|
|
||||||
self.insert(Stringify)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(&self) -> Pipeline {
|
|
||||||
let mut r = Vec::new();
|
|
||||||
|
|
||||||
self.elements.iter().for_each(|el| r.push(el.runner()));
|
|
||||||
|
|
||||||
Pipeline { runners: r }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PipelineBuilder {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Data<'a> {
|
|
||||||
String(&'a str),
|
|
||||||
Int(i32),
|
|
||||||
}
|
|
||||||
impl Data<'_> {
|
|
||||||
pub fn to_owned_data(&self) -> OwnedData {
|
|
||||||
match self {
|
|
||||||
Data::String(s) => (*s).to_owned().into(),
|
|
||||||
Data::Int(i) => (*i).into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> From<&'a str> for Data<'a> {
|
|
||||||
fn from(value: &'a str) -> Self {
|
|
||||||
Self::String(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<i32> for Data<'_> {
|
|
||||||
fn from(value: i32) -> Self {
|
|
||||||
Self::Int(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> From<&'a OwnedData> for Data<'a> {
|
|
||||||
fn from(value: &'a OwnedData) -> Self {
|
|
||||||
match value {
|
|
||||||
OwnedData::String(s) => Data::String(s),
|
|
||||||
OwnedData::Int(i) => Data::Int(*i),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum OwnedData {
|
|
||||||
String(String),
|
|
||||||
Int(i32),
|
|
||||||
}
|
|
||||||
impl From<String> for OwnedData {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
Self::String(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<i32> for OwnedData {
|
|
||||||
fn from(value: i32) -> Self {
|
|
||||||
Self::Int(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum DataType {
|
|
||||||
String,
|
|
||||||
Int,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Inputs<'a>(Vec<Data<'a>>);
|
|
||||||
impl<'a> Inputs<'a> {
|
|
||||||
fn inner(&self) -> Vec<Data<'a>> {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> From<Vec<Data<'a>>> for Inputs<'a> {
|
|
||||||
fn from(value: Vec<Data<'a>>) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, T: Into<Data<'a>>> From<T> for Inputs<'a> {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self(vec![value.into()])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> From<&'a Outputs> for Inputs<'a> {
|
|
||||||
fn from(value: &'a Outputs) -> Self {
|
|
||||||
Self(value.0.iter().map(std::convert::Into::into).collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Outputs(Vec<OwnedData>);
|
|
||||||
impl Outputs {
|
|
||||||
pub fn into_inner(self) -> Vec<OwnedData> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Vec<OwnedData>> for Outputs {
|
|
||||||
fn from(value: Vec<OwnedData>) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Into<OwnedData>> From<T> for Outputs {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self(vec![value.into()])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Inputs<'_>> for Outputs {
|
|
||||||
fn from(value: Inputs) -> Self {
|
|
||||||
Self(
|
|
||||||
value
|
|
||||||
.0
|
|
||||||
.into_iter()
|
|
||||||
.map(|i: Data<'_>| Data::to_owned_data(&i))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod strops {
|
|
||||||
use super::{Data, DataType, ElementIo, Inputs, Outputs, PipelineElement};
|
|
||||||
|
|
||||||
pub struct Concatenate(pub String);
|
|
||||||
impl PipelineElement for Concatenate {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
if let [Data::String(s0), Data::String(s1), ..] = input.inner()[..] {
|
|
||||||
format!("{s0}{s1}").into()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
|
||||||
ElementIo {
|
|
||||||
inputs: vec![DataType::String, DataType::String],
|
|
||||||
outputs: vec![DataType::String],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Upper;
|
|
||||||
impl PipelineElement for Upper {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
if let [Data::String(s), ..] = input.inner()[..] {
|
|
||||||
s.to_uppercase().into()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
|
||||||
ElementIo {
|
|
||||||
inputs: vec![DataType::String],
|
|
||||||
outputs: vec![DataType::String],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Lower;
|
|
||||||
impl PipelineElement for Lower {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
if let [Data::String(s), ..] = input.inner()[..] {
|
|
||||||
s.to_lowercase().into()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
|
||||||
ElementIo {
|
|
||||||
inputs: vec![DataType::String],
|
|
||||||
outputs: vec![DataType::String],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod numops {
|
|
||||||
use core::panic;
|
|
||||||
|
|
||||||
use super::{Data, DataType, ElementIo, Inputs, Outputs, PipelineElement};
|
|
||||||
|
|
||||||
pub struct Add(pub i32);
|
|
||||||
impl PipelineElement for Add {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
if let [Data::Int(i0), Data::Int(i1), ..] = input.inner()[..] {
|
|
||||||
(i0 + i1).into()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
|
||||||
ElementIo {
|
|
||||||
inputs: vec![DataType::Int, DataType::Int],
|
|
||||||
outputs: vec![DataType::Int],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Subtract(pub i32);
|
|
||||||
impl PipelineElement for Subtract {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
if let [Data::Int(i0), Data::Int(i1), ..] = input.inner()[..] {
|
|
||||||
(i0 + i1).into()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
|
||||||
ElementIo {
|
|
||||||
inputs: vec![DataType::Int, DataType::Int],
|
|
||||||
outputs: vec![DataType::Int],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Stringify;
|
|
||||||
impl PipelineElement for Stringify {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
if let [Data::Int(int), ..] = input.inner()[..] {
|
|
||||||
int.to_string().into()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
|
||||||
ElementIo {
|
|
||||||
inputs: vec![DataType::Int],
|
|
||||||
outputs: vec![DataType::String],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
2
crates/prowocessing/src/experimental/trait_based/data.rs
Normal file
2
crates/prowocessing/src/experimental/trait_based/data.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod io;
|
||||||
|
pub mod raw;
|
51
crates/prowocessing/src/experimental/trait_based/data/io.rs
Normal file
51
crates/prowocessing/src/experimental/trait_based/data/io.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use super::raw::{Data, OwnedData};
|
||||||
|
|
||||||
|
pub struct Inputs<'a>(Vec<Data<'a>>);
|
||||||
|
impl<'a> Inputs<'a> {
|
||||||
|
pub(crate) fn inner(&self) -> Vec<Data<'a>> {
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<Vec<Data<'a>>> for Inputs<'a> {
|
||||||
|
fn from(value: Vec<Data<'a>>) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T: Into<Data<'a>>> From<T> for Inputs<'a> {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Self(vec![value.into()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<&'a Outputs> for Inputs<'a> {
|
||||||
|
fn from(value: &'a Outputs) -> Self {
|
||||||
|
Self(value.0.iter().map(std::convert::Into::into).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Outputs(Vec<OwnedData>);
|
||||||
|
impl Outputs {
|
||||||
|
pub fn into_inner(self) -> Vec<OwnedData> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Vec<OwnedData>> for Outputs {
|
||||||
|
fn from(value: Vec<OwnedData>) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Into<OwnedData>> From<T> for Outputs {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Self(vec![value.into()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Inputs<'_>> for Outputs {
|
||||||
|
fn from(value: Inputs) -> Self {
|
||||||
|
Self(
|
||||||
|
value
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.map(|i: Data<'_>| Data::to_owned_data(&i))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
48
crates/prowocessing/src/experimental/trait_based/data/raw.rs
Normal file
48
crates/prowocessing/src/experimental/trait_based/data/raw.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Data<'a> {
|
||||||
|
String(&'a str),
|
||||||
|
Int(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data<'_> {
|
||||||
|
pub fn to_owned_data(&self) -> OwnedData {
|
||||||
|
match self {
|
||||||
|
Data::String(s) => (*s).to_owned().into(),
|
||||||
|
Data::Int(i) => (*i).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<&'a str> for Data<'a> {
|
||||||
|
fn from(value: &'a str) -> Self {
|
||||||
|
Self::String(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<i32> for Data<'_> {
|
||||||
|
fn from(value: i32) -> Self {
|
||||||
|
Self::Int(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<&'a OwnedData> for Data<'a> {
|
||||||
|
fn from(value: &'a OwnedData) -> Self {
|
||||||
|
match value {
|
||||||
|
OwnedData::String(s) => Data::String(s),
|
||||||
|
OwnedData::Int(i) => Data::Int(*i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OwnedData {
|
||||||
|
String(String),
|
||||||
|
Int(i32),
|
||||||
|
}
|
||||||
|
impl From<String> for OwnedData {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self::String(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<i32> for OwnedData {
|
||||||
|
fn from(value: i32) -> Self {
|
||||||
|
Self::Int(value)
|
||||||
|
}
|
||||||
|
}
|
19
crates/prowocessing/src/experimental/trait_based/element.rs
Normal file
19
crates/prowocessing/src/experimental/trait_based/element.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use crate::experimental::trait_based::data::io::Inputs;
|
||||||
|
|
||||||
|
use super::data::io::Outputs;
|
||||||
|
|
||||||
|
pub(crate) trait PipelineElement {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs;
|
||||||
|
fn signature(&self) -> ElementIo;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ElementIo {
|
||||||
|
pub inputs: Vec<DataType>,
|
||||||
|
pub outputs: Vec<DataType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum DataType {
|
||||||
|
String,
|
||||||
|
Int,
|
||||||
|
}
|
7
crates/prowocessing/src/experimental/trait_based/ops.rs
Normal file
7
crates/prowocessing/src/experimental/trait_based/ops.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
mod num;
|
||||||
|
mod str;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub(crate) use super::num::*;
|
||||||
|
pub(crate) use super::str::*;
|
||||||
|
}
|
69
crates/prowocessing/src/experimental/trait_based/ops/num.rs
Normal file
69
crates/prowocessing/src/experimental/trait_based/ops/num.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use core::panic;
|
||||||
|
|
||||||
|
use crate::experimental::trait_based::{
|
||||||
|
data::{
|
||||||
|
io::{Inputs, Outputs},
|
||||||
|
raw::Data,
|
||||||
|
},
|
||||||
|
element::{DataType, ElementIo, PipelineElement},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Add(pub i32);
|
||||||
|
impl PipelineElement for Add {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
|input| {
|
||||||
|
if let [Data::Int(i0), Data::Int(i1), ..] = input.inner()[..] {
|
||||||
|
(i0 + i1).into()
|
||||||
|
} else {
|
||||||
|
panic!("Invalid data passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> ElementIo {
|
||||||
|
ElementIo {
|
||||||
|
inputs: vec![DataType::Int, DataType::Int],
|
||||||
|
outputs: vec![DataType::Int],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Subtract(pub i32);
|
||||||
|
impl PipelineElement for Subtract {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
|input| {
|
||||||
|
if let [Data::Int(i0), Data::Int(i1), ..] = input.inner()[..] {
|
||||||
|
(i0 + i1).into()
|
||||||
|
} else {
|
||||||
|
panic!("Invalid data passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> ElementIo {
|
||||||
|
ElementIo {
|
||||||
|
inputs: vec![DataType::Int, DataType::Int],
|
||||||
|
outputs: vec![DataType::Int],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Stringify;
|
||||||
|
impl PipelineElement for Stringify {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
|input| {
|
||||||
|
if let [Data::Int(int), ..] = input.inner()[..] {
|
||||||
|
int.to_string().into()
|
||||||
|
} else {
|
||||||
|
panic!("Invalid data passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> ElementIo {
|
||||||
|
ElementIo {
|
||||||
|
inputs: vec![DataType::Int],
|
||||||
|
outputs: vec![DataType::String],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
crates/prowocessing/src/experimental/trait_based/ops/str.rs
Normal file
67
crates/prowocessing/src/experimental/trait_based/ops/str.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use crate::experimental::trait_based::{
|
||||||
|
data::{
|
||||||
|
io::{Inputs, Outputs},
|
||||||
|
raw::Data,
|
||||||
|
},
|
||||||
|
element::{DataType, ElementIo, PipelineElement},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Concatenate(pub String);
|
||||||
|
impl PipelineElement for Concatenate {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
|input| {
|
||||||
|
if let [Data::String(s0), Data::String(s1), ..] = input.inner()[..] {
|
||||||
|
format!("{s0}{s1}").into()
|
||||||
|
} else {
|
||||||
|
panic!("Invalid data passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> ElementIo {
|
||||||
|
ElementIo {
|
||||||
|
inputs: vec![DataType::String, DataType::String],
|
||||||
|
outputs: vec![DataType::String],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Upper;
|
||||||
|
impl PipelineElement for Upper {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
|input| {
|
||||||
|
if let [Data::String(s), ..] = input.inner()[..] {
|
||||||
|
s.to_uppercase().into()
|
||||||
|
} else {
|
||||||
|
panic!("Invalid data passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> ElementIo {
|
||||||
|
ElementIo {
|
||||||
|
inputs: vec![DataType::String],
|
||||||
|
outputs: vec![DataType::String],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Lower;
|
||||||
|
impl PipelineElement for Lower {
|
||||||
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
|input| {
|
||||||
|
if let [Data::String(s), ..] = input.inner()[..] {
|
||||||
|
s.to_lowercase().into()
|
||||||
|
} else {
|
||||||
|
panic!("Invalid data passed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> ElementIo {
|
||||||
|
ElementIo {
|
||||||
|
inputs: vec![DataType::String],
|
||||||
|
outputs: vec![DataType::String],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
crates/prowocessing/src/experimental/trait_based/pipeline.rs
Normal file
94
crates/prowocessing/src/experimental/trait_based/pipeline.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use super::data::io::{Inputs, Outputs};
|
||||||
|
use super::element::PipelineElement;
|
||||||
|
use super::ops::prelude::*;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - Bind additional inputs if instruction has more then one and is passd without any additional
|
||||||
|
// - allow binding to pointers to other pipelines?
|
||||||
|
// - allow referencing earlier data
|
||||||
|
pub struct PipelineBuilder {
|
||||||
|
elements: Vec<Box<dyn PipelineElement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipelineBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
elements: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert<T: PipelineElement + 'static>(mut self, el: T) -> Self {
|
||||||
|
if let Some(previous_item) = self.elements.last() {
|
||||||
|
assert_eq!(
|
||||||
|
previous_item.signature().outputs[0],
|
||||||
|
el.signature().inputs[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.elements.push(Box::new(el));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn concatenate(self, sec: String) -> Self {
|
||||||
|
self.insert(Concatenate(sec))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn upper(self) -> Self {
|
||||||
|
self.insert(Upper)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn lower(self) -> Self {
|
||||||
|
self.insert(Lower)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
#[allow(
|
||||||
|
clippy::should_implement_trait,
|
||||||
|
reason = "is not equivalent to addition"
|
||||||
|
)]
|
||||||
|
pub fn add(self, sec: i32) -> Self {
|
||||||
|
self.insert(Add(sec))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn subtract(self, sec: i32) -> Self {
|
||||||
|
self.insert(Subtract(sec))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn stringify(self) -> Self {
|
||||||
|
self.insert(Stringify)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&self) -> Pipeline {
|
||||||
|
let mut r = Vec::new();
|
||||||
|
|
||||||
|
self.elements.iter().for_each(|el| r.push(el.runner()));
|
||||||
|
|
||||||
|
Pipeline { runners: r }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PipelineBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pipeline {
|
||||||
|
runners: Vec<fn(&Inputs) -> Outputs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pipeline {
|
||||||
|
pub fn run(&self, inputs: Inputs) -> Outputs {
|
||||||
|
let mut out: Outputs = inputs.into();
|
||||||
|
|
||||||
|
for runner in &self.runners {
|
||||||
|
out = runner(&(&out).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue