diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 2534631..d5a260c 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -56,7 +56,6 @@ fn main() { mod dev { use clap::Subcommand; - use prowocessing::experimental::trait_based::DataType; #[derive(Subcommand)] pub(crate) enum DevCommands { @@ -81,7 +80,7 @@ mod dev { println!("Lwr: {}", lwr.run(test_str.clone())); } 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(); println!( diff --git a/crates/prowocessing/src/experimental/trait_based.rs b/crates/prowocessing/src/experimental/trait_based.rs index 3be8f3a..de2fdac 100644 --- a/crates/prowocessing/src/experimental/trait_based.rs +++ b/crates/prowocessing/src/experimental/trait_based.rs @@ -1,339 +1,4 @@ -use self::{ - numops::{Add, Stringify, Subtract}, - strops::{Concatenate, Lower, Upper}, -}; - -trait PipelineElement { - fn runner(&self) -> fn(&Inputs) -> Outputs; - fn signature(&self) -> ElementIo; -} - -struct ElementIo { - pub inputs: Vec, - pub outputs: Vec, -} - -// 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>, -} - -pub struct Pipeline { - runners: Vec 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(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 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 for OwnedData { - fn from(value: String) -> Self { - Self::String(value) - } -} -impl From 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>); -impl<'a> Inputs<'a> { - fn inner(&self) -> Vec> { - self.0.clone() - } -} -impl<'a> From>> for Inputs<'a> { - fn from(value: Vec>) -> Self { - Self(value) - } -} -impl<'a, T: Into>> From 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); -impl Outputs { - pub fn into_inner(self) -> Vec { - self.0 - } -} -impl From> for Outputs { - fn from(value: Vec) -> Self { - Self(value) - } -} -impl> From for Outputs { - fn from(value: T) -> Self { - Self(vec![value.into()]) - } -} -impl From> 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], - } - } - } -} +pub mod data; +pub mod element; +pub mod ops; +pub mod pipeline; diff --git a/crates/prowocessing/src/experimental/trait_based/data.rs b/crates/prowocessing/src/experimental/trait_based/data.rs new file mode 100644 index 0000000..cc27567 --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/data.rs @@ -0,0 +1,2 @@ +pub mod io; +pub mod raw; diff --git a/crates/prowocessing/src/experimental/trait_based/data/io.rs b/crates/prowocessing/src/experimental/trait_based/data/io.rs new file mode 100644 index 0000000..fe40344 --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/data/io.rs @@ -0,0 +1,51 @@ +use super::raw::{Data, OwnedData}; + +pub struct Inputs<'a>(Vec>); +impl<'a> Inputs<'a> { + pub(crate) fn inner(&self) -> Vec> { + self.0.clone() + } +} +impl<'a> From>> for Inputs<'a> { + fn from(value: Vec>) -> Self { + Self(value) + } +} +impl<'a, T: Into>> From 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); +impl Outputs { + pub fn into_inner(self) -> Vec { + self.0 + } +} +impl From> for Outputs { + fn from(value: Vec) -> Self { + Self(value) + } +} +impl> From for Outputs { + fn from(value: T) -> Self { + Self(vec![value.into()]) + } +} +impl From> for Outputs { + fn from(value: Inputs) -> Self { + Self( + value + .0 + .into_iter() + .map(|i: Data<'_>| Data::to_owned_data(&i)) + .collect(), + ) + } +} diff --git a/crates/prowocessing/src/experimental/trait_based/data/raw.rs b/crates/prowocessing/src/experimental/trait_based/data/raw.rs new file mode 100644 index 0000000..88c16e7 --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/data/raw.rs @@ -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 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 for OwnedData { + fn from(value: String) -> Self { + Self::String(value) + } +} +impl From for OwnedData { + fn from(value: i32) -> Self { + Self::Int(value) + } +} diff --git a/crates/prowocessing/src/experimental/trait_based/element.rs b/crates/prowocessing/src/experimental/trait_based/element.rs new file mode 100644 index 0000000..6fdba6b --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/element.rs @@ -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, + pub outputs: Vec, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum DataType { + String, + Int, +} diff --git a/crates/prowocessing/src/experimental/trait_based/ops.rs b/crates/prowocessing/src/experimental/trait_based/ops.rs new file mode 100644 index 0000000..e7c9d04 --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/ops.rs @@ -0,0 +1,7 @@ +mod num; +mod str; + +pub mod prelude { + pub(crate) use super::num::*; + pub(crate) use super::str::*; +} diff --git a/crates/prowocessing/src/experimental/trait_based/ops/num.rs b/crates/prowocessing/src/experimental/trait_based/ops/num.rs new file mode 100644 index 0000000..88b57d3 --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/ops/num.rs @@ -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], + } + } +} diff --git a/crates/prowocessing/src/experimental/trait_based/ops/str.rs b/crates/prowocessing/src/experimental/trait_based/ops/str.rs new file mode 100644 index 0000000..56c39ad --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/ops/str.rs @@ -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], + } + } +} diff --git a/crates/prowocessing/src/experimental/trait_based/pipeline.rs b/crates/prowocessing/src/experimental/trait_based/pipeline.rs new file mode 100644 index 0000000..628130b --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based/pipeline.rs @@ -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>, +} + +impl PipelineBuilder { + pub fn new() -> Self { + Self { + elements: Vec::new(), + } + } + + fn insert(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 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 + } +}