From 1d85252523b593f86c5d5fb9bd82eb0f3fdcc6fb Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 29 Jan 2024 22:47:35 +0100 Subject: [PATCH 01/15] processing library: init --- Cargo.lock | 135 +++++++++++++++++++++++++++------ Cargo.toml | 2 +- crates/prowocessing/Cargo.toml | 13 ++++ crates/prowocessing/src/lib.rs | 4 + 4 files changed, 129 insertions(+), 25 deletions(-) create mode 100644 crates/prowocessing/Cargo.toml create mode 100644 crates/prowocessing/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7447d0d..7a48440 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,15 @@ dependencies = [ "time", ] +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "ariadne" version = "0.4.0" @@ -293,6 +302,12 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fdeflate" version = "0.3.3" @@ -359,9 +374,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "image" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23" dependencies = [ "bytemuck", "byteorder", @@ -369,7 +384,6 @@ dependencies = [ "exr", "gif", "jpeg-decoder", - "num-rational", "num-traits", "png", "qoi", @@ -443,27 +457,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.17" @@ -494,6 +487,71 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" +[[package]] +name = "palette" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d38e6e5ca1612e2081cc31188f08c3cba630ce4ba44709a153f1a0f38d678f2" +dependencies = [ + "approx", + "fast-srgb8", + "palette_derive", + "phf", +] + +[[package]] +name = "palette_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05d1c929301fee6830dafa764341118829b2535c216b0571e3821ecac5c885b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "png" version = "0.17.10" @@ -522,6 +580,14 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prowocessing" +version = "0.1.0" +dependencies = [ + "image", + "palette", +] + [[package]] name = "qoi" version = "0.4.1" @@ -540,6 +606,21 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + [[package]] name = "rayon" version = "1.8.0" @@ -641,6 +722,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "smallvec" version = "1.11.2" diff --git a/Cargo.toml b/Cargo.toml index 6d7f53d..6527b6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = [ "crates/app", "crates/eval", - "crates/ir", + "crates/ir", "crates/prowocessing", ] resolver = "2" diff --git a/crates/prowocessing/Cargo.toml b/crates/prowocessing/Cargo.toml new file mode 100644 index 0000000..42d1a80 --- /dev/null +++ b/crates/prowocessing/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "prowocessing" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +image = "0.24.8" +palette = "0.7.4" + +[lints] +workspace = true diff --git a/crates/prowocessing/src/lib.rs b/crates/prowocessing/src/lib.rs new file mode 100644 index 0000000..f83705a --- /dev/null +++ b/crates/prowocessing/src/lib.rs @@ -0,0 +1,4 @@ +//! # This is the image processing library for iOwO +//! +//! One of the design goals for this library is, however, to be a simple, generic image processing library. +//! For now, it's just indev... lets see what comes of it! -- 2.46.0 From f86bd52b92875216c570c1476c5b1343ec8ab250 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 19 Feb 2024 12:56:47 +0100 Subject: [PATCH 02/15] experimentation: write experiment for enum architecture --- crates/prowocessing/src/lib.rs | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/crates/prowocessing/src/lib.rs b/crates/prowocessing/src/lib.rs index f83705a..8affe30 100644 --- a/crates/prowocessing/src/lib.rs +++ b/crates/prowocessing/src/lib.rs @@ -2,3 +2,79 @@ //! //! One of the design goals for this library is, however, to be a simple, generic image processing library. //! For now, it's just indev... lets see what comes of it! + +use experimental::enum_based::{Instruction, PipelineBuilder}; + +/// just some experiments, to test whether the architecture i want is even possible (or how to do it). probably temporary. +/// Gonna first try string processing... +mod experimental { + pub mod enum_based { + pub enum Instruction { + Uppercase, + Lowercase, + } + + pub struct Pipeline { + pipeline: Vec String>, + } + + impl Pipeline { + pub fn run(&self, val: String) -> String { + let mut current = val; + + for instr in &self.pipeline { + current = instr(current); + } + + current + } + } + + pub struct PipelineBuilder { + pipeline: Vec, + } + + impl PipelineBuilder { + pub fn new() -> Self { + Self { + pipeline: Vec::new(), + } + } + + pub fn insert(mut self, instr: Instruction) -> Self { + self.pipeline.push(instr); + self + } + + pub fn build(&self) -> Pipeline { + fn uppercase(v: String) -> String { + str::to_uppercase(&v) + } + fn lowercase(v: String) -> String { + str::to_lowercase(&v) + } + + let mut res = Vec::new(); + + for item in &self.pipeline { + res.push(match item { + Instruction::Uppercase => uppercase, + Instruction::Lowercase => lowercase, + }); + } + + Pipeline { pipeline: res } + } + } + } +} + +#[test] +fn test_enums() { + let builder = PipelineBuilder::new().insert(Instruction::Uppercase); + let upr = builder.build(); + let upr_lowr = builder.insert(Instruction::Lowercase).build(); + + assert_eq!(upr.run(String::from("Test")), String::from("TEST")); + assert_eq!(upr_lowr.run(String::from("Test")), String::from("test")); +} -- 2.46.0 From 33a1d8531818c281e10c9fa184d6ca777551a004 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 19 Feb 2024 17:54:40 +0100 Subject: [PATCH 03/15] cli: add subcommand support --- crates/app/src/config.rs | 20 +++++------------ crates/app/src/config/cli.rs | 9 +++----- crates/app/src/main.rs | 42 +++++++++++++++++++++++++++++------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/crates/app/src/config.rs b/crates/app/src/config.rs index b4d1ed1..552a951 100644 --- a/crates/app/src/config.rs +++ b/crates/app/src/config.rs @@ -1,18 +1,11 @@ -use std::path::PathBuf; - -use clap::Parser; - -use self::{ - cli::Args, - config_file::{find_config_file, Configs}, -}; +use self::config_file::{find_config_file, Configs}; +pub(crate) use cli::CliConfigs; mod cli; mod config_file; /// this struct may hold all configuration pub struct Config { - pub source: PathBuf, pub evaluator: eval::Available, pub startup_msg: bool, @@ -20,10 +13,9 @@ pub struct Config { impl Config { /// Get the configs from all possible places (args, file, env...) - pub fn read() -> Self { - let args = Args::parse(); - let config = if let Some(config) = args.config_path { - Ok(config) + pub fn read(args: &CliConfigs) -> Self { + let config = if let Some(config) = &args.config_path { + Ok(config.clone()) } else { find_config_file() }; @@ -42,7 +34,6 @@ impl Config { if let Some(file) = config { Self { - source: args.source, evaluator: args.evaluator.and(file.evaluator).unwrap_or_default(), // this is negated because to an outward api, the negative is more intuitive, // while in the source the other way around is more intuitive @@ -50,7 +41,6 @@ impl Config { } } else { Self { - source: args.source, startup_msg: !args.no_startup_message, evaluator: args.evaluator.unwrap_or_default(), } diff --git a/crates/app/src/config/cli.rs b/crates/app/src/config/cli.rs index 1d9c57a..c0e6c4d 100644 --- a/crates/app/src/config/cli.rs +++ b/crates/app/src/config/cli.rs @@ -1,12 +1,9 @@ use std::path::PathBuf; -use clap::{builder::BoolishValueParser, ArgAction, Parser}; - -#[derive(Parser)] -pub(crate) struct Args { - /// What file contains the pipeline to evaluate. - pub source: PathBuf, +use clap::{builder::BoolishValueParser, ArgAction, Args}; +#[derive(Args)] +pub(crate) struct CliConfigs { /// How to actually run the pipeline. /// Overrides the config file. Defaults to the debug evaluator. #[arg(short, long)] diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 58103a5..7d7eff2 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -1,6 +1,7 @@ -use std::fs; +use std::{fs, path::PathBuf}; -use config::Config; +use clap::{Parser, Subcommand}; +use config::{CliConfigs, Config}; use welcome_msg::print_startup_msg; mod config; @@ -9,19 +10,44 @@ mod config; mod error_reporting; mod welcome_msg; +#[derive(Parser)] +struct Args { + #[command(flatten)] + configs: CliConfigs, + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + Run { + /// What file contains the pipeline to evaluate. + source: PathBuf, + }, + Dev, +} + fn main() { // TODO: proper error handling across the whole function // don't forget to also look inside `Config` - let cfg = Config::read(); + let args = Args::parse(); + let cfg = Config::read(&args.configs); if cfg.startup_msg { print_startup_msg(); } - let source = fs::read_to_string(cfg.source).expect("can't find source file"); - let ir = ir::from_ron(&source).expect("failed to parse source to graph ir"); + match args.command { + Commands::Run { source } => { + let source = fs::read_to_string(source).expect("can't find source file"); + let ir = ir::from_ron(&source).expect("failed to parse source to graph ir"); - let mut machine = cfg.evaluator.pick(); - machine.feed(ir); - machine.eval_full(); + let mut machine = cfg.evaluator.pick(); + machine.feed(ir); + machine.eval_full(); + } + Commands::Dev => { + println!("Hello world!"); + } + } } -- 2.46.0 From 3af262258e8674eb3fd172dcf575d3c1b0f2c88f Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 19 Feb 2024 18:07:09 +0100 Subject: [PATCH 04/15] cli: add dev command for enums experiment --- Cargo.lock | 1 + crates/app/Cargo.toml | 1 + crates/app/src/main.rs | 36 +++++++++++++++++++++++++++++++--- crates/prowocessing/src/lib.rs | 9 ++++++++- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a48440..9b0db63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,7 @@ dependencies = [ "eval", "ir", "owo-colors", + "prowocessing", "ron", "serde", "serde_json", diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index 2caaaf4..a3204ee 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -11,6 +11,7 @@ clap = { workspace = true, features = [ "derive", "env" ] } dirs = "5" eval = { path = "../eval" } ir = { path = "../ir" } +prowocessing = { path = "../prowocessing"} owo-colors = "4" ron = "0.8" serde = { workspace = true, features = [ "derive" ] } diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 7d7eff2..2caaa2f 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -2,6 +2,7 @@ use std::{fs, path::PathBuf}; use clap::{Parser, Subcommand}; use config::{CliConfigs, Config}; +use dev::DevCommands; use welcome_msg::print_startup_msg; mod config; @@ -24,7 +25,10 @@ enum Commands { /// What file contains the pipeline to evaluate. source: PathBuf, }, - Dev, + Dev { + #[command(subcommand)] + dev_command: DevCommands, + }, } fn main() { @@ -46,8 +50,34 @@ fn main() { machine.feed(ir); machine.eval_full(); } - Commands::Dev => { - println!("Hello world!"); + Commands::Dev { dev_command } => dev_command.run(), + } +} + +mod dev { + use clap::Subcommand; + use prowocessing::experimental::enum_based::{Pipeline, PipelineBuilder}; + + #[derive(Subcommand)] + pub(crate) enum DevCommands { + Enums { test_str: String }, + } + + impl DevCommands { + pub fn run(self) { + match self { + DevCommands::Enums { test_str } => { + let upr = PipelineBuilder::new() + .insert(prowocessing::experimental::enum_based::Instruction::Uppercase) + .build(); + let lwr = PipelineBuilder::new() + .insert(prowocessing::experimental::enum_based::Instruction::Lowercase) + .build(); + + println!("Upr: {}", upr.run(test_str.clone())); + println!("Lwr: {}", lwr.run(test_str.clone())); + } + } } } } diff --git a/crates/prowocessing/src/lib.rs b/crates/prowocessing/src/lib.rs index 8affe30..778d544 100644 --- a/crates/prowocessing/src/lib.rs +++ b/crates/prowocessing/src/lib.rs @@ -7,7 +7,7 @@ use experimental::enum_based::{Instruction, PipelineBuilder}; /// just some experiments, to test whether the architecture i want is even possible (or how to do it). probably temporary. /// Gonna first try string processing... -mod experimental { +pub mod experimental { pub mod enum_based { pub enum Instruction { Uppercase, @@ -41,6 +41,7 @@ mod experimental { } } + #[must_use] pub fn insert(mut self, instr: Instruction) -> Self { self.pipeline.push(instr); self @@ -66,6 +67,12 @@ mod experimental { Pipeline { pipeline: res } } } + + impl Default for PipelineBuilder { + fn default() -> Self { + Self::new() + } + } } } -- 2.46.0 From 78d800b461db9d3aa8142c85f282e3de0ca84d02 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 19 Feb 2024 18:09:10 +0100 Subject: [PATCH 05/15] prowocessing: extract experiment into its own file --- crates/prowocessing/src/experimental.rs | 1 + .../src/experimental/enum_based.rs | 64 +++++++++++++++++ crates/prowocessing/src/lib.rs | 69 +------------------ 3 files changed, 66 insertions(+), 68 deletions(-) create mode 100644 crates/prowocessing/src/experimental.rs create mode 100644 crates/prowocessing/src/experimental/enum_based.rs diff --git a/crates/prowocessing/src/experimental.rs b/crates/prowocessing/src/experimental.rs new file mode 100644 index 0000000..090198e --- /dev/null +++ b/crates/prowocessing/src/experimental.rs @@ -0,0 +1 @@ +pub mod enum_based; diff --git a/crates/prowocessing/src/experimental/enum_based.rs b/crates/prowocessing/src/experimental/enum_based.rs new file mode 100644 index 0000000..c60f4a9 --- /dev/null +++ b/crates/prowocessing/src/experimental/enum_based.rs @@ -0,0 +1,64 @@ +pub enum Instruction { + Uppercase, + Lowercase, +} + +pub struct Pipeline { + pipeline: Vec String>, +} + +impl Pipeline { + pub fn run(&self, val: String) -> String { + let mut current = val; + + for instr in &self.pipeline { + current = instr(current); + } + + current + } +} + +pub struct PipelineBuilder { + pipeline: Vec, +} + +impl PipelineBuilder { + pub fn new() -> Self { + Self { + pipeline: Vec::new(), + } + } + + #[must_use] + pub fn insert(mut self, instr: Instruction) -> Self { + self.pipeline.push(instr); + self + } + + pub fn build(&self) -> Pipeline { + fn uppercase(v: String) -> String { + str::to_uppercase(&v) + } + fn lowercase(v: String) -> String { + str::to_lowercase(&v) + } + + let mut res = Vec::new(); + + for item in &self.pipeline { + res.push(match item { + Instruction::Uppercase => uppercase, + Instruction::Lowercase => lowercase, + }); + } + + Pipeline { pipeline: res } + } +} + +impl Default for PipelineBuilder { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/prowocessing/src/lib.rs b/crates/prowocessing/src/lib.rs index 778d544..2e7b047 100644 --- a/crates/prowocessing/src/lib.rs +++ b/crates/prowocessing/src/lib.rs @@ -7,74 +7,7 @@ use experimental::enum_based::{Instruction, PipelineBuilder}; /// just some experiments, to test whether the architecture i want is even possible (or how to do it). probably temporary. /// Gonna first try string processing... -pub mod experimental { - pub mod enum_based { - pub enum Instruction { - Uppercase, - Lowercase, - } - - pub struct Pipeline { - pipeline: Vec String>, - } - - impl Pipeline { - pub fn run(&self, val: String) -> String { - let mut current = val; - - for instr in &self.pipeline { - current = instr(current); - } - - current - } - } - - pub struct PipelineBuilder { - pipeline: Vec, - } - - impl PipelineBuilder { - pub fn new() -> Self { - Self { - pipeline: Vec::new(), - } - } - - #[must_use] - pub fn insert(mut self, instr: Instruction) -> Self { - self.pipeline.push(instr); - self - } - - pub fn build(&self) -> Pipeline { - fn uppercase(v: String) -> String { - str::to_uppercase(&v) - } - fn lowercase(v: String) -> String { - str::to_lowercase(&v) - } - - let mut res = Vec::new(); - - for item in &self.pipeline { - res.push(match item { - Instruction::Uppercase => uppercase, - Instruction::Lowercase => lowercase, - }); - } - - Pipeline { pipeline: res } - } - } - - impl Default for PipelineBuilder { - fn default() -> Self { - Self::new() - } - } - } -} +pub mod experimental; #[test] fn test_enums() { -- 2.46.0 From 2d537cc4eefaed0cb5d19a64dc05c1aaa2fe291f Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 19 Feb 2024 20:54:24 +0100 Subject: [PATCH 06/15] prowocessing: add trait based experiment --- crates/app/src/main.rs | 14 +- crates/prowocessing/src/experimental.rs | 2 + .../src/experimental/trait_based.rs | 339 ++++++++++++++++++ crates/prowocessing/src/lib.rs | 4 +- 4 files changed, 356 insertions(+), 3 deletions(-) create mode 100644 crates/prowocessing/src/experimental/trait_based.rs diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 2caaa2f..2534631 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -56,17 +56,20 @@ fn main() { mod dev { use clap::Subcommand; - use prowocessing::experimental::enum_based::{Pipeline, PipelineBuilder}; + use prowocessing::experimental::trait_based::DataType; #[derive(Subcommand)] pub(crate) enum DevCommands { Enums { test_str: String }, + Add { num0: i32, num1: i32 }, } impl DevCommands { pub fn run(self) { match self { DevCommands::Enums { test_str } => { + use prowocessing::experimental::enum_based::PipelineBuilder; + let upr = PipelineBuilder::new() .insert(prowocessing::experimental::enum_based::Instruction::Uppercase) .build(); @@ -77,6 +80,15 @@ mod dev { println!("Upr: {}", upr.run(test_str.clone())); println!("Lwr: {}", lwr.run(test_str.clone())); } + DevCommands::Add { num0, num1 } => { + use prowocessing::experimental::trait_based::PipelineBuilder; + + let pipe = PipelineBuilder::new().add(1).stringify().build(); + println!( + "{:?}", + pipe.run(vec![num0.into(), num1.into()].into()).into_inner()[0] + ); + } } } } diff --git a/crates/prowocessing/src/experimental.rs b/crates/prowocessing/src/experimental.rs index 090198e..fcc0d52 100644 --- a/crates/prowocessing/src/experimental.rs +++ b/crates/prowocessing/src/experimental.rs @@ -1 +1,3 @@ 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 new file mode 100644 index 0000000..3be8f3a --- /dev/null +++ b/crates/prowocessing/src/experimental/trait_based.rs @@ -0,0 +1,339 @@ +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], + } + } + } +} diff --git a/crates/prowocessing/src/lib.rs b/crates/prowocessing/src/lib.rs index 2e7b047..aa81057 100644 --- a/crates/prowocessing/src/lib.rs +++ b/crates/prowocessing/src/lib.rs @@ -2,8 +2,7 @@ //! //! One of the design goals for this library is, however, to be a simple, generic image processing library. //! For now, it's just indev... lets see what comes of it! - -use experimental::enum_based::{Instruction, PipelineBuilder}; +#![feature(lint_reasons)] /// just some experiments, to test whether the architecture i want is even possible (or how to do it). probably temporary. /// Gonna first try string processing... @@ -11,6 +10,7 @@ pub mod experimental; #[test] fn test_enums() { + use crate::experimental::enum_based::{Instruction, PipelineBuilder}; let builder = PipelineBuilder::new().insert(Instruction::Uppercase); let upr = builder.build(); let upr_lowr = builder.insert(Instruction::Lowercase).build(); -- 2.46.0 From 98f6af78be77fddd2ebf65613278f0480e336163 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Wed, 21 Feb 2024 13:11:31 +0100 Subject: [PATCH 07/15] prowocessing: refactor trait based experiment to individual files --- crates/app/src/main.rs | 3 +- .../src/experimental/trait_based.rs | 343 +----------------- .../src/experimental/trait_based/data.rs | 2 + .../src/experimental/trait_based/data/io.rs | 51 +++ .../src/experimental/trait_based/data/raw.rs | 48 +++ .../src/experimental/trait_based/element.rs | 19 + .../src/experimental/trait_based/ops.rs | 7 + .../src/experimental/trait_based/ops/num.rs | 69 ++++ .../src/experimental/trait_based/ops/str.rs | 67 ++++ .../src/experimental/trait_based/pipeline.rs | 94 +++++ 10 files changed, 362 insertions(+), 341 deletions(-) create mode 100644 crates/prowocessing/src/experimental/trait_based/data.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/data/io.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/data/raw.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/element.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/ops.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/ops/num.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/ops/str.rs create mode 100644 crates/prowocessing/src/experimental/trait_based/pipeline.rs 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 + } +} -- 2.46.0 From 0ebfed66edfec7f7fd810c8f96393588417d99ae Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Wed, 21 Feb 2024 14:24:57 +0100 Subject: [PATCH 08/15] 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(); -- 2.46.0 From ddc1f935c6856407d936b0a705c226b731a35b1e Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Fri, 23 Feb 2024 12:03:46 +0100 Subject: [PATCH 09/15] prowocessing: apply most basic reviews --- Cargo.toml | 3 +- crates/app/src/main.rs | 6 ++-- .../src/experimental/trait_based/data.rs | 2 -- .../src/experimental/trait_based/data/io.rs | 32 +++++++++++-------- .../src/experimental/trait_based/data/raw.rs | 32 +++++++++---------- .../src/experimental/trait_based/ops/num.rs | 8 ++--- .../src/experimental/trait_based/ops/str.rs | 8 ++--- 7 files changed, 48 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6527b6f..5f4bbef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,8 @@ members = [ "crates/app", "crates/eval", - "crates/ir", "crates/prowocessing", + "crates/ir", + "crates/prowocessing", ] resolver = "2" diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index d5a260c..ffd7271 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -27,7 +27,7 @@ enum Commands { }, Dev { #[command(subcommand)] - dev_command: DevCommands, + command: DevCommands, }, } @@ -50,7 +50,9 @@ fn main() { machine.feed(ir); machine.eval_full(); } - Commands::Dev { dev_command } => dev_command.run(), + Commands::Dev { + command: dev_command, + } => dev_command.run(), } } diff --git a/crates/prowocessing/src/experimental/trait_based/data.rs b/crates/prowocessing/src/experimental/trait_based/data.rs index 51ec597..e3dd671 100644 --- a/crates/prowocessing/src/experimental/trait_based/data.rs +++ b/crates/prowocessing/src/experimental/trait_based/data.rs @@ -1,7 +1,5 @@ //! 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 849f955..d091621 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/io.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/io.rs @@ -1,22 +1,26 @@ -use super::raw::{Data, OwnedData}; +//! Types for element and pipeline IO + +use std::convert::Into; + +use super::raw::{Data, DataRef}; /// Newtype struct with borrowed types for pipeline/element inputs, so that doesn't force a move or clone -pub struct Inputs<'a>(Vec>); +pub struct Inputs<'a>(Vec>); impl<'a> Inputs<'a> { /// get inner value(s) - pub(crate) fn inner(&self) -> Vec> { + pub(crate) fn inner(&self) -> Vec> { self.0.clone() } } -impl<'a> From>> for Inputs<'a> { - fn from(value: Vec>) -> Self { +impl<'a> From>> for Inputs<'a> { + fn from(value: Vec>) -> Self { Self(value) } } -impl<'a, T: Into>> From for Inputs<'a> { +impl<'a, T: Into>> From for Inputs<'a> { fn from(value: T) -> Self { Self(vec![value.into()]) } @@ -24,25 +28,25 @@ impl<'a, T: Into>> From for Inputs<'a> { impl<'a> From<&'a Outputs> for Inputs<'a> { fn from(value: &'a Outputs) -> Self { - Self(value.0.iter().map(std::convert::Into::into).collect()) + Self(value.0.iter().map(Into::into).collect()) } } -/// Newtype struct around `OwnedData` for pipeline/element outputs -pub struct Outputs(Vec); +/// Used for pipeline/element outputs +pub struct Outputs(Vec); impl Outputs { /// consume self and return inner value(s) - pub fn into_inner(self) -> Vec { + pub fn into_inner(self) -> Vec { self.0 } } -impl From> for Outputs { - fn from(value: Vec) -> Self { +impl From> for Outputs { + fn from(value: Vec) -> Self { Self(value) } } -impl> From for Outputs { +impl> From for Outputs { fn from(value: T) -> Self { Self(vec![value.into()]) } @@ -53,7 +57,7 @@ impl From> for Outputs { value .0 .into_iter() - .map(|i: Data<'_>| Data::to_owned_data(&i)) + .map(|i: DataRef<'_>| DataRef::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 index e028474..acc75c1 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/raw.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/raw.rs @@ -1,58 +1,58 @@ -//! Dynamic data storage and transfer types +//! Dynamic data storage and transfer types for use in [`io`] /// Owned data type, for use mostly in outputs and storage #[derive(Clone, Debug)] -pub enum OwnedData { +pub enum Data { String(String), Int(i32), } -impl From for OwnedData { +impl From for Data { fn from(value: String) -> Self { Self::String(value) } } -impl From for OwnedData { +impl From for Data { fn from(value: i32) -> Self { Self::Int(value) } } /// Unowned data type, for inputs into runner functions -#[derive(Clone, Copy)] -pub enum Data<'a> { +#[derive(Clone, Copy, Debug)] +pub enum DataRef<'a> { String(&'a str), Int(i32), } -impl Data<'_> { +impl DataRef<'_> { /// converts itself to `OwnedData` - pub fn to_owned_data(&self) -> OwnedData { + pub fn to_owned_data(&self) -> Data { match self { - Data::String(s) => (*s).to_owned().into(), - Data::Int(i) => (*i).into(), + DataRef::String(s) => (*s).to_owned().into(), + DataRef::Int(i) => (*i).into(), } } } -impl<'a> From<&'a str> for Data<'a> { +impl<'a> From<&'a str> for DataRef<'a> { fn from(value: &'a str) -> Self { Self::String(value) } } -impl From for Data<'_> { +impl From for DataRef<'_> { fn from(value: i32) -> Self { Self::Int(value) } } -impl<'a> From<&'a OwnedData> for Data<'a> { - fn from(value: &'a OwnedData) -> Self { +impl<'a> From<&'a Data> for DataRef<'a> { + fn from(value: &'a Data) -> Self { match value { - OwnedData::String(s) => Data::String(s), - OwnedData::Int(i) => Data::Int(*i), + Data::String(s) => DataRef::String(s), + Data::Int(i) => DataRef::Int(*i), } } } diff --git a/crates/prowocessing/src/experimental/trait_based/ops/num.rs b/crates/prowocessing/src/experimental/trait_based/ops/num.rs index 0b2a295..09b4372 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/num.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/num.rs @@ -4,7 +4,7 @@ use core::panic; use crate::experimental::trait_based::{ data::{ io::{Inputs, Outputs}, - raw::Data, + raw::DataRef, }, element::{DataType, ElementSignature, PipelineElement}, }; @@ -14,7 +14,7 @@ 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()[..] { + if let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] { (i0 + i1).into() } else { panic!("Invalid data passed") @@ -35,7 +35,7 @@ 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()[..] { + if let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] { (i0 + i1).into() } else { panic!("Invalid data passed") @@ -56,7 +56,7 @@ pub struct Stringify; impl PipelineElement for Stringify { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [Data::Int(int), ..] = input.inner()[..] { + if let [DataRef::Int(int), ..] = input.inner()[..] { int.to_string().into() } else { panic!("Invalid data passed") diff --git a/crates/prowocessing/src/experimental/trait_based/ops/str.rs b/crates/prowocessing/src/experimental/trait_based/ops/str.rs index 38fe992..dc0d99d 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/str.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/str.rs @@ -2,7 +2,7 @@ use crate::experimental::trait_based::{ data::{ io::{Inputs, Outputs}, - raw::Data, + raw::DataRef, }, element::{DataType, ElementSignature, PipelineElement}, }; @@ -12,7 +12,7 @@ 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()[..] { + if let [DataRef::String(s0), DataRef::String(s1), ..] = input.inner()[..] { format!("{s0}{s1}").into() } else { panic!("Invalid data passed") @@ -33,7 +33,7 @@ pub struct Upper; impl PipelineElement for Upper { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [Data::String(s), ..] = input.inner()[..] { + if let [DataRef::String(s), ..] = input.inner()[..] { s.to_uppercase().into() } else { panic!("Invalid data passed") @@ -54,7 +54,7 @@ pub struct Lower; impl PipelineElement for Lower { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [Data::String(s), ..] = input.inner()[..] { + if let [DataRef::String(s), ..] = input.inner()[..] { s.to_lowercase().into() } else { panic!("Invalid data passed") -- 2.46.0 From c900a0f4b3ca57a3402e8f5e0c50093ce15b4e3e Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Fri, 23 Feb 2024 12:11:35 +0100 Subject: [PATCH 10/15] prowocessing: let-else refatoring as according to review --- .../src/experimental/trait_based/ops/num.rs | 21 ++++++++----------- .../src/experimental/trait_based/ops/str.rs | 21 ++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/crates/prowocessing/src/experimental/trait_based/ops/num.rs b/crates/prowocessing/src/experimental/trait_based/ops/num.rs index 09b4372..a6ac18c 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/num.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/num.rs @@ -14,11 +14,10 @@ pub struct Add(pub i32); impl PipelineElement for Add { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] { - (i0 + i1).into() - } else { + let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] else { panic!("Invalid data passed") - } + }; + (i0 + i1).into() } } @@ -35,11 +34,10 @@ pub struct Subtract(pub i32); impl PipelineElement for Subtract { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] { - (i0 + i1).into() - } else { + let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] else { panic!("Invalid data passed") - } + }; + (i0 + i1).into() } } @@ -56,11 +54,10 @@ pub struct Stringify; impl PipelineElement for Stringify { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [DataRef::Int(int), ..] = input.inner()[..] { - int.to_string().into() - } else { + let [DataRef::Int(int), ..] = input.inner()[..] else { panic!("Invalid data passed") - } + }; + int.to_string().into() } } diff --git a/crates/prowocessing/src/experimental/trait_based/ops/str.rs b/crates/prowocessing/src/experimental/trait_based/ops/str.rs index dc0d99d..49ce606 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/str.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/str.rs @@ -12,11 +12,10 @@ pub struct Concatenate(pub String); impl PipelineElement for Concatenate { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [DataRef::String(s0), DataRef::String(s1), ..] = input.inner()[..] { - format!("{s0}{s1}").into() - } else { + let [DataRef::String(s0), DataRef::String(s1), ..] = input.inner()[..] else { panic!("Invalid data passed") - } + }; + format!("{s0}{s1}").into() } } @@ -33,11 +32,10 @@ pub struct Upper; impl PipelineElement for Upper { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [DataRef::String(s), ..] = input.inner()[..] { - s.to_uppercase().into() - } else { + let [DataRef::String(s), ..] = input.inner()[..] else { panic!("Invalid data passed") - } + }; + s.to_uppercase().into() } } @@ -54,11 +52,10 @@ pub struct Lower; impl PipelineElement for Lower { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - if let [DataRef::String(s), ..] = input.inner()[..] { - s.to_lowercase().into() - } else { + let [DataRef::String(s), ..] = input.inner()[..] else { panic!("Invalid data passed") - } + }; + s.to_lowercase().into() } } -- 2.46.0 From a3e357a0e7968deedf9fbaccc619eae24c06d470 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Fri, 23 Feb 2024 12:46:39 +0100 Subject: [PATCH 11/15] simplified by entirely removing `DataRef` --- crates/app/src/main.rs | 3 +- crates/eval/src/lib.rs | 2 +- .../src/experimental/trait_based/data/io.rs | 27 ++++--------- .../src/experimental/trait_based/data/raw.rs | 40 +------------------ .../src/experimental/trait_based/ops/num.rs | 8 ++-- .../src/experimental/trait_based/ops/str.rs | 8 ++-- 6 files changed, 19 insertions(+), 69 deletions(-) diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index ffd7271..7780bbb 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -87,7 +87,8 @@ mod dev { let pipe = PipelineBuilder::new().add(1).stringify().build(); println!( "{:?}", - pipe.run(vec![num0.into(), num1.into()].into()).into_inner()[0] + pipe.run(vec![&num0.into(), &num1.into()].into()) + .into_inner()[0] ); } } diff --git a/crates/eval/src/lib.rs b/crates/eval/src/lib.rs index c3a6c38..8687d91 100644 --- a/crates/eval/src/lib.rs +++ b/crates/eval/src/lib.rs @@ -37,7 +37,7 @@ impl Available { #[must_use] pub fn pick(&self) -> Box { match self { - Self::Debug => Box::new(kind::debug::Evaluator::default()), + Self::Debug => Box::::default(), } } } diff --git a/crates/prowocessing/src/experimental/trait_based/data/io.rs b/crates/prowocessing/src/experimental/trait_based/data/io.rs index d091621..59e2f28 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/io.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/io.rs @@ -1,26 +1,19 @@ //! Types for element and pipeline IO -use std::convert::Into; +use std::{borrow::ToOwned, convert::Into}; -use super::raw::{Data, DataRef}; +use super::raw::Data; /// Newtype struct with borrowed types for pipeline/element inputs, so that doesn't force a move or clone -pub struct Inputs<'a>(Vec>); +pub struct Inputs<'a>(pub Vec<&'a Data>); -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 { +impl<'a> From> for Inputs<'a> { + fn from(value: Vec<&'a Data>) -> Self { Self(value) } } -impl<'a, T: Into>> From for Inputs<'a> { +impl<'a, T: Into<&'a Data>> From for Inputs<'a> { fn from(value: T) -> Self { Self(vec![value.into()]) } @@ -53,12 +46,6 @@ impl> From for Outputs { } impl From> for Outputs { fn from(value: Inputs) -> Self { - Self( - value - .0 - .into_iter() - .map(|i: DataRef<'_>| DataRef::to_owned_data(&i)) - .collect(), - ) + Self(value.0.into_iter().map(ToOwned::to_owned).collect()) } } diff --git a/crates/prowocessing/src/experimental/trait_based/data/raw.rs b/crates/prowocessing/src/experimental/trait_based/data/raw.rs index acc75c1..502bb91 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/raw.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/raw.rs @@ -1,6 +1,6 @@ //! Dynamic data storage and transfer types for use in [`io`] -/// Owned data type, for use mostly in outputs and storage +// Dynamic data type #[derive(Clone, Debug)] pub enum Data { String(String), @@ -18,41 +18,3 @@ impl From for Data { Self::Int(value) } } - -/// Unowned data type, for inputs into runner functions -#[derive(Clone, Copy, Debug)] -pub enum DataRef<'a> { - String(&'a str), - Int(i32), -} - -impl DataRef<'_> { - /// converts itself to `OwnedData` - pub fn to_owned_data(&self) -> Data { - match self { - DataRef::String(s) => (*s).to_owned().into(), - DataRef::Int(i) => (*i).into(), - } - } -} - -impl<'a> From<&'a str> for DataRef<'a> { - fn from(value: &'a str) -> Self { - Self::String(value) - } -} - -impl From for DataRef<'_> { - fn from(value: i32) -> Self { - Self::Int(value) - } -} - -impl<'a> From<&'a Data> for DataRef<'a> { - fn from(value: &'a Data) -> Self { - match value { - Data::String(s) => DataRef::String(s), - Data::Int(i) => DataRef::Int(*i), - } - } -} diff --git a/crates/prowocessing/src/experimental/trait_based/ops/num.rs b/crates/prowocessing/src/experimental/trait_based/ops/num.rs index a6ac18c..1a0a701 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/num.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/num.rs @@ -4,7 +4,7 @@ use core::panic; use crate::experimental::trait_based::{ data::{ io::{Inputs, Outputs}, - raw::DataRef, + raw::Data, }, element::{DataType, ElementSignature, PipelineElement}, }; @@ -14,7 +14,7 @@ pub struct Add(pub i32); impl PipelineElement for Add { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] else { + let [Data::Int(i0), Data::Int(i1), ..] = input.0[..] else { panic!("Invalid data passed") }; (i0 + i1).into() @@ -34,7 +34,7 @@ pub struct Subtract(pub i32); impl PipelineElement for Subtract { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - let [DataRef::Int(i0), DataRef::Int(i1), ..] = input.inner()[..] else { + let [Data::Int(i0), Data::Int(i1), ..] = input.0[..] else { panic!("Invalid data passed") }; (i0 + i1).into() @@ -54,7 +54,7 @@ pub struct Stringify; impl PipelineElement for Stringify { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - let [DataRef::Int(int), ..] = input.inner()[..] else { + let [Data::Int(int), ..] = input.0[..] else { panic!("Invalid data passed") }; int.to_string().into() diff --git a/crates/prowocessing/src/experimental/trait_based/ops/str.rs b/crates/prowocessing/src/experimental/trait_based/ops/str.rs index 49ce606..01fd25a 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/str.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/str.rs @@ -2,7 +2,7 @@ use crate::experimental::trait_based::{ data::{ io::{Inputs, Outputs}, - raw::DataRef, + raw::Data, }, element::{DataType, ElementSignature, PipelineElement}, }; @@ -12,7 +12,7 @@ pub struct Concatenate(pub String); impl PipelineElement for Concatenate { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - let [DataRef::String(s0), DataRef::String(s1), ..] = input.inner()[..] else { + let [Data::String(s0), Data::String(s1), ..] = input.0[..] else { panic!("Invalid data passed") }; format!("{s0}{s1}").into() @@ -32,7 +32,7 @@ pub struct Upper; impl PipelineElement for Upper { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - let [DataRef::String(s), ..] = input.inner()[..] else { + let [Data::String(s), ..] = input.0[..] else { panic!("Invalid data passed") }; s.to_uppercase().into() @@ -52,7 +52,7 @@ pub struct Lower; impl PipelineElement for Lower { fn runner(&self) -> fn(&Inputs) -> Outputs { |input| { - let [DataRef::String(s), ..] = input.inner()[..] else { + let [Data::String(s), ..] = input.0[..] else { panic!("Invalid data passed") }; s.to_lowercase().into() -- 2.46.0 From 4bc84451e0a4a2d0dc26e77cc41154e2fa2b3faa Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 26 Feb 2024 12:36:57 +0100 Subject: [PATCH 12/15] experimentation: use dynamic type ids for signatures and add qol macro --- .../src/experimental/trait_based.rs | 1 + .../src/experimental/trait_based/element.rs | 18 +++++++++++------- .../src/experimental/trait_based/ops/num.rs | 18 +++++------------- .../src/experimental/trait_based/ops/str.rs | 17 ++++------------- 4 files changed, 21 insertions(+), 33 deletions(-) diff --git a/crates/prowocessing/src/experimental/trait_based.rs b/crates/prowocessing/src/experimental/trait_based.rs index 7e742a1..251fb35 100644 --- a/crates/prowocessing/src/experimental/trait_based.rs +++ b/crates/prowocessing/src/experimental/trait_based.rs @@ -5,6 +5,7 @@ //! - [Builder pattern](https://rust-unofficial.github.io/patterns/patterns/creational/builder.html) pub mod data; +#[macro_use] pub mod element; pub mod ops; pub mod pipeline; diff --git a/crates/prowocessing/src/experimental/trait_based/element.rs b/crates/prowocessing/src/experimental/trait_based/element.rs index b816351..b07c739 100644 --- a/crates/prowocessing/src/experimental/trait_based/element.rs +++ b/crates/prowocessing/src/experimental/trait_based/element.rs @@ -1,5 +1,7 @@ //! The trait and type representations +use std::any::TypeId; + use crate::experimental::trait_based::data::io::Inputs; use super::data::io::Outputs; @@ -13,13 +15,15 @@ pub(crate) trait PipelineElement { /// Type signature for an element used for static checking pub(crate) struct ElementSignature { - pub inputs: Vec, - pub outputs: Vec, + pub inputs: Vec, + pub outputs: Vec, } -/// Data type enum -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum DataType { - String, - Int, +macro_rules! signature { + ($($inputs:ty),+ => $($outputs:ty),+) => ( + ElementSignature { + inputs: vec![$(std::any::TypeId::of::<$inputs>(), )+], + outputs: vec![$(std::any::TypeId::of::<$outputs>(), )+] + } + ) } diff --git a/crates/prowocessing/src/experimental/trait_based/ops/num.rs b/crates/prowocessing/src/experimental/trait_based/ops/num.rs index 1a0a701..ea189bf 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/num.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/num.rs @@ -1,12 +1,13 @@ //! Operations on numeric data use core::panic; +use std::any::TypeId; use crate::experimental::trait_based::{ data::{ io::{Inputs, Outputs}, raw::Data, }, - element::{DataType, ElementSignature, PipelineElement}, + element::{ElementSignature, PipelineElement}, }; /// Addition @@ -22,10 +23,7 @@ impl PipelineElement for Add { } fn signature(&self) -> ElementSignature { - ElementSignature { - inputs: vec![DataType::Int, DataType::Int], - outputs: vec![DataType::Int], - } + signature!(i32, i32 => i32) } } @@ -42,10 +40,7 @@ impl PipelineElement for Subtract { } fn signature(&self) -> ElementSignature { - ElementSignature { - inputs: vec![DataType::Int, DataType::Int], - outputs: vec![DataType::Int], - } + signature!(i32, i32 => i32) } } @@ -62,9 +57,6 @@ impl PipelineElement for Stringify { } fn signature(&self) -> ElementSignature { - ElementSignature { - inputs: vec![DataType::Int], - outputs: vec![DataType::String], - } + signature!(i32 => String) } } diff --git a/crates/prowocessing/src/experimental/trait_based/ops/str.rs b/crates/prowocessing/src/experimental/trait_based/ops/str.rs index 01fd25a..fb59ada 100644 --- a/crates/prowocessing/src/experimental/trait_based/ops/str.rs +++ b/crates/prowocessing/src/experimental/trait_based/ops/str.rs @@ -4,7 +4,7 @@ use crate::experimental::trait_based::{ io::{Inputs, Outputs}, raw::Data, }, - element::{DataType, ElementSignature, PipelineElement}, + element::{ElementSignature, PipelineElement}, }; /// Concatenate the inputs @@ -20,10 +20,7 @@ impl PipelineElement for Concatenate { } fn signature(&self) -> ElementSignature { - ElementSignature { - inputs: vec![DataType::String, DataType::String], - outputs: vec![DataType::String], - } + signature!(String, String => String) } } @@ -40,10 +37,7 @@ impl PipelineElement for Upper { } fn signature(&self) -> ElementSignature { - ElementSignature { - inputs: vec![DataType::String], - outputs: vec![DataType::String], - } + signature!(String => String) } } @@ -60,9 +54,6 @@ impl PipelineElement for Lower { } fn signature(&self) -> ElementSignature { - ElementSignature { - inputs: vec![DataType::String], - outputs: vec![DataType::String], - } + signature!(String => String) } } -- 2.46.0 From 062138337cd50366072acefda099c3313fdce56f Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Tue, 27 Feb 2024 13:13:18 +0100 Subject: [PATCH 13/15] experimentation: implement some basic traits for io and data types --- crates/prowocessing/src/experimental/trait_based/data/io.rs | 4 +++- crates/prowocessing/src/experimental/trait_based/data/raw.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/prowocessing/src/experimental/trait_based/data/io.rs b/crates/prowocessing/src/experimental/trait_based/data/io.rs index 59e2f28..4eb9bd3 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/io.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/io.rs @@ -5,6 +5,7 @@ use std::{borrow::ToOwned, convert::Into}; use super::raw::Data; /// Newtype struct with borrowed types for pipeline/element inputs, so that doesn't force a move or clone +#[derive(PartialEq, Eq, Debug)] pub struct Inputs<'a>(pub Vec<&'a Data>); impl<'a> From> for Inputs<'a> { @@ -26,7 +27,8 @@ impl<'a> From<&'a Outputs> for Inputs<'a> { } /// Used for pipeline/element outputs -pub struct Outputs(Vec); +#[derive(PartialEq, Eq, Debug)] +pub struct Outputs(pub Vec); impl Outputs { /// consume self and return inner value(s) diff --git a/crates/prowocessing/src/experimental/trait_based/data/raw.rs b/crates/prowocessing/src/experimental/trait_based/data/raw.rs index 502bb91..6640e64 100644 --- a/crates/prowocessing/src/experimental/trait_based/data/raw.rs +++ b/crates/prowocessing/src/experimental/trait_based/data/raw.rs @@ -1,7 +1,7 @@ //! Dynamic data storage and transfer types for use in [`io`] // Dynamic data type -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Data { String(String), Int(i32), -- 2.46.0 From ecc466d01d4309ff505220ec9751b80282239442 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Tue, 27 Feb 2024 13:14:00 +0100 Subject: [PATCH 14/15] app, prowocessing: move dev commands to tests --- crates/app/src/main.rs | 31 ++--------------------------- crates/prowocessing/src/lib.rs | 36 ++++++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 7780bbb..9c7c0de 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -60,38 +60,11 @@ mod dev { use clap::Subcommand; #[derive(Subcommand)] - pub(crate) enum DevCommands { - Enums { test_str: String }, - Add { num0: i32, num1: i32 }, - } + pub(crate) enum DevCommands {} impl DevCommands { pub fn run(self) { - match self { - DevCommands::Enums { test_str } => { - use prowocessing::experimental::enum_based::PipelineBuilder; - - let upr = PipelineBuilder::new() - .insert(prowocessing::experimental::enum_based::Instruction::Uppercase) - .build(); - let lwr = PipelineBuilder::new() - .insert(prowocessing::experimental::enum_based::Instruction::Lowercase) - .build(); - - println!("Upr: {}", upr.run(test_str.clone())); - println!("Lwr: {}", lwr.run(test_str.clone())); - } - DevCommands::Add { num0, num1 } => { - use prowocessing::experimental::trait_based::pipeline::PipelineBuilder; - - let pipe = PipelineBuilder::new().add(1).stringify().build(); - println!( - "{:?}", - pipe.run(vec![&num0.into(), &num1.into()].into()) - .into_inner()[0] - ); - } - } + println!("There are currently no dev commands."); } } } diff --git a/crates/prowocessing/src/lib.rs b/crates/prowocessing/src/lib.rs index aa81057..083eb4f 100644 --- a/crates/prowocessing/src/lib.rs +++ b/crates/prowocessing/src/lib.rs @@ -8,13 +8,33 @@ /// Gonna first try string processing... pub mod experimental; -#[test] -fn test_enums() { - use crate::experimental::enum_based::{Instruction, PipelineBuilder}; - let builder = PipelineBuilder::new().insert(Instruction::Uppercase); - let upr = builder.build(); - let upr_lowr = builder.insert(Instruction::Lowercase).build(); +#[cfg(test)] +mod tests { + use crate::experimental::{ + enum_based, + trait_based::{self, data::io::Outputs}, + }; - assert_eq!(upr.run(String::from("Test")), String::from("TEST")); - assert_eq!(upr_lowr.run(String::from("Test")), String::from("test")); + #[test] + fn test_enums() { + let builder = enum_based::PipelineBuilder::new().insert(enum_based::Instruction::Uppercase); + let upr = builder.build(); + let upr_lowr = builder.insert(enum_based::Instruction::Lowercase).build(); + + assert_eq!(upr.run(String::from("Test")), String::from("TEST")); + assert_eq!(upr_lowr.run(String::from("Test")), String::from("test")); + } + + #[test] + fn add() { + let pipe = trait_based::pipeline::PipelineBuilder::new() + .add(0) + .stringify() + .build(); + + assert_eq!( + pipe.run(vec![&2.into(), &3.into()].into()), + Outputs(vec![String::from("5").into()]) + ); + } } -- 2.46.0 From 6d318aa7c91cc8183c0eacf91d479afef7230438 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Tue, 27 Feb 2024 13:18:01 +0100 Subject: [PATCH 15/15] app: apply review --- crates/app/src/config.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/app/src/config.rs b/crates/app/src/config.rs index 552a951..17cd39c 100644 --- a/crates/app/src/config.rs +++ b/crates/app/src/config.rs @@ -14,11 +14,16 @@ pub struct Config { impl Config { /// Get the configs from all possible places (args, file, env...) pub fn read(args: &CliConfigs) -> Self { - let config = if let Some(config) = &args.config_path { - Ok(config.clone()) - } else { - find_config_file() - }; + // let config = if let Some(config) = &args.config_path { + // Ok(config.clone()) + // } else { + // find_config_file() + // }; + let config = args + .config_path + .clone() + .ok_or(()) + .or_else(|()| find_config_file()); // try to read a maybe existing config file let config = config.ok().and_then(|path| { -- 2.46.0