Compare commits
No commits in common. "54401d2a21b83a25f2f28cca90220c153cad0f11" and "dc44244e7b88fa86ca471d2659c4e772d6c9a817" have entirely different histories.
54401d2a21
...
dc44244e7b
20 changed files with 57 additions and 651 deletions
133
Cargo.lock
generated
133
Cargo.lock
generated
|
@ -66,22 +66,12 @@ dependencies = [
|
||||||
"eval",
|
"eval",
|
||||||
"ir",
|
"ir",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
"prowocessing",
|
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ariadne"
|
name = "ariadne"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -441,12 +431,6 @@ dependencies = [
|
||||||
"zune-inflate",
|
"zune-inflate",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fast-srgb8"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -543,9 +527,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.24.8"
|
version = "0.24.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23"
|
checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
@ -553,6 +537,7 @@ dependencies = [
|
||||||
"exr",
|
"exr",
|
||||||
"gif",
|
"gif",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png",
|
||||||
"qoi",
|
"qoi",
|
||||||
|
@ -733,6 +718,27 @@ dependencies = [
|
||||||
"simd-adler32",
|
"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]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
@ -837,71 +843,6 @@ dependencies = [
|
||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.10"
|
version = "0.17.10"
|
||||||
|
@ -930,14 +871,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prowocessing"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"image",
|
|
||||||
"palette",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "qoi"
|
name = "qoi"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -969,24 +902,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
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"
|
|
||||||
>>>>>>> 1d85252 (processing library: init)
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|
|
@ -5,7 +5,6 @@ members = [
|
||||||
"crates/ir",
|
"crates/ir",
|
||||||
"crates/lang",
|
"crates/lang",
|
||||||
"crates/svg-filters",
|
"crates/svg-filters",
|
||||||
"crates/prowocessing",
|
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ clap = { workspace = true, features = [ "derive", "env" ] }
|
||||||
dirs = "5"
|
dirs = "5"
|
||||||
eval = { path = "../eval" }
|
eval = { path = "../eval" }
|
||||||
ir = { path = "../ir" }
|
ir = { path = "../ir" }
|
||||||
prowocessing = { path = "../prowocessing"}
|
|
||||||
owo-colors = "4"
|
owo-colors = "4"
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { workspace = true, features = [ "derive" ] }
|
serde = { workspace = true, features = [ "derive" ] }
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
use self::config_file::{find_config_file, Configs};
|
use std::path::PathBuf;
|
||||||
pub(crate) use cli::CliConfigs;
|
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
use self::{
|
||||||
|
cli::Args,
|
||||||
|
config_file::{find_config_file, Configs},
|
||||||
|
};
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod config_file;
|
mod config_file;
|
||||||
|
|
||||||
/// this struct may hold all configuration
|
/// this struct may hold all configuration
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
pub source: PathBuf,
|
||||||
pub evaluator: eval::Available,
|
pub evaluator: eval::Available,
|
||||||
|
|
||||||
pub startup_msg: bool,
|
pub startup_msg: bool,
|
||||||
|
@ -13,17 +20,13 @@ pub struct Config {
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Get the configs from all possible places (args, file, env...)
|
/// Get the configs from all possible places (args, file, env...)
|
||||||
pub fn read(args: &CliConfigs) -> Self {
|
pub fn read() -> Self {
|
||||||
// let config = if let Some(config) = &args.config_path {
|
let args = Args::parse();
|
||||||
// Ok(config.clone())
|
let config = if let Some(config) = args.config_path {
|
||||||
// } else {
|
Ok(config)
|
||||||
// find_config_file()
|
} 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
|
// try to read a maybe existing config file
|
||||||
let config = config.ok().and_then(|path| {
|
let config = config.ok().and_then(|path| {
|
||||||
|
@ -39,6 +42,7 @@ impl Config {
|
||||||
|
|
||||||
if let Some(file) = config {
|
if let Some(file) = config {
|
||||||
Self {
|
Self {
|
||||||
|
source: args.source,
|
||||||
evaluator: args.evaluator.and(file.evaluator).unwrap_or_default(),
|
evaluator: args.evaluator.and(file.evaluator).unwrap_or_default(),
|
||||||
// this is negated because to an outward api, the negative is more intuitive,
|
// this is negated because to an outward api, the negative is more intuitive,
|
||||||
// while in the source the other way around is more intuitive
|
// while in the source the other way around is more intuitive
|
||||||
|
@ -46,6 +50,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
|
source: args.source,
|
||||||
startup_msg: !args.no_startup_message,
|
startup_msg: !args.no_startup_message,
|
||||||
evaluator: args.evaluator.unwrap_or_default(),
|
evaluator: args.evaluator.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{builder::BoolishValueParser, ArgAction, Args};
|
use clap::{builder::BoolishValueParser, ArgAction, Parser};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub(crate) struct Args {
|
||||||
|
/// What file contains the pipeline to evaluate.
|
||||||
|
pub source: PathBuf,
|
||||||
|
|
||||||
#[derive(Args)]
|
|
||||||
pub(crate) struct CliConfigs {
|
|
||||||
/// How to actually run the pipeline.
|
/// How to actually run the pipeline.
|
||||||
/// Overrides the config file. Defaults to the debug evaluator.
|
/// Overrides the config file. Defaults to the debug evaluator.
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use std::{fs, path::PathBuf};
|
use std::fs;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use config::Config;
|
||||||
use config::{CliConfigs, Config};
|
|
||||||
use dev::DevCommands;
|
|
||||||
use welcome_msg::print_startup_msg;
|
use welcome_msg::print_startup_msg;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
@ -11,60 +9,19 @@ mod config;
|
||||||
mod error_reporting;
|
mod error_reporting;
|
||||||
mod welcome_msg;
|
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 {
|
|
||||||
#[command(subcommand)]
|
|
||||||
command: DevCommands,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO: proper error handling across the whole function
|
// TODO: proper error handling across the whole function
|
||||||
// don't forget to also look inside `Config`
|
// don't forget to also look inside `Config`
|
||||||
let args = Args::parse();
|
let cfg = Config::read();
|
||||||
let cfg = Config::read(&args.configs);
|
|
||||||
|
|
||||||
if cfg.startup_msg {
|
if cfg.startup_msg {
|
||||||
print_startup_msg();
|
print_startup_msg();
|
||||||
}
|
}
|
||||||
|
|
||||||
match args.command {
|
let source = fs::read_to_string(cfg.source).expect("can't find source file");
|
||||||
Commands::Run { source } => {
|
let ir = ir::from_ron(&source).expect("failed to parse source to graph ir");
|
||||||
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();
|
let mut machine = cfg.evaluator.pick();
|
||||||
machine.feed(ir);
|
machine.feed(ir);
|
||||||
machine.eval_full();
|
machine.eval_full();
|
||||||
}
|
|
||||||
Commands::Dev {
|
|
||||||
command: dev_command,
|
|
||||||
} => dev_command.run(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod dev {
|
|
||||||
use clap::Subcommand;
|
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
|
||||||
pub(crate) enum DevCommands {}
|
|
||||||
|
|
||||||
impl DevCommands {
|
|
||||||
pub fn run(self) {
|
|
||||||
println!("There are currently no dev commands.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl Available {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn pick(&self) -> Box<dyn Evaluator> {
|
pub fn pick(&self) -> Box<dyn Evaluator> {
|
||||||
match self {
|
match self {
|
||||||
Self::Debug => Box::<kind::debug::Evaluator>::default(),
|
Self::Debug => Box::new(kind::debug::Evaluator::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
[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
|
|
|
@ -1,2 +0,0 @@
|
||||||
pub mod enum_based;
|
|
||||||
pub mod trait_based;
|
|
|
@ -1,64 +0,0 @@
|
||||||
pub enum Instruction {
|
|
||||||
Uppercase,
|
|
||||||
Lowercase,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Pipeline {
|
|
||||||
pipeline: Vec<fn(String) -> 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<Instruction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
//! 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;
|
|
||||||
#[macro_use]
|
|
||||||
pub mod element;
|
|
||||||
pub mod ops;
|
|
||||||
pub mod pipeline;
|
|
|
@ -1,5 +0,0 @@
|
||||||
//! Definitions of the data transfer and storage types.
|
|
||||||
|
|
||||||
pub mod io;
|
|
||||||
|
|
||||||
pub mod raw;
|
|
|
@ -1,53 +0,0 @@
|
||||||
//! Types for element and pipeline IO
|
|
||||||
|
|
||||||
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<Vec<&'a Data>> for Inputs<'a> {
|
|
||||||
fn from(value: Vec<&'a Data>) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Into<&'a Data>> From<T> for Inputs<'a> {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self(vec![value.into()])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Outputs> for Inputs<'a> {
|
|
||||||
fn from(value: &'a Outputs) -> Self {
|
|
||||||
Self(value.0.iter().map(Into::into).collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used for pipeline/element outputs
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
|
||||||
pub struct Outputs(pub Vec<Data>);
|
|
||||||
|
|
||||||
impl Outputs {
|
|
||||||
/// consume self and return inner value(s)
|
|
||||||
pub fn into_inner(self) -> Vec<Data> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Vec<Data>> for Outputs {
|
|
||||||
fn from(value: Vec<Data>) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Into<Data>> From<T> for Outputs {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self(vec![value.into()])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Inputs<'_>> for Outputs {
|
|
||||||
fn from(value: Inputs) -> Self {
|
|
||||||
Self(value.0.into_iter().map(ToOwned::to_owned).collect())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
//! Dynamic data storage and transfer types for use in [`io`]
|
|
||||||
|
|
||||||
// Dynamic data type
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum Data {
|
|
||||||
String(String),
|
|
||||||
Int(i32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for Data {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
Self::String(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i32> for Data {
|
|
||||||
fn from(value: i32) -> Self {
|
|
||||||
Self::Int(value)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
//! The trait and type representations
|
|
||||||
|
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
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;
|
|
||||||
/// return the signature of the element
|
|
||||||
fn signature(&self) -> ElementSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Type signature for an element used for static checking
|
|
||||||
pub(crate) struct ElementSignature {
|
|
||||||
pub inputs: Vec<TypeId>,
|
|
||||||
pub outputs: Vec<TypeId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! signature {
|
|
||||||
($($inputs:ty),+ => $($outputs:ty),+) => (
|
|
||||||
ElementSignature {
|
|
||||||
inputs: vec![$(std::any::TypeId::of::<$inputs>(), )+],
|
|
||||||
outputs: vec![$(std::any::TypeId::of::<$outputs>(), )+]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
mod num;
|
|
||||||
mod str;
|
|
||||||
|
|
||||||
pub mod prelude {
|
|
||||||
pub(crate) use super::num::*;
|
|
||||||
pub(crate) use super::str::*;
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
//! Operations on numeric data
|
|
||||||
use core::panic;
|
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
use crate::experimental::trait_based::{
|
|
||||||
data::{
|
|
||||||
io::{Inputs, Outputs},
|
|
||||||
raw::Data,
|
|
||||||
},
|
|
||||||
element::{ElementSignature, PipelineElement},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Addition
|
|
||||||
pub struct Add(pub i32);
|
|
||||||
impl PipelineElement for Add {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
let [Data::Int(i0), Data::Int(i1), ..] = input.0[..] else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
};
|
|
||||||
(i0 + i1).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementSignature {
|
|
||||||
signature!(i32, i32 => i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Subtraction
|
|
||||||
pub struct Subtract(pub i32);
|
|
||||||
impl PipelineElement for Subtract {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
let [Data::Int(i0), Data::Int(i1), ..] = input.0[..] else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
};
|
|
||||||
(i0 + i1).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementSignature {
|
|
||||||
signature!(i32, i32 => i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turn input to string
|
|
||||||
pub struct Stringify;
|
|
||||||
impl PipelineElement for Stringify {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
let [Data::Int(int), ..] = input.0[..] else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
};
|
|
||||||
int.to_string().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementSignature {
|
|
||||||
signature!(i32 => String)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
//! Operation on String/text data
|
|
||||||
use crate::experimental::trait_based::{
|
|
||||||
data::{
|
|
||||||
io::{Inputs, Outputs},
|
|
||||||
raw::Data,
|
|
||||||
},
|
|
||||||
element::{ElementSignature, PipelineElement},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Concatenate the inputs
|
|
||||||
pub struct Concatenate(pub String);
|
|
||||||
impl PipelineElement for Concatenate {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
let [Data::String(s0), Data::String(s1), ..] = input.0[..] else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
};
|
|
||||||
format!("{s0}{s1}").into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementSignature {
|
|
||||||
signature!(String, String => String)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turn input text to uppercase
|
|
||||||
pub struct Upper;
|
|
||||||
impl PipelineElement for Upper {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
let [Data::String(s), ..] = input.0[..] else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
};
|
|
||||||
s.to_uppercase().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementSignature {
|
|
||||||
signature!(String => String)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turn input text to lowercase
|
|
||||||
pub struct Lower;
|
|
||||||
impl PipelineElement for Lower {
|
|
||||||
fn runner(&self) -> fn(&Inputs) -> Outputs {
|
|
||||||
|input| {
|
|
||||||
let [Data::String(s), ..] = input.0[..] else {
|
|
||||||
panic!("Invalid data passed")
|
|
||||||
};
|
|
||||||
s.to_lowercase().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> ElementSignature {
|
|
||||||
signature!(String => String)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
use super::data::io::{Inputs, Outputs};
|
|
||||||
use super::element::PipelineElement;
|
|
||||||
use super::ops::prelude::*;
|
|
||||||
|
|
||||||
/// 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<Box<dyn PipelineElement>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PipelineBuilder {
|
|
||||||
/// Create new, empty builder
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
elements: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Insert element into pipeline
|
|
||||||
fn insert<T: PipelineElement + 'static>(mut self, el: T) -> Self {
|
|
||||||
if let Some(previous_item) = self.elements.last() {
|
|
||||||
assert_eq!(
|
|
||||||
previous_item.signature().outputs[0],
|
|
||||||
el.signature().inputs[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.elements.push(Box::new(el));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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,
|
|
||||||
reason = "is not equivalent to addition"
|
|
||||||
)]
|
|
||||||
pub fn add(self, sec: i32) -> Self {
|
|
||||||
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();
|
|
||||||
|
|
||||||
self.elements.iter().for_each(|el| r.push(el.runner()));
|
|
||||||
|
|
||||||
Pipeline { runners: r }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PipelineBuilder {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runnable pipeline - at the core of this library
|
|
||||||
pub struct Pipeline {
|
|
||||||
runners: Vec<fn(&Inputs) -> Outputs>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pipeline {
|
|
||||||
/// run the pipeline
|
|
||||||
pub fn run(&self, inputs: Inputs) -> Outputs {
|
|
||||||
let mut out: Outputs = inputs.into();
|
|
||||||
|
|
||||||
for runner in &self.runners {
|
|
||||||
out = runner(&(&out).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
//! # 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!
|
|
||||||
#![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...
|
|
||||||
pub mod experimental;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::experimental::{
|
|
||||||
enum_based,
|
|
||||||
trait_based::{self, data::io::Outputs},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[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()])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue