finish implementing the modular object format #3
13 changed files with 442 additions and 75 deletions
|
|
@ -27,7 +27,7 @@ object templates can define several options for each property:
|
||||||
- `transforms`: uses this property as an input of a new object
|
- `transforms`: uses this property as an input of a new object
|
||||||
- `subobjects`: creates a parent-child relationship between this and at least one more object, based on the properties sharing a value and their transformations
|
- `subobjects`: creates a parent-child relationship between this and at least one more object, based on the properties sharing a value and their transformations
|
||||||
- `conditions`: values other properties need to hold for this property to be valid
|
- `conditions`: values other properties need to hold for this property to be valid
|
||||||
- `duplicates`: makes the property act as an array
|
- `array`: makes the property act as an array
|
||||||
|
|
||||||
for more information, see the wiki!
|
for more information, see the wiki!
|
||||||
|
|
||||||
|
|
|
||||||
91
server/Cargo.lock
generated
91
server/Cargo.lock
generated
|
|
@ -2,18 +2,78 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.12.0"
|
version = "2.12.0"
|
||||||
|
|
@ -30,6 +90,12 @@ version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.178"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.6"
|
version = "2.7.6"
|
||||||
|
|
@ -112,6 +178,17 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.110"
|
version = "2.0.110"
|
||||||
|
|
@ -162,18 +239,32 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
|
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgu"
|
name = "wgu"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"hex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ version = "0.0.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hex = "0.4.3"
|
||||||
serde = { version = "*", features = ["derive"] }
|
serde = { version = "*", features = ["derive"] }
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
|
sha2 = "0.10.9"
|
||||||
toml = "0.9.8"
|
toml = "0.9.8"
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,83 @@
|
||||||
pub mod modules;
|
pub mod modules;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
use crate::modules::{ModuleItem, item_registry};
|
|
||||||
use crate::types::{ObjectInstance, ObjectTemplate};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::modules::{ModuleItem, FunctionItem, item_registry};
|
||||||
|
use crate::types::{FunctionTemplate, FunctionTemplateObject, ObjectInstance, ObjectTemplate};
|
||||||
|
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
use sha2::{Sha256, Digest};
|
||||||
|
use hex;
|
||||||
|
|
||||||
|
impl ObjectTemplate {
|
||||||
|
fn from_object_type(object_type: &str) -> Result<ObjectTemplate, String> {
|
||||||
|
let modules = item_registry();
|
||||||
|
|
||||||
|
let template: ObjectTemplate = match modules.get(object_type) {
|
||||||
|
Some(ModuleItem::Template(template_str)) => toml::from_str(template_str).unwrap(),
|
||||||
|
Some(_) => panic!("{} is not a ModuleItem::Template", object_type),
|
||||||
|
None => return Err(format!("ModuleItem {} doesn't exist", object_type))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(template)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ObjectInstance {
|
impl ObjectInstance {
|
||||||
|
pub fn from_object_type(object_type: &str, input: Value) -> Result<Self, String> {
|
||||||
|
let mut instance = ObjectInstance {
|
||||||
|
object_type: object_type.to_string(),
|
||||||
|
input: json!(input),
|
||||||
|
..ObjectInstance::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/26593387/how-can-i-get-the-current-time-in-milliseconds
|
||||||
|
instance.created = format!("{:?}", SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("time should go forward")
|
||||||
|
.as_millis());
|
||||||
|
|
||||||
|
instance.edited = format!("{:?}", SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("time should go forward")
|
||||||
|
.as_millis());
|
||||||
|
|
||||||
|
instance.hashed = format!("{:?}", SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("time should go forward")
|
||||||
|
.as_millis());
|
||||||
|
|
||||||
|
let input_sha256_bytes = Sha256::digest(
|
||||||
|
format!("{}+{}",
|
||||||
|
instance.object_type,
|
||||||
|
json!(instance.input)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
instance.input_sha256 = hex::encode(input_sha256_bytes);
|
||||||
|
|
||||||
|
let full_sha256_bytes = Sha256::digest(
|
||||||
|
format!("{}+{}+{}+{}+{}",
|
||||||
|
instance.object_type,
|
||||||
|
instance.hashed,
|
||||||
|
json!(instance.input),
|
||||||
|
json!(instance.local),
|
||||||
|
json!(instance.remote)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
instance.full_sha256 = hex::encode(full_sha256_bytes);
|
||||||
|
|
||||||
|
ObjectInstance::validate(&instance)?;
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
||||||
let modules = item_registry();
|
let modules = item_registry();
|
||||||
let object_type = &obj.object_type;
|
let object_type = &obj.object_type;
|
||||||
|
let template = ObjectTemplate::from_object_type(object_type)?;
|
||||||
let template: ObjectTemplate = match modules.get(object_type.as_str()) {
|
|
||||||
Some(ModuleItem::Template(template_str)) => toml::from_str(template_str).unwrap(),
|
|
||||||
Some(_) => panic!("{} is not a ModuleItem::Template", object_type),
|
|
||||||
None => return Err(format!("template {} doesn't exist", object_type))
|
|
||||||
};
|
|
||||||
|
|
||||||
match modules.get(format!("{}:func:validator", object_type).as_str()) {
|
match modules.get(format!("{}:func:validator", object_type).as_str()) {
|
||||||
Some(ModuleItem::Validator(validate)) => validate(&obj)?,
|
Some(ModuleItem::Validator(validate)) => validate(&obj)?,
|
||||||
|
|
@ -24,7 +87,7 @@ impl ObjectInstance {
|
||||||
|
|
||||||
for (name, property) in template.input {
|
for (name, property) in template.input {
|
||||||
for transform in property.transforms {
|
for transform in property.transforms {
|
||||||
let destination = transform.split(":").collect::<Vec<&str>>();
|
let destination: Vec<&str> = transform.splitn(2, ":").collect();
|
||||||
|
|
||||||
let temp_object = ObjectInstance {
|
let temp_object = ObjectInstance {
|
||||||
object_type: destination[0].to_string(),
|
object_type: destination[0].to_string(),
|
||||||
|
|
@ -45,14 +108,115 @@ impl ObjectInstance {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_template(object_type: &str, input: Value) -> Result<Self, String> {
|
pub fn run_transform(
|
||||||
let instance = ObjectInstance {
|
obj: &ObjectInstance,
|
||||||
object_type: object_type.to_string(),
|
source: &str,
|
||||||
input: json!(input),
|
destination: &str
|
||||||
..ObjectInstance::default()
|
)
|
||||||
|
-> Result<Self, String>
|
||||||
|
{
|
||||||
|
let object_type = &obj.object_type;
|
||||||
|
let template = ObjectTemplate::from_object_type(object_type)?;
|
||||||
|
|
||||||
|
// assuming that the property to transform (source) is 'input.some.thing.nya',
|
||||||
|
// source_parts[0] is the category (input)
|
||||||
|
// source_parts[1] is the name (some.thing.nya)
|
||||||
|
let source_parts: Vec<&str> = source.splitn(2, ".").collect();
|
||||||
|
|
||||||
|
// assuming that the transform destination is 'meta/text:value',
|
||||||
|
// destination_parts[0] is the object type (meta/text)
|
||||||
|
// destination_parts[1] is the property under `input` (value)
|
||||||
|
let destination_parts: Vec<&str> = destination.splitn(2, ":").collect();
|
||||||
|
|
||||||
|
let source_instance_category = match source_parts[0] {
|
||||||
|
"input" => &obj.input,
|
||||||
|
"local" => &obj.local,
|
||||||
|
"remote" => &obj.remote,
|
||||||
|
_ => return Err(format!("the category specified in the transformation source ({}) is invalid (must be input OR local OR remote)", source_parts[0]))
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectInstance::validate(&instance)?;
|
let source_template_category = match source_parts[0] {
|
||||||
Ok(instance)
|
"input" => template.input,
|
||||||
|
"local" => template.local,
|
||||||
|
"remote" => template.remote,
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let template_property = match source_template_category.get(source_parts[1]) {
|
||||||
|
Some(template_property) => template_property,
|
||||||
|
None => return Err(format!("the property specified as the transformation source ({}) doesn't exist in the template", source))
|
||||||
|
};
|
||||||
|
|
||||||
|
if template_property.transforms.contains(&destination.to_string()) {
|
||||||
|
let result = ObjectInstance::from_object_type(destination_parts[0], json!({
|
||||||
|
destination_parts[1]: source_instance_category.get(source_parts[1])
|
||||||
|
}))?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
Err(format!("invalid destination {}", destination))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_function(
|
||||||
|
function: &str,
|
||||||
|
inputs: FunctionItem,
|
||||||
|
params: Option<FunctionItem>
|
||||||
|
)
|
||||||
|
-> Result<FunctionItem, String>
|
||||||
|
{
|
||||||
|
let modules = item_registry();
|
||||||
|
|
||||||
|
// same thing as in ObjectTemplate::from_object_type
|
||||||
|
let (template, function): (FunctionTemplate, _) = match modules.get(function) {
|
||||||
|
Some(ModuleItem::Function((template_str, function))) => (toml::from_str(template_str).unwrap(), function),
|
||||||
|
Some(_) => return Err(format!("the ModuleItem `{}` is not a ModuleItem::Function", function)),
|
||||||
|
None => return Err(format!("the ModuleItem `{}` doesn't exist", function))
|
||||||
|
};
|
||||||
|
|
||||||
|
validate_function_data(&inputs, &template.inputs, "input")?;
|
||||||
|
|
||||||
|
if let Some(params) = ¶ms {
|
||||||
|
validate_function_data(params, &template.params, "parameter")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = function(inputs.clone(), params.clone())?;
|
||||||
|
validate_function_data(&result, &template.outputs, "output")?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
|
||||||
|
fn validate_function_data(data: &FunctionItem, template: &HashMap<String, FunctionTemplateObject>, category: &str) -> Result<(), String> {
|
||||||
|
for (name, template_object) in template {
|
||||||
|
if let None = data.get(name) && template_object.required {
|
||||||
|
return Err(format!("required {} {} doesn't exist", category, name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, instances) in data {
|
||||||
|
let template_object = match template.get(name) {
|
||||||
|
Some(template_object) => template_object,
|
||||||
|
None => return Err(format!("{} {} doesn't exist in the template", "input", name))
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_count = &template_object.count;
|
||||||
|
let expected_object_type = &template_object.object_type;
|
||||||
|
|
||||||
|
if instances.len() != *expected_count {
|
||||||
|
return Err(format!("the amount of object instances in the {} {} ({}) doesn't match the expected amount ({})", category, name, instances.len(), expected_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
for instance in instances {
|
||||||
|
if instance.object_type != *expected_object_type {
|
||||||
|
return Err(format!("the object type of one or more object instances in the {} {} ({}) doesn't match the expected type ({})", category, name, instance.object_type, expected_object_type))
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectInstance::validate(&instance)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,33 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use wgu::types::ObjectInstance;
|
use wgu::types::ObjectInstance;
|
||||||
use wgu::modules::{ModuleItem, item_registry};
|
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<(), String> {
|
||||||
let modules = item_registry();
|
|
||||||
|
|
||||||
// change these!
|
// change these!
|
||||||
|
// 1 | creating a new object instance
|
||||||
let object_type = "meta/number";
|
let object_type = "meta/number";
|
||||||
let input = json!({
|
let input = json!({
|
||||||
"value": 1312
|
"value": 1312
|
||||||
});
|
});
|
||||||
let function = "local";
|
|
||||||
|
|
||||||
// this creates a new object instance
|
let some_object = ObjectInstance::from_object_type(object_type, input)?;
|
||||||
let some_object = ObjectInstance::from_template(object_type, input)?;
|
|
||||||
|
|
||||||
println!("this is an object:");
|
println!("this is an object:");
|
||||||
println!("{:?}", some_object);
|
println!("{:#?}", some_object);
|
||||||
println!("");
|
println!("");
|
||||||
|
|
||||||
// this runs a function on it to calculate other properties
|
// 2 | running a function on it
|
||||||
let some_object_with_data = match modules.get(format!("{}:func:{}", object_type, function).as_str()) {
|
let function = "meta/number:func:local";
|
||||||
Some(ModuleItem::Calculator(calc)) => calc(&some_object)?,
|
let mut function_input = HashMap::new();
|
||||||
Some(_) => return Err(format!("if you're trying to run a ModuleItem::Function and not a ModuleItem::Calculator, you'll have to add the match arm for that")),
|
function_input.insert(format!("main"), vec![some_object.clone()]);
|
||||||
None => {
|
|
||||||
return Err(format!("the ModuleItem `{}:func:{}` doesn't exist. this is not necessarily bad in this example (if you changed `object_type`)", object_type, function));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("this is the same object with data:");
|
println!("running function {}", function);
|
||||||
println!("{:?}", some_object_with_data);
|
println!("input: {:#?}", function_input);
|
||||||
|
|
||||||
|
let some_object_with_data = ObjectInstance::run_function(function, function_input, None)?;
|
||||||
|
|
||||||
|
println!("output: {:#?}", some_object_with_data);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,15 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
pub mod meta;
|
pub mod meta;
|
||||||
|
|
||||||
|
pub type FunctionItem = HashMap<String, Vec<ObjectInstance>>;
|
||||||
|
|
||||||
pub enum ModuleItem {
|
pub enum ModuleItem {
|
||||||
Template(&'static str),
|
Template(&'static str),
|
||||||
Validator(fn(&ObjectInstance) -> Result<(), String>),
|
Validator(fn(&ObjectInstance) -> Result<(), String>),
|
||||||
Calculator(fn(&ObjectInstance) -> Result<ObjectInstance, String>),
|
Function((
|
||||||
Function(fn(
|
&'static str, // template
|
||||||
inputs: HashMap<&str, &ObjectInstance>,
|
fn(inputs: FunctionItem, params: Option<FunctionItem>) -> Result<FunctionItem, String>
|
||||||
params: Option<HashMap<&str, &ObjectInstance>>
|
))
|
||||||
) -> Result<HashMap<String, ObjectInstance>, String>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item_registry() -> HashMap<&'static str, ModuleItem> {
|
pub fn item_registry() -> HashMap<&'static str, ModuleItem> {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ mod dummy;
|
||||||
mod text;
|
mod text;
|
||||||
mod number;
|
mod number;
|
||||||
mod bool;
|
mod bool;
|
||||||
|
mod connection;
|
||||||
|
|
||||||
pub fn registry() -> HashMap<&'static str, ModuleItem> {
|
pub fn registry() -> HashMap<&'static str, ModuleItem> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
@ -13,15 +14,18 @@ pub fn registry() -> HashMap<&'static str, ModuleItem> {
|
||||||
// meta/text
|
// meta/text
|
||||||
map.insert("meta/text", ModuleItem::Template(text::TEMPLATE));
|
map.insert("meta/text", ModuleItem::Template(text::TEMPLATE));
|
||||||
map.insert("meta/text:func:validator", ModuleItem::Validator(text::validate));
|
map.insert("meta/text:func:validator", ModuleItem::Validator(text::validate));
|
||||||
map.insert("meta/text:func:local", ModuleItem::Calculator(text::local));
|
map.insert("meta/text:func:local", ModuleItem::Function((text::TEMPLATE_LOCAL, text::local)));
|
||||||
|
|
||||||
// meta/number
|
// meta/number
|
||||||
map.insert("meta/number", ModuleItem::Template(number::TEMPLATE));
|
map.insert("meta/number", ModuleItem::Template(number::TEMPLATE));
|
||||||
map.insert("meta/number:func:validator", ModuleItem::Validator(number::validate));
|
map.insert("meta/number:func:validator", ModuleItem::Validator(number::validate));
|
||||||
map.insert("meta/number:func:local", ModuleItem::Calculator(number::local));
|
map.insert("meta/number:func:local", ModuleItem::Function((number::TEMPLATE_LOCAL, number::local)));
|
||||||
|
|
||||||
// meta/bool
|
// meta/bool
|
||||||
map.insert("meta/bool", ModuleItem::Template(bool::TEMPLATE));
|
map.insert("meta/bool", ModuleItem::Template(bool::TEMPLATE));
|
||||||
map.insert("meta/bool:func:validator", ModuleItem::Validator(bool::validate));
|
map.insert("meta/bool:func:validator", ModuleItem::Validator(bool::validate));
|
||||||
|
|
||||||
|
// meta/connection
|
||||||
|
map.insert("meta/connection", ModuleItem::Template(connection::TEMPLATE));
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ pub const TEMPLATE: &str = r#"
|
||||||
transforms = []
|
transforms = []
|
||||||
subobjects = []
|
subobjects = []
|
||||||
conditions = []
|
conditions = []
|
||||||
duplicates = false
|
array = false
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
||||||
|
|
|
||||||
41
server/src/modules/meta/connection.rs
Normal file
41
server/src/modules/meta/connection.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
pub const TEMPLATE: &str = r#"
|
||||||
|
[input.variant]
|
||||||
|
transforms = ["meta/text:value"]
|
||||||
|
subobjects = []
|
||||||
|
conditions = [
|
||||||
|
["input.variant", "function"]
|
||||||
|
["input.variant", "transform"]
|
||||||
|
["input.variant", "subobject"]
|
||||||
|
["input.variant", "custom"]
|
||||||
|
]
|
||||||
|
array = false
|
||||||
|
|
||||||
|
[input.from]
|
||||||
|
transforms = ["meta/text:value"]
|
||||||
|
subobjects = []
|
||||||
|
conditions = []
|
||||||
|
array = true
|
||||||
|
|
||||||
|
[input.to]
|
||||||
|
transforms = ["meta/text:value"]
|
||||||
|
subobjects = []
|
||||||
|
conditions = []
|
||||||
|
array = true
|
||||||
|
|
||||||
|
[input.property]
|
||||||
|
transforms = ["meta/text:value"]
|
||||||
|
subobjects = []
|
||||||
|
conditions = [
|
||||||
|
["input.variant", "transform"]
|
||||||
|
["input.variant", "subobject"]
|
||||||
|
]
|
||||||
|
array = false
|
||||||
|
|
||||||
|
[input.value]
|
||||||
|
transforms = ["meta/text:value"]
|
||||||
|
subobjects = []
|
||||||
|
conditions = [
|
||||||
|
["input.variant", "custom"]
|
||||||
|
]
|
||||||
|
array = false
|
||||||
|
"#;
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub const TEMPLATE: &str = r#"[input.value]
|
pub const TEMPLATE: &str = r#"
|
||||||
|
[input.value]
|
||||||
transforms = ["meta/text:value"]
|
transforms = ["meta/text:value"]
|
||||||
subobjects = []
|
subobjects = []
|
||||||
conditions = []
|
conditions = []
|
||||||
duplicates = false
|
array = false
|
||||||
"#;
|
"#;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,32 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use crate::ObjectInstance;
|
|
||||||
|
use crate::{modules::FunctionItem, types::ObjectInstance};
|
||||||
|
|
||||||
pub const TEMPLATE: &str = r#"
|
pub const TEMPLATE: &str = r#"
|
||||||
[input.value]
|
[input.value]
|
||||||
transforms = []
|
transforms = []
|
||||||
subobjects = []
|
subobjects = []
|
||||||
conditions = []
|
conditions = []
|
||||||
duplicates = false
|
array = false
|
||||||
|
|
||||||
[local.length]
|
[local.length]
|
||||||
transforms = ["meta/number:value"]
|
transforms = ["meta/number:value"]
|
||||||
subobjects = []
|
subobjects = []
|
||||||
conditions = []
|
conditions = []
|
||||||
duplicates = false
|
array = false
|
||||||
|
"#;
|
||||||
|
|
||||||
|
pub const TEMPLATE_LOCAL: &str = r#"
|
||||||
|
[inputs.main]
|
||||||
|
required = true
|
||||||
|
object_type = "meta/number"
|
||||||
|
count = 1
|
||||||
|
|
||||||
|
[outputs.main]
|
||||||
|
required = true
|
||||||
|
object_type = "meta/number"
|
||||||
|
count = 1
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
||||||
|
|
@ -25,18 +39,28 @@ pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local(obj: &ObjectInstance) -> Result<ObjectInstance, String> {
|
pub fn local(
|
||||||
let _value = obj.input.get("value")
|
inputs: FunctionItem,
|
||||||
.ok_or("input.value must exist")?;
|
_params: Option<FunctionItem>
|
||||||
|
)
|
||||||
|
-> Result<FunctionItem, String>
|
||||||
|
{
|
||||||
|
let Some(main) = inputs.get("main")
|
||||||
|
else { unreachable!() };
|
||||||
|
|
||||||
let value = _value.as_number()
|
let main_obj = &main[0];
|
||||||
.ok_or("input.value must be a number")?;
|
|
||||||
|
|
||||||
let mut new = obj.clone();
|
let Some(value) = &main_obj.input.get("value")
|
||||||
new.local = json!({
|
else { unreachable!() };
|
||||||
|
|
||||||
|
let mut result_obj = ObjectInstance::from_object_type("meta/number", main_obj.input.clone())?;
|
||||||
|
|
||||||
|
result_obj.local = json!({
|
||||||
"length": value.to_string().len()
|
"length": value.to_string().len()
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(new)
|
let mut result = HashMap::new();
|
||||||
}
|
result.insert(format!("main"), vec![result_obj]);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,33 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use crate::ObjectInstance;
|
|
||||||
|
use crate::{modules::FunctionItem, types::ObjectInstance};
|
||||||
|
|
||||||
pub const TEMPLATE: &str = r#"
|
pub const TEMPLATE: &str = r#"
|
||||||
[input.value]
|
[input.value]
|
||||||
transforms = []
|
transforms = []
|
||||||
subobjects = []
|
subobjects = []
|
||||||
conditions = []
|
conditions = []
|
||||||
duplicates = false
|
array = false
|
||||||
|
|
||||||
[local.length]
|
[local.length]
|
||||||
transforms = ["meta/number:value"]
|
transforms = ["meta/number:value"]
|
||||||
subobjects = []
|
subobjects = []
|
||||||
conditions = []
|
conditions = []
|
||||||
duplicates = false
|
array = false
|
||||||
|
"#;
|
||||||
|
|
||||||
|
|
||||||
|
pub const TEMPLATE_LOCAL: &str = r#"
|
||||||
|
[inputs.main]
|
||||||
|
required = true
|
||||||
|
object_type = "meta/text"
|
||||||
|
count = 1
|
||||||
|
|
||||||
|
[outputs.main]
|
||||||
|
required = true
|
||||||
|
object_type = "meta/text"
|
||||||
|
count = 1
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
||||||
|
|
@ -25,17 +40,28 @@ pub fn validate(obj: &ObjectInstance) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local(obj: &ObjectInstance) -> Result<ObjectInstance, String> {
|
pub fn local(
|
||||||
let value = obj.input.get("value")
|
inputs: FunctionItem,
|
||||||
.ok_or("input.value must exist")?;
|
_params: Option<FunctionItem>
|
||||||
|
)
|
||||||
|
-> Result<FunctionItem, String>
|
||||||
|
{
|
||||||
|
let Some(main) = inputs.get("main")
|
||||||
|
else { unreachable!() };
|
||||||
|
|
||||||
let value = value.as_str()
|
let main_obj = &main[0];
|
||||||
.ok_or("input.value must be a string")?;
|
|
||||||
|
|
||||||
let mut new = obj.clone();
|
let Some(value) = &main_obj.input.get("value")
|
||||||
new.local = json!({
|
else { unreachable!() };
|
||||||
"length": value.len()
|
|
||||||
|
let mut result_obj = ObjectInstance::from_object_type("meta/text", main_obj.input.clone())?;
|
||||||
|
|
||||||
|
result_obj.local = json!({
|
||||||
|
"length": value.to_string().len()
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(new)
|
let mut result = HashMap::new();
|
||||||
|
result.insert(format!("main"), vec![result_obj]);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||||
pub struct ObjectInstance {
|
pub struct ObjectInstance {
|
||||||
pub variant: u32,
|
pub version: usize,
|
||||||
pub plotted: bool,
|
pub plotted: bool,
|
||||||
pub created: String,
|
pub created: String,
|
||||||
pub edited: String,
|
pub edited: String,
|
||||||
|
|
@ -24,24 +24,39 @@ pub struct Log {
|
||||||
level: String,
|
level: String,
|
||||||
variant: String,
|
variant: String,
|
||||||
timestamp: String,
|
timestamp: String,
|
||||||
message: String,
|
message: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Default)]
|
#[derive(Deserialize, Debug, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct ObjectTemplate {
|
pub struct ObjectTemplate {
|
||||||
pub input: HashMap<String, TemplateProperty>,
|
pub input: HashMap<String, ObjectTemplateProperty>,
|
||||||
pub local: HashMap<String, TemplateProperty>,
|
pub local: HashMap<String, ObjectTemplateProperty>,
|
||||||
pub remote: HashMap<String, TemplateProperty>,
|
pub remote: HashMap<String, ObjectTemplateProperty>
|
||||||
}
|
}
|
||||||
|
|
||||||
// part of ObjectTemplate
|
// part of ObjectTemplate
|
||||||
#[derive(Deserialize, Debug, Default)]
|
#[derive(Deserialize, Debug, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct TemplateProperty {
|
pub struct ObjectTemplateProperty {
|
||||||
pub transforms: Vec<String>,
|
pub transforms: Vec<String>,
|
||||||
pub subobjects: Vec<String>,
|
pub subobjects: Vec<String>,
|
||||||
pub conditions: Vec<[String; 2]>,
|
pub conditions: Vec<[String; 2]>,
|
||||||
pub duplicates: bool
|
pub array: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct FunctionTemplate {
|
||||||
|
pub inputs: HashMap<String, FunctionTemplateObject>,
|
||||||
|
pub params: HashMap<String, FunctionTemplateObject>,
|
||||||
|
pub outputs: HashMap<String, FunctionTemplateObject>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct FunctionTemplateObject {
|
||||||
|
pub required: bool,
|
||||||
|
pub object_type: String,
|
||||||
|
pub count: usize
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue