prowocessing: add documentation of trait experiment
This commit is contained in:
parent
98f6af78be
commit
0ebfed66ed
9 changed files with 93 additions and 37 deletions
|
@ -1,3 +1,2 @@
|
||||||
pub mod enum_based;
|
pub mod enum_based;
|
||||||
|
|
||||||
pub mod trait_based;
|
pub mod trait_based;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//! An experiment for a hyper-modular trait-based architecture.
|
||||||
|
//!
|
||||||
|
//! Patterns defining this (or well, which I reference a lot while writing this):
|
||||||
|
//! - [Command pattern using trait objects](https://rust-unofficial.github.io/patterns/patterns/behavioural/command.html)
|
||||||
|
//! - [Builder pattern](https://rust-unofficial.github.io/patterns/patterns/creational/builder.html)
|
||||||
|
|
||||||
pub mod data;
|
pub mod data;
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
|
|
|
@ -1,2 +1,7 @@
|
||||||
|
//! Definitions of the data transfer and storage types.
|
||||||
|
|
||||||
|
/// Types for element and pipeline IO
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
|
||||||
|
/// Raw data types contained in `io`
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
|
|
|
@ -1,29 +1,38 @@
|
||||||
use super::raw::{Data, OwnedData};
|
use super::raw::{Data, OwnedData};
|
||||||
|
|
||||||
|
/// Newtype struct with borrowed types for pipeline/element inputs, so that doesn't force a move or clone
|
||||||
pub struct Inputs<'a>(Vec<Data<'a>>);
|
pub struct Inputs<'a>(Vec<Data<'a>>);
|
||||||
|
|
||||||
impl<'a> Inputs<'a> {
|
impl<'a> Inputs<'a> {
|
||||||
|
/// get inner value(s)
|
||||||
pub(crate) fn inner(&self) -> Vec<Data<'a>> {
|
pub(crate) fn inner(&self) -> Vec<Data<'a>> {
|
||||||
self.0.clone()
|
self.0.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<Vec<Data<'a>>> for Inputs<'a> {
|
impl<'a> From<Vec<Data<'a>>> for Inputs<'a> {
|
||||||
fn from(value: Vec<Data<'a>>) -> Self {
|
fn from(value: Vec<Data<'a>>) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Into<Data<'a>>> From<T> for Inputs<'a> {
|
impl<'a, T: Into<Data<'a>>> From<T> for Inputs<'a> {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Self(vec![value.into()])
|
Self(vec![value.into()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Outputs> for Inputs<'a> {
|
impl<'a> From<&'a Outputs> for Inputs<'a> {
|
||||||
fn from(value: &'a Outputs) -> Self {
|
fn from(value: &'a Outputs) -> Self {
|
||||||
Self(value.0.iter().map(std::convert::Into::into).collect())
|
Self(value.0.iter().map(std::convert::Into::into).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Newtype struct around `OwnedData` for pipeline/element outputs
|
||||||
pub struct Outputs(Vec<OwnedData>);
|
pub struct Outputs(Vec<OwnedData>);
|
||||||
|
|
||||||
impl Outputs {
|
impl Outputs {
|
||||||
|
/// consume self and return inner value(s)
|
||||||
pub fn into_inner(self) -> Vec<OwnedData> {
|
pub fn into_inner(self) -> Vec<OwnedData> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,25 @@
|
||||||
|
//! Dynamic data storage and transfer types
|
||||||
|
|
||||||
|
/// Owned data type, for use mostly in outputs and storage
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unowned data type, for inputs into runner functions
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Data<'a> {
|
pub enum Data<'a> {
|
||||||
String(&'a str),
|
String(&'a str),
|
||||||
|
@ -5,6 +27,7 @@ pub enum Data<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data<'_> {
|
impl Data<'_> {
|
||||||
|
/// converts itself to `OwnedData`
|
||||||
pub fn to_owned_data(&self) -> OwnedData {
|
pub fn to_owned_data(&self) -> OwnedData {
|
||||||
match self {
|
match self {
|
||||||
Data::String(s) => (*s).to_owned().into(),
|
Data::String(s) => (*s).to_owned().into(),
|
||||||
|
@ -12,16 +35,19 @@ impl Data<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Data<'a> {
|
impl<'a> From<&'a str> for Data<'a> {
|
||||||
fn from(value: &'a str) -> Self {
|
fn from(value: &'a str) -> Self {
|
||||||
Self::String(value)
|
Self::String(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i32> for Data<'_> {
|
impl From<i32> for Data<'_> {
|
||||||
fn from(value: i32) -> Self {
|
fn from(value: i32) -> Self {
|
||||||
Self::Int(value)
|
Self::Int(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a OwnedData> for Data<'a> {
|
impl<'a> From<&'a OwnedData> for Data<'a> {
|
||||||
fn from(value: &'a OwnedData) -> Self {
|
fn from(value: &'a OwnedData) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
@ -30,19 +56,3 @@ impl<'a> From<&'a OwnedData> for Data<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
|
//! The trait and type representations
|
||||||
|
|
||||||
use crate::experimental::trait_based::data::io::Inputs;
|
use crate::experimental::trait_based::data::io::Inputs;
|
||||||
|
|
||||||
use super::data::io::Outputs;
|
use super::data::io::Outputs;
|
||||||
|
|
||||||
pub(crate) trait PipelineElement {
|
pub(crate) trait PipelineElement {
|
||||||
|
/// return a static runner function pointer to avoid dynamic dispatch during pipeline execution - Types MUST match the signature
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs;
|
fn runner(&self) -> fn(&Inputs) -> Outputs;
|
||||||
fn signature(&self) -> ElementIo;
|
/// return the signature of the element
|
||||||
|
fn signature(&self) -> ElementSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ElementIo {
|
/// Type signature for an element used for static checking
|
||||||
|
pub(crate) struct ElementSignature {
|
||||||
pub inputs: Vec<DataType>,
|
pub inputs: Vec<DataType>,
|
||||||
pub outputs: Vec<DataType>,
|
pub outputs: Vec<DataType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data type enum
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum DataType {
|
pub enum DataType {
|
||||||
String,
|
String,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! Operations on numeric data
|
||||||
use core::panic;
|
use core::panic;
|
||||||
|
|
||||||
use crate::experimental::trait_based::{
|
use crate::experimental::trait_based::{
|
||||||
|
@ -5,9 +6,10 @@ use crate::experimental::trait_based::{
|
||||||
io::{Inputs, Outputs},
|
io::{Inputs, Outputs},
|
||||||
raw::Data,
|
raw::Data,
|
||||||
},
|
},
|
||||||
element::{DataType, ElementIo, PipelineElement},
|
element::{DataType, ElementSignature, PipelineElement},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Addition
|
||||||
pub struct Add(pub i32);
|
pub struct Add(pub i32);
|
||||||
impl PipelineElement for Add {
|
impl PipelineElement for Add {
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
@ -20,14 +22,15 @@ impl PipelineElement for Add {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
fn signature(&self) -> ElementSignature {
|
||||||
ElementIo {
|
ElementSignature {
|
||||||
inputs: vec![DataType::Int, DataType::Int],
|
inputs: vec![DataType::Int, DataType::Int],
|
||||||
outputs: vec![DataType::Int],
|
outputs: vec![DataType::Int],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Subtraction
|
||||||
pub struct Subtract(pub i32);
|
pub struct Subtract(pub i32);
|
||||||
impl PipelineElement for Subtract {
|
impl PipelineElement for Subtract {
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
@ -40,14 +43,15 @@ impl PipelineElement for Subtract {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
fn signature(&self) -> ElementSignature {
|
||||||
ElementIo {
|
ElementSignature {
|
||||||
inputs: vec![DataType::Int, DataType::Int],
|
inputs: vec![DataType::Int, DataType::Int],
|
||||||
outputs: vec![DataType::Int],
|
outputs: vec![DataType::Int],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn input to string
|
||||||
pub struct Stringify;
|
pub struct Stringify;
|
||||||
impl PipelineElement for Stringify {
|
impl PipelineElement for Stringify {
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
@ -60,8 +64,8 @@ impl PipelineElement for Stringify {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
fn signature(&self) -> ElementSignature {
|
||||||
ElementIo {
|
ElementSignature {
|
||||||
inputs: vec![DataType::Int],
|
inputs: vec![DataType::Int],
|
||||||
outputs: vec![DataType::String],
|
outputs: vec![DataType::String],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
//! Operation on String/text data
|
||||||
use crate::experimental::trait_based::{
|
use crate::experimental::trait_based::{
|
||||||
data::{
|
data::{
|
||||||
io::{Inputs, Outputs},
|
io::{Inputs, Outputs},
|
||||||
raw::Data,
|
raw::Data,
|
||||||
},
|
},
|
||||||
element::{DataType, ElementIo, PipelineElement},
|
element::{DataType, ElementSignature, PipelineElement},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Concatenate the inputs
|
||||||
pub struct Concatenate(pub String);
|
pub struct Concatenate(pub String);
|
||||||
impl PipelineElement for Concatenate {
|
impl PipelineElement for Concatenate {
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
@ -18,14 +20,15 @@ impl PipelineElement for Concatenate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
fn signature(&self) -> ElementSignature {
|
||||||
ElementIo {
|
ElementSignature {
|
||||||
inputs: vec![DataType::String, DataType::String],
|
inputs: vec![DataType::String, DataType::String],
|
||||||
outputs: vec![DataType::String],
|
outputs: vec![DataType::String],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn input text to uppercase
|
||||||
pub struct Upper;
|
pub struct Upper;
|
||||||
impl PipelineElement for Upper {
|
impl PipelineElement for Upper {
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
@ -38,14 +41,15 @@ impl PipelineElement for Upper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
fn signature(&self) -> ElementSignature {
|
||||||
ElementIo {
|
ElementSignature {
|
||||||
inputs: vec![DataType::String],
|
inputs: vec![DataType::String],
|
||||||
outputs: vec![DataType::String],
|
outputs: vec![DataType::String],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn input text to lowercase
|
||||||
pub struct Lower;
|
pub struct Lower;
|
||||||
impl PipelineElement for Lower {
|
impl PipelineElement for Lower {
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
||||||
|
@ -58,8 +62,8 @@ impl PipelineElement for Lower {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> ElementIo {
|
fn signature(&self) -> ElementSignature {
|
||||||
ElementIo {
|
ElementSignature {
|
||||||
inputs: vec![DataType::String],
|
inputs: vec![DataType::String],
|
||||||
outputs: vec![DataType::String],
|
outputs: vec![DataType::String],
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,25 @@ use super::data::io::{Inputs, Outputs};
|
||||||
use super::element::PipelineElement;
|
use super::element::PipelineElement;
|
||||||
use super::ops::prelude::*;
|
use super::ops::prelude::*;
|
||||||
|
|
||||||
// TODO:
|
/// Builder for the pipelines that are actually run
|
||||||
// - Bind additional inputs if instruction has more then one and is passd without any additional
|
///
|
||||||
// - allow binding to pointers to other pipelines?
|
/// TODO:
|
||||||
// - allow referencing earlier data
|
/// - 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 {
|
pub struct PipelineBuilder {
|
||||||
elements: Vec<Box<dyn PipelineElement>>,
|
elements: Vec<Box<dyn PipelineElement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineBuilder {
|
impl PipelineBuilder {
|
||||||
|
/// Create new, empty builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
elements: Vec::new(),
|
elements: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert element into pipeline
|
||||||
fn insert<T: PipelineElement + 'static>(mut self, el: T) -> Self {
|
fn insert<T: PipelineElement + 'static>(mut self, el: T) -> Self {
|
||||||
if let Some(previous_item) = self.elements.last() {
|
if let Some(previous_item) = self.elements.last() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -28,21 +32,25 @@ impl PipelineBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// insert string concatenattion element
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn concatenate(self, sec: String) -> Self {
|
pub fn concatenate(self, sec: String) -> Self {
|
||||||
self.insert(Concatenate(sec))
|
self.insert(Concatenate(sec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// insert string uppercase element
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn upper(self) -> Self {
|
pub fn upper(self) -> Self {
|
||||||
self.insert(Upper)
|
self.insert(Upper)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// insert string lowercase element
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn lower(self) -> Self {
|
pub fn lower(self) -> Self {
|
||||||
self.insert(Lower)
|
self.insert(Lower)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// insert numeric addition element
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(
|
#[allow(
|
||||||
clippy::should_implement_trait,
|
clippy::should_implement_trait,
|
||||||
|
@ -52,16 +60,19 @@ impl PipelineBuilder {
|
||||||
self.insert(Add(sec))
|
self.insert(Add(sec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// insert numeric subtraction element
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn subtract(self, sec: i32) -> Self {
|
pub fn subtract(self, sec: i32) -> Self {
|
||||||
self.insert(Subtract(sec))
|
self.insert(Subtract(sec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// insert stringify element
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn stringify(self) -> Self {
|
pub fn stringify(self) -> Self {
|
||||||
self.insert(Stringify)
|
self.insert(Stringify)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build the pipeline. Doesn't check again - `insert` should verify correctness.
|
||||||
pub fn build(&self) -> Pipeline {
|
pub fn build(&self) -> Pipeline {
|
||||||
let mut r = Vec::new();
|
let mut r = Vec::new();
|
||||||
|
|
||||||
|
@ -77,11 +88,13 @@ impl Default for PipelineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runnable pipeline - at the core of this library
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
runners: Vec<fn(&Inputs) -> Outputs>,
|
runners: Vec<fn(&Inputs) -> Outputs>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
|
/// run the pipeline
|
||||||
pub fn run(&self, inputs: Inputs) -> Outputs {
|
pub fn run(&self, inputs: Inputs) -> Outputs {
|
||||||
let mut out: Outputs = inputs.into();
|
let mut out: Outputs = inputs.into();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue