From 0ebfed66edfec7f7fd810c8f96393588417d99ae Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Wed, 21 Feb 2024 14:24:57 +0100 Subject: [PATCH] prowocessing: add documentation of trait experiment --- crates/prowocessing/src/experimental.rs | 1 - .../src/experimental/trait_based.rs | 6 +++ .../src/experimental/trait_based/data.rs | 5 +++ .../src/experimental/trait_based/data/io.rs | 9 ++++ .../src/experimental/trait_based/data/raw.rs | 42 ++++++++++++------- .../src/experimental/trait_based/element.rs | 10 ++++- .../src/experimental/trait_based/ops/num.rs | 18 ++++---- .../src/experimental/trait_based/ops/str.rs | 18 ++++---- .../src/experimental/trait_based/pipeline.rs | 21 ++++++++-- 9 files changed, 93 insertions(+), 37 deletions(-) diff --git a/crates/prowocessing/src/experimental.rs b/crates/prowocessing/src/experimental.rs index fcc0d52..1a0f7e3 100644 --- a/crates/prowocessing/src/experimental.rs +++ b/crates/prowocessing/src/experimental.rs @@ -1,3 +1,2 @@ pub mod enum_based; - pub mod trait_based; diff --git a/crates/prowocessing/src/experimental/trait_based.rs b/crates/prowocessing/src/experimental/trait_based.rs index de2fdac..7e742a1 100644 --- a/crates/prowocessing/src/experimental/trait_based.rs +++ b/crates/prowocessing/src/experimental/trait_based.rs @@ -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 element; pub mod ops; diff --git a/crates/prowocessing/src/experimental/trait_based/data.rs b/crates/prowocessing/src/experimental/trait_based/data.rs index cc27567..51ec597 100644 --- a/crates/prowocessing/src/experimental/trait_based/data.rs +++ b/crates/prowocessing/src/experimental/trait_based/data.rs @@ -1,2 +1,7 @@ +//! Definitions of the data transfer and storage types. + +/// Types for element and pipeline IO pub mod io; + +/// Raw data types contained in `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 index fe40344..849f955 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/io.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/io.rs @@ -1,29 +1,38 @@ 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>); + impl<'a> Inputs<'a> { + /// get inner value(s) 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()) } } +/// Newtype struct around `OwnedData` for pipeline/element outputs pub struct Outputs(Vec); + impl Outputs { + /// consume self and return inner value(s) pub fn into_inner(self) -> Vec { self.0 } diff --git a/crates/prowocessing/src/experimental/trait_based/data/raw.rs b/crates/prowocessing/src/experimental/trait_based/data/raw.rs index 88c16e7..e028474 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/raw.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/raw.rs @@ -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 for OwnedData { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From for OwnedData { + fn from(value: i32) -> Self { + Self::Int(value) + } +} + +/// Unowned data type, for inputs into runner functions #[derive(Clone, Copy)] pub enum Data<'a> { String(&'a str), @@ -5,6 +27,7 @@ pub enum Data<'a> { } impl Data<'_> { + /// converts itself to `OwnedData` pub fn to_owned_data(&self) -> OwnedData { match self { Data::String(s) => (*s).to_owned().into(), @@ -12,16 +35,19 @@ impl Data<'_> { } } } + 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 { @@ -30,19 +56,3 @@ impl<'a> From<&'a OwnedData> for Data<'a> { } } } - -#[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 index 6fdba6b..b816351 100644 --- a/crates/prowocessing/src/experimental/trait_based/element.rs +++ b/crates/prowocessing/src/experimental/trait_based/element.rs @@ -1,17 +1,23 @@ +//! The trait and type representations + use crate::experimental::trait_based::data::io::Inputs; use super::data::io::Outputs; 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 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, pub outputs: Vec, } +/// Data type enum #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DataType { String, diff --git a/crates/prowocessing/src/experimental/trait_based/ops/num.rs b/crates/prowocessing/src/experimental/trait_based/ops/num.rs index 88b57d3..0b2a295 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/num.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/num.rs @@ -1,3 +1,4 @@ +//! Operations on numeric data use core::panic; use crate::experimental::trait_based::{ @@ -5,9 +6,10 @@ use crate::experimental::trait_based::{ io::{Inputs, Outputs}, raw::Data, }, - element::{DataType, ElementIo, PipelineElement}, + element::{DataType, ElementSignature, PipelineElement}, }; +/// Addition pub struct Add(pub i32); impl PipelineElement for Add { fn runner(&self) -> fn(&Inputs) -> Outputs { @@ -20,14 +22,15 @@ impl PipelineElement for Add { } } - fn signature(&self) -> ElementIo { - ElementIo { + fn signature(&self) -> ElementSignature { + ElementSignature { inputs: vec![DataType::Int, DataType::Int], outputs: vec![DataType::Int], } } } +/// Subtraction pub struct Subtract(pub i32); impl PipelineElement for Subtract { fn runner(&self) -> fn(&Inputs) -> Outputs { @@ -40,14 +43,15 @@ impl PipelineElement for Subtract { } } - fn signature(&self) -> ElementIo { - ElementIo { + fn signature(&self) -> ElementSignature { + ElementSignature { inputs: vec![DataType::Int, DataType::Int], outputs: vec![DataType::Int], } } } +/// Turn input to string pub struct Stringify; impl PipelineElement for Stringify { fn runner(&self) -> fn(&Inputs) -> Outputs { @@ -60,8 +64,8 @@ impl PipelineElement for Stringify { } } - fn signature(&self) -> ElementIo { - ElementIo { + fn signature(&self) -> ElementSignature { + ElementSignature { 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 index 56c39ad..38fe992 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/str.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/str.rs @@ -1,11 +1,13 @@ +//! Operation on String/text data use crate::experimental::trait_based::{ data::{ io::{Inputs, Outputs}, raw::Data, }, - element::{DataType, ElementIo, PipelineElement}, + element::{DataType, ElementSignature, PipelineElement}, }; +/// Concatenate the inputs pub struct Concatenate(pub String); impl PipelineElement for Concatenate { fn runner(&self) -> fn(&Inputs) -> Outputs { @@ -18,14 +20,15 @@ impl PipelineElement for Concatenate { } } - fn signature(&self) -> ElementIo { - ElementIo { + fn signature(&self) -> ElementSignature { + ElementSignature { inputs: vec![DataType::String, DataType::String], outputs: vec![DataType::String], } } } +/// Turn input text to uppercase pub struct Upper; impl PipelineElement for Upper { fn runner(&self) -> fn(&Inputs) -> Outputs { @@ -38,14 +41,15 @@ impl PipelineElement for Upper { } } - fn signature(&self) -> ElementIo { - ElementIo { + fn signature(&self) -> ElementSignature { + ElementSignature { inputs: vec![DataType::String], outputs: vec![DataType::String], } } } +/// Turn input text to lowercase pub struct Lower; impl PipelineElement for Lower { fn runner(&self) -> fn(&Inputs) -> Outputs { @@ -58,8 +62,8 @@ impl PipelineElement for Lower { } } - fn signature(&self) -> ElementIo { - ElementIo { + fn signature(&self) -> ElementSignature { + ElementSignature { 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 index 628130b..715fda7 100644 --- a/crates/prowocessing/src/experimental/trait_based/pipeline.rs +++ b/crates/prowocessing/src/experimental/trait_based/pipeline.rs @@ -2,21 +2,25 @@ 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 +/// Builder for the pipelines that are actually run +/// +/// 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 { + /// Create new, empty builder pub fn new() -> Self { Self { elements: Vec::new(), } } + /// Insert element into pipeline fn insert(mut self, el: T) -> Self { if let Some(previous_item) = self.elements.last() { assert_eq!( @@ -28,21 +32,25 @@ impl PipelineBuilder { self } + /// insert string concatenattion element #[must_use] pub fn concatenate(self, sec: String) -> Self { self.insert(Concatenate(sec)) } + /// insert string uppercase element #[must_use] pub fn upper(self) -> Self { self.insert(Upper) } + /// insert string lowercase element #[must_use] pub fn lower(self) -> Self { self.insert(Lower) } + /// insert numeric addition element #[must_use] #[allow( clippy::should_implement_trait, @@ -52,16 +60,19 @@ impl PipelineBuilder { self.insert(Add(sec)) } + /// insert numeric subtraction element #[must_use] pub fn subtract(self, sec: i32) -> Self { self.insert(Subtract(sec)) } + /// insert stringify element #[must_use] pub fn stringify(self) -> Self { self.insert(Stringify) } + /// Build the pipeline. Doesn't check again - `insert` should verify correctness. pub fn build(&self) -> Pipeline { let mut r = Vec::new(); @@ -77,11 +88,13 @@ impl Default for PipelineBuilder { } } +/// Runnable pipeline - at the core of this library pub struct Pipeline { runners: Vec Outputs>, } impl Pipeline { + /// run the pipeline pub fn run(&self, inputs: Inputs) -> Outputs { let mut out: Outputs = inputs.into();