From 6dca69a650ae33f6c3134abb76154591d9ae9234 Mon Sep 17 00:00:00 2001 From: sagie gur ari Date: Wed, 6 May 2020 07:42:26 +0000 Subject: [PATCH] Multiple new set commands. --- CHANGELOG.md | 6 + docs/sdk.md | 215 +++++++++++++++++- .../src/sdk/std/collections/map_put/mod.rs | 2 +- duckscript_sdk/src/sdk/std/collections/mod.rs | 12 + .../src/sdk/std/collections/set_clear/help.md | 32 +++ .../src/sdk/std/collections/set_clear/mod.rs | 73 ++++++ .../sdk/std/collections/set_clear/mod_test.rs | 41 ++++ .../sdk/std/collections/set_contains/help.md | 21 ++ .../sdk/std/collections/set_contains/mod.rs | 74 ++++++ .../std/collections/set_contains/mod_test.rs | 48 ++++ .../sdk/std/collections/set_is_empty/help.md | 21 ++ .../sdk/std/collections/set_is_empty/mod.rs | 22 ++ .../std/collections/set_is_empty/mod_test.rs | 7 + .../std/collections/set_is_empty/script.ds | 3 + .../src/sdk/std/collections/set_put/help.md | 22 ++ .../src/sdk/std/collections/set_put/mod.rs | 75 ++++++ .../sdk/std/collections/set_put/mod_test.rs | 63 +++++ .../sdk/std/collections/set_remove/help.md | 28 +++ .../src/sdk/std/collections/set_remove/mod.rs | 75 ++++++ .../std/collections/set_remove/mod_test.rs | 51 +++++ .../src/sdk/std/collections/set_size/help.md | 28 +++ .../src/sdk/std/collections/set_size/mod.rs | 72 ++++++ .../sdk/std/collections/set_size/mod_test.rs | 35 +++ duckscript_sdk/src/utils/state.rs | 72 +++++- test/std/collections/set_clear_test.ds | 27 +++ test/std/collections/set_is_empty_test.ds | 35 +++ test/std/collections/set_put_test.ds | 20 ++ test/std/collections/set_remove_test.ds | 29 +++ test/std/collections/set_size_test.ds | 43 ++++ 29 files changed, 1248 insertions(+), 4 deletions(-) create mode 100644 duckscript_sdk/src/sdk/std/collections/set_clear/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/set_clear/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_clear/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_contains/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/set_contains/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_contains/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_is_empty/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/set_is_empty/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_is_empty/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_is_empty/script.ds create mode 100644 duckscript_sdk/src/sdk/std/collections/set_put/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/set_put/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_put/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_remove/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/set_remove/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_remove/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_size/help.md create mode 100755 duckscript_sdk/src/sdk/std/collections/set_size/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/collections/set_size/mod_test.rs create mode 100644 test/std/collections/set_clear_test.ds create mode 100644 test/std/collections/set_is_empty_test.ds create mode 100644 test/std/collections/set_put_test.ds create mode 100644 test/std/collections/set_remove_test.ds create mode 100644 test/std/collections/set_size_test.ds diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d87fff..a593eaa 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ### v0.3.4 +* New set_contains command. +* New set_remove command. +* New set_size command. +* New set_is_empty command. +* New set_put command. +* New set_clear command. * Add array_size alias to array_length command. * New array_remove command. * New set_new command. diff --git a/docs/sdk.md b/docs/sdk.md index bfbff38..768c134 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -29,13 +29,19 @@ * [std::collections::MapIsEmpty (map_is_empty)](#std__collections__MapIsEmpty) * [std::collections::MapKeys (map_keys)](#std__collections__MapKeys) * [std::collections::MapLoadProperties (map_load_properties)](#std__collections__MapLoadProperties) -* [std::collections::MapPut (map_put)](#std__collections__MapPut) +* [std::collections::MapPut (map_put, map_add)](#std__collections__MapPut) * [std::collections::MapRemove (map_remove)](#std__collections__MapRemove) * [std::collections::MapSize (map_size)](#std__collections__MapSize) * [std::collections::MapToProperties (map_to_properties)](#std__collections__MapToProperties) * [std::collections::Range (range)](#std__collections__Range) * [std::collections::ReadProperties (read_properties)](#std__collections__ReadProperties) * [std::collections::Set (set_new)](#std__collections__Set) +* [std::collections::SetClear (set_clear)](#std__collections__SetClear) +* [std::collections::SetContains (set_contains)](#std__collections__SetContains) +* [std::collections::SetIsEmpty (set_is_empty)](#std__collections__SetIsEmpty) +* [std::collections::SetPut (set_put, set_add)](#std__collections__SetPut) +* [std::collections::SetRemove (set_remove)](#std__collections__SetRemove) +* [std::collections::SetSize (set_size)](#std__collections__SetSize) * [std::collections::WriteProperties (write_properties)](#std__collections__WriteProperties) * [std::debug::DuckscriptSDKVersion (duckscript_sdk_version)](#std__debug__DuckscriptSDKVersion) * [std::debug::DuckscriptVersion (duckscript_version)](#std__debug__DuckscriptVersion) @@ -1340,7 +1346,7 @@ release ${handle} #### Aliases: -map_put +map_put, map_add ## std::collections::MapRemove @@ -1548,6 +1554,211 @@ release ${handle} #### Aliases: set_new + +## std::collections::SetClear +```sh +result = set_clear handle +``` + +Clears the provided set. + +#### Parameters + +The set handle. + +#### Return Value + +True if successful. + +#### Examples + +```sh +handle = set + +result = set_put ${handle} 1 + +result = set_is_empty ${handle} +assert_false ${result} + +result set_clear ${handle} +assert ${result} + +result = set_is_empty ${handle} +assert ${result} + +release ${handle} +``` + + +#### Aliases: +set_clear + + +## std::collections::SetContains +```sh +var = set_contains handle value +``` + +Returns true if the set contains the provided value. + +#### Parameters + +* The set handle. +* The value + +#### Return Value + +True if the value was found in the set. + +#### Examples + +```sh +handle = set_new value1 value2 value3 +found = set_contains ${handle} value2 +``` + + +#### Aliases: +set_contains + + +## std::collections::SetIsEmpty + +```sh +var = set_is_empty handle +``` + +Returns true if the provided set handle is an empty set. + +#### Parameters + +The set handle. + +#### Return Value + +True if the provided handle belongs to an empty set. + +#### Examples + +```sh +handle = set +set_put ${handle} value +empty = set_is_empty ${handle} +``` + + +#### Source: + +```sh + +scope::set_is_empty::length = set_size ${scope::set_is_empty::argument::1} +equals 0 ${scope::set_is_empty::length} + +``` + + +#### Aliases: +set_is_empty + + +## std::collections::SetPut +```sh +var = set_put handle value +``` + +Pushes an additional value to an existing set. + +#### Parameters + +The set handle. + +#### Return Value + +True if a new value was pushed. + +#### Examples + +```sh +handle = set_new 1 2 3 +set_put ${handle} 4 +size = set_size ${handle} +assert_eq ${size} 4 +``` + + +#### Aliases: +set_put, set_add + + +## std::collections::SetRemove +```sh +removed = set_remove handle value +``` + +Removes a the value from the set and returns true/false if it was removed. + +#### Parameters + +* The set handle. +* The value to remove. + +#### Return Value + +True if the value was found and removed from the set. + +#### Examples + +```sh +handle = set_new + +result = set_put ${handle} value +assert_eq ${result} true + +removed = set_remove ${handle} value +assert ${removed} + +release ${handle} +``` + + +#### Aliases: +set_remove + + +## std::collections::SetSize +```sh +var = set_size handle +``` + +Returns the set size based on the provided set handle. + +#### Parameters + +The set handle. + +#### Return Value + +The set size. + +#### Examples + +```sh +handle = set + +result = set_put ${handle} 1 +result = set_put ${handle} 2 +result = set_put ${handle} 3 + +result = set_size ${handle} +assert_eq ${result} 3 + +release ${handle} +``` + + +#### Aliases: +set_size + ## std::collections::WriteProperties ```sh diff --git a/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs b/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs index 9b323d9..538cb2c 100755 --- a/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs +++ b/duckscript_sdk/src/sdk/std/collections/map_put/mod.rs @@ -20,7 +20,7 @@ impl Command for CommandImpl { } fn aliases(&self) -> Vec { - vec!["map_put".to_string()] + vec!["map_put".to_string(), "map_add".to_string()] } fn help(&self) -> String { diff --git a/duckscript_sdk/src/sdk/std/collections/mod.rs b/duckscript_sdk/src/sdk/std/collections/mod.rs index e5a9e09..233bb2f 100755 --- a/duckscript_sdk/src/sdk/std/collections/mod.rs +++ b/duckscript_sdk/src/sdk/std/collections/mod.rs @@ -28,6 +28,12 @@ mod map_to_properties; mod range; mod read_properties; mod set; +mod set_clear; +mod set_contains; +mod set_is_empty; +mod set_put; +mod set_remove; +mod set_size; mod write_properties; use crate::utils::pckg; @@ -69,6 +75,12 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr commands.set(range::create(&package))?; commands.set(read_properties::create(&package))?; commands.set(set::create(&package))?; + commands.set(set_clear::create(&package))?; + commands.set(set_contains::create(&package))?; + commands.set(set_is_empty::create(&package)?)?; + commands.set(set_put::create(&package))?; + commands.set(set_remove::create(&package))?; + commands.set(set_size::create(&package))?; commands.set(write_properties::create(&package))?; Ok(()) diff --git a/duckscript_sdk/src/sdk/std/collections/set_clear/help.md b/duckscript_sdk/src/sdk/std/collections/set_clear/help.md new file mode 100644 index 0000000..af34e8a --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_clear/help.md @@ -0,0 +1,32 @@ +```sh +result = set_clear handle +``` + +Clears the provided set. + +#### Parameters + +The set handle. + +#### Return Value + +True if successful. + +#### Examples + +```sh +handle = set + +result = set_put ${handle} 1 + +result = set_is_empty ${handle} +assert_false ${result} + +result set_clear ${handle} +assert ${result} + +result = set_is_empty ${handle} +assert ${result} + +release ${handle} +``` diff --git a/duckscript_sdk/src/sdk/std/collections/set_clear/mod.rs b/duckscript_sdk/src/sdk/std/collections/set_clear/mod.rs new file mode 100755 index 0000000..4d6130f --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_clear/mod.rs @@ -0,0 +1,73 @@ +use crate::utils::pckg; +use crate::utils::state::{get_handles_sub_state, mutate_set}; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "SetClear") + } + + fn aliases(&self) -> Vec { + vec!["set_clear".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Set handle not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = arguments[0].clone(); + + let result = mutate_set(key, state, |set| { + set.clear(); + + Ok(None) + }); + + match result { + Ok(_) => CommandResult::Continue(Some("true".to_string())), + Err(error) => CommandResult::Error(error), + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_clear/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/set_clear/mod_test.rs new file mode 100644 index 0000000..1ad38d1 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_clear/mod_test.rs @@ -0,0 +1,41 @@ +use super::*; +use crate::sdk::std::collections::{set, set_put, set_size}; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = set_clear", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error(vec![create("")], "out = set_clear bad_handle", "out"); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![ + create(""), + set::create(""), + set_size::create(""), + set_put::create(""), + ], + r#" + handle = set_new + set_put ${handle} 1 + set_put ${handle} 2 + set_put ${handle} 3 + set_put ${handle} 1 + set_clear ${handle} + out = set_size ${handle} + "#, + CommandValidation::Match("out".to_string(), "0".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_contains/help.md b/duckscript_sdk/src/sdk/std/collections/set_contains/help.md new file mode 100644 index 0000000..8968de1 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_contains/help.md @@ -0,0 +1,21 @@ +```sh +var = set_contains handle value +``` + +Returns true if the set contains the provided value. + +#### Parameters + +* The set handle. +* The value + +#### Return Value + +True if the value was found in the set. + +#### Examples + +```sh +handle = set_new value1 value2 value3 +found = set_contains ${handle} value2 +``` diff --git a/duckscript_sdk/src/sdk/std/collections/set_contains/mod.rs b/duckscript_sdk/src/sdk/std/collections/set_contains/mod.rs new file mode 100755 index 0000000..afb8c80 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_contains/mod.rs @@ -0,0 +1,74 @@ +use crate::utils::pckg; +use crate::utils::state::{get_handles_sub_state, mutate_set}; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "SetContains") + } + + fn aliases(&self) -> Vec { + vec!["set_contains".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Set handle not provided.".to_string()) + } else if arguments.len() < 2 { + CommandResult::Error("Value not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = arguments[0].clone(); + + let result = mutate_set(key, state, |set| { + let item = set.contains(&arguments[1]); + Ok(Some(item.to_string())) + }); + + match result { + Ok(value) => CommandResult::Continue(value), + Err(error) => CommandResult::Error(error), + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_contains/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/set_contains/mod_test.rs new file mode 100644 index 0000000..b6c03a3 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_contains/mod_test.rs @@ -0,0 +1,48 @@ +use super::*; +use crate::sdk::std::collections::set; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = set_contains", "out"); +} + +#[test] +fn run_missing_key() { + test::run_script_and_error(vec![create("")], "out = set_contains handle", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error(vec![create("")], "out = set_contains bad_handle key", "out"); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![create(""), set::create("")], + r#" + handle = set_new 1 2 3 + out = set_contains ${handle} 2 + "#, + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_value_not_found() { + test::run_script_and_validate( + vec![create(""), set::create("")], + r#" + handle = set_new 1 2 3 + out = set_contains ${handle} 4 + "#, + CommandValidation::Match("out".to_string(), "false".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_is_empty/help.md b/duckscript_sdk/src/sdk/std/collections/set_is_empty/help.md new file mode 100644 index 0000000..f32446b --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_is_empty/help.md @@ -0,0 +1,21 @@ +```sh +var = set_is_empty handle +``` + +Returns true if the provided set handle is an empty set. + +#### Parameters + +The set handle. + +#### Return Value + +True if the provided handle belongs to an empty set. + +#### Examples + +```sh +handle = set +set_put ${handle} value +empty = set_is_empty ${handle} +``` diff --git a/duckscript_sdk/src/sdk/std/collections/set_is_empty/mod.rs b/duckscript_sdk/src/sdk/std/collections/set_is_empty/mod.rs new file mode 100755 index 0000000..b6f2ee5 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_is_empty/mod.rs @@ -0,0 +1,22 @@ +use crate::types::command::create_alias_command; +use crate::utils::pckg; +use duckscript::types::command::Command; +use duckscript::types::error::ScriptError; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +pub(crate) fn create(package: &str) -> Result, ScriptError> { + let name = pckg::concat(package, "SetIsEmpty"); + let command = create_alias_command( + name, + vec!["set_is_empty".to_string()], + include_str!("help.md").to_string(), + "set_is_empty".to_string(), + include_str!("script.ds").to_string(), + 1, + )?; + + Ok(Box::new(command)) +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_is_empty/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/set_is_empty/mod_test.rs new file mode 100644 index 0000000..cbc4367 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_is_empty/mod_test.rs @@ -0,0 +1,7 @@ +use super::*; +use crate::test; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("").unwrap()); +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_is_empty/script.ds b/duckscript_sdk/src/sdk/std/collections/set_is_empty/script.ds new file mode 100644 index 0000000..cd45eb7 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_is_empty/script.ds @@ -0,0 +1,3 @@ + +scope::set_is_empty::length = set_size ${scope::set_is_empty::argument::1} +equals 0 ${scope::set_is_empty::length} diff --git a/duckscript_sdk/src/sdk/std/collections/set_put/help.md b/duckscript_sdk/src/sdk/std/collections/set_put/help.md new file mode 100644 index 0000000..488e353 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_put/help.md @@ -0,0 +1,22 @@ +```sh +var = set_put handle value +``` + +Pushes an additional value to an existing set. + +#### Parameters + +The set handle. + +#### Return Value + +True if a new value was pushed. + +#### Examples + +```sh +handle = set_new 1 2 3 +set_put ${handle} 4 +size = set_size ${handle} +assert_eq ${size} 4 +``` diff --git a/duckscript_sdk/src/sdk/std/collections/set_put/mod.rs b/duckscript_sdk/src/sdk/std/collections/set_put/mod.rs new file mode 100755 index 0000000..659f698 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_put/mod.rs @@ -0,0 +1,75 @@ +use crate::utils::pckg; +use crate::utils::state::{get_handles_sub_state, mutate_set}; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "SetPut") + } + + fn aliases(&self) -> Vec { + vec!["set_put".to_string(), "set_add".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Set handle not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = arguments[0].clone(); + + let result = mutate_set(key, state, |set| { + for argument in &arguments[1..] { + set.insert(argument.to_string()); + } + + Ok(None) + }); + + match result { + Ok(_) => CommandResult::Continue(Some("true".to_string())), + Err(error) => CommandResult::Error(error), + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_put/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/set_put/mod_test.rs new file mode 100644 index 0000000..3658945 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_put/mod_test.rs @@ -0,0 +1,63 @@ +use super::*; +use crate::sdk::std::collections::{set, set_size}; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = set_put", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error(vec![create("")], "out = set_put bad_handle 1", "out"); +} + +#[test] +fn run_only_set_not_found() { + test::run_script_and_error(vec![create("")], "out = set_put bad_handle", "out"); +} + +#[test] +fn run_found_no_input() { + test::run_script_and_validate( + vec![create(""), set::create(""), set_size::create("")], + r#" + handle = set_new 1 2 3 + set_put ${handle} + out = set_size ${handle} + "#, + CommandValidation::Match("out".to_string(), "3".to_string()), + ); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![create(""), set::create(""), set_size::create("")], + r#" + handle = set_new 1 2 3 + set_put ${handle} 4 + out = set_size ${handle} + "#, + CommandValidation::Match("out".to_string(), "4".to_string()), + ); +} + +#[test] +fn run_found_duplicate() { + test::run_script_and_validate( + vec![create(""), set::create(""), set_size::create("")], + r#" + handle = set_new 1 2 3 + set_put ${handle} 3 + out = set_size ${handle} + "#, + CommandValidation::Match("out".to_string(), "3".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_remove/help.md b/duckscript_sdk/src/sdk/std/collections/set_remove/help.md new file mode 100644 index 0000000..dcd7c43 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_remove/help.md @@ -0,0 +1,28 @@ +```sh +removed = set_remove handle value +``` + +Removes a the value from the set and returns true/false if it was removed. + +#### Parameters + +* The set handle. +* The value to remove. + +#### Return Value + +True if the value was found and removed from the set. + +#### Examples + +```sh +handle = set_new + +result = set_put ${handle} value +assert_eq ${result} true + +removed = set_remove ${handle} value +assert ${removed} + +release ${handle} +``` diff --git a/duckscript_sdk/src/sdk/std/collections/set_remove/mod.rs b/duckscript_sdk/src/sdk/std/collections/set_remove/mod.rs new file mode 100755 index 0000000..497c7cd --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_remove/mod.rs @@ -0,0 +1,75 @@ +use crate::utils::pckg; +use crate::utils::state::{get_handles_sub_state, mutate_set}; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "SetRemove") + } + + fn aliases(&self) -> Vec { + vec!["set_remove".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Set handle not provided.".to_string()) + } else if arguments.len() < 2 { + CommandResult::Error("Value not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = arguments[0].clone(); + + let result = mutate_set(key, state, |set| { + let item = set.remove(&arguments[1]); + + Ok(Some(item.to_string())) + }); + + match result { + Ok(value) => CommandResult::Continue(value), + Err(error) => CommandResult::Error(error), + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_remove/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/set_remove/mod_test.rs new file mode 100644 index 0000000..d4c903d --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_remove/mod_test.rs @@ -0,0 +1,51 @@ +use super::*; +use crate::sdk::std::collections::{set, set_put}; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = set_remove", "out"); +} + +#[test] +fn run_missing_key() { + test::run_script_and_error(vec![create("")], "out = set_remove handle", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error(vec![create("")], "out = set_remove bad_handle key", "out"); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![create(""), set::create(""), set_put::create("")], + r#" + handle = set_new + set_put ${handle} value + out = set_remove ${handle} value + "#, + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_twice() { + test::run_script_and_validate( + vec![create(""), set::create(""), set_put::create("")], + r#" + handle = set_new + set_put ${handle} value + out = set_remove ${handle} value + out = set_remove ${handle} value + "#, + CommandValidation::Match("out".to_string(), "false".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_size/help.md b/duckscript_sdk/src/sdk/std/collections/set_size/help.md new file mode 100644 index 0000000..b47c917 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_size/help.md @@ -0,0 +1,28 @@ +```sh +var = set_size handle +``` + +Returns the set size based on the provided set handle. + +#### Parameters + +The set handle. + +#### Return Value + +The set size. + +#### Examples + +```sh +handle = set + +result = set_put ${handle} 1 +result = set_put ${handle} 2 +result = set_put ${handle} 3 + +result = set_size ${handle} +assert_eq ${result} 3 + +release ${handle} +``` diff --git a/duckscript_sdk/src/sdk/std/collections/set_size/mod.rs b/duckscript_sdk/src/sdk/std/collections/set_size/mod.rs new file mode 100755 index 0000000..b2b5a84 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_size/mod.rs @@ -0,0 +1,72 @@ +use crate::utils::pckg; +use crate::utils::state::get_handles_sub_state; +use duckscript::types::command::{Command, CommandResult, Commands}; +use duckscript::types::instruction::Instruction; +use duckscript::types::runtime::StateValue; +use std::collections::HashMap; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "SetSize") + } + + fn aliases(&self) -> Vec { + vec!["set_size".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn requires_context(&self) -> bool { + true + } + + fn run_with_context( + &self, + arguments: Vec, + state: &mut HashMap, + _variables: &mut HashMap, + _output_variable: Option, + _instructions: &Vec, + _commands: &mut Commands, + _line: usize, + ) -> CommandResult { + if arguments.is_empty() { + CommandResult::Error("Set handle not provided.".to_string()) + } else { + let state = get_handles_sub_state(state); + + let key = &arguments[0]; + + match state.get(key) { + Some(state_value) => match state_value { + StateValue::Set(set) => CommandResult::Continue(Some(set.len().to_string())), + _ => CommandResult::Error("Invalid handle provided.".to_string()), + }, + None => { + CommandResult::Error(format!("Set for handle: {} not found.", key).to_string()) + } + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/collections/set_size/mod_test.rs b/duckscript_sdk/src/sdk/std/collections/set_size/mod_test.rs new file mode 100644 index 0000000..b9f1a6f --- /dev/null +++ b/duckscript_sdk/src/sdk/std/collections/set_size/mod_test.rs @@ -0,0 +1,35 @@ +use super::*; +use crate::sdk::std::collections::{set, set_put}; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = set_size", "out"); +} + +#[test] +fn run_not_found() { + test::run_script_and_error(vec![create("")], "out = set_size bad_handle", "out"); +} + +#[test] +fn run_found() { + test::run_script_and_validate( + vec![create(""), set::create(""), set_put::create("")], + r#" + handle = set_new + set_put ${handle} 1 + set_put ${handle} 2 + set_put ${handle} 3 + set_put ${handle} 1 + out = set_size ${handle} + "#, + CommandValidation::Match("out".to_string(), "3".to_string()), + ); +} diff --git a/duckscript_sdk/src/utils/state.rs b/duckscript_sdk/src/utils/state.rs index e8ae172..89b3ad2 100644 --- a/duckscript_sdk/src/utils/state.rs +++ b/duckscript_sdk/src/utils/state.rs @@ -2,7 +2,7 @@ use crate::utils::pckg; use duckscript::types::runtime::StateValue; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::iter; #[cfg(test)] @@ -305,3 +305,73 @@ where None => Err(format!("Handle: {} not found.", &key).to_string()), } } + +pub(crate) fn mutate_set( + key: String, + state: &mut HashMap, + mut handler: F, +) -> Result, String> +where + F: FnMut(&mut HashSet) -> Result, String>, +{ + match state.remove(&key) { + Some(state_value) => match state_value { + StateValue::Set(mut set) => { + let result = handler(&mut set); + + state.insert(key, StateValue::Set(set)); + + result + } + StateValue::Boolean(value) => { + state.insert(key, StateValue::Boolean(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::Number(value) => { + state.insert(key, StateValue::Number(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber(value) => { + state.insert(key, StateValue::UnsignedNumber(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::Number32Bit(value) => { + state.insert(key, StateValue::Number32Bit(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber32Bit(value) => { + state.insert(key, StateValue::UnsignedNumber32Bit(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::Number64Bit(value) => { + state.insert(key, StateValue::Number64Bit(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::UnsignedNumber64Bit(value) => { + state.insert(key, StateValue::UnsignedNumber64Bit(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::String(value) => { + state.insert(key, StateValue::String(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::ByteArray(value) => { + state.insert(key, StateValue::ByteArray(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::List(value) => { + state.insert(key, StateValue::List(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::SubState(value) => { + state.insert(key, StateValue::SubState(value)); + Err("Invalid handle provided.".to_string()) + } + StateValue::Any(value) => { + state.insert(key, StateValue::Any(value)); + Err("Invalid handle provided.".to_string()) + } + }, + None => Err(format!("Handle: {} not found.", &key).to_string()), + } +} diff --git a/test/std/collections/set_clear_test.ds b/test/std/collections/set_clear_test.ds new file mode 100644 index 0000000..9e49566 --- /dev/null +++ b/test/std/collections/set_clear_test.ds @@ -0,0 +1,27 @@ + +fn clear_not_empty + handle = set_new 1 2 3 + + result = set_is_empty ${handle} + assert_false ${result} + + result set_clear ${handle} + assert ${result} + + result = set_is_empty ${handle} + assert ${result} + + release ${handle} +end + +fn clear_empty + handle = set_new + + result set_clear ${handle} + assert ${result} + + result = set_is_empty ${handle} + assert ${result} + + release ${handle} +end diff --git a/test/std/collections/set_is_empty_test.ds b/test/std/collections/set_is_empty_test.ds new file mode 100644 index 0000000..4ace80f --- /dev/null +++ b/test/std/collections/set_is_empty_test.ds @@ -0,0 +1,35 @@ + +fn test_size_empty + handle = set_new + + result = set_is_empty ${handle} + assert ${result} + + release ${handle} +end + +fn test_size_emptied + handle = set_new + + result = set_put ${handle} value + assert_eq ${result} true + set_remove ${handle} value + + result = set_is_empty ${handle} + assert ${result} + release ${handle} +end + +fn test_size_not_empty + handle = set_new + + result = set_put ${handle} 1 + result = set_put ${handle} 2 + result = set_put ${handle} 3 + result = set_put ${handle} 1 + + result = set_is_empty ${handle} + assert_false ${result} + + release ${handle} +end diff --git a/test/std/collections/set_put_test.ds b/test/std/collections/set_put_test.ds new file mode 100644 index 0000000..2de9ffa --- /dev/null +++ b/test/std/collections/set_put_test.ds @@ -0,0 +1,20 @@ + +fn test_set_with_data + handle = set_new a + counter = range 1 4 + for index in ${counter} + set_put ${handle} ${index} + end + + size = set_size ${handle} + assert_eq ${size} 4 + + result = set_remove ${handle} 1 + assert ${result} + size = set_size ${handle} + assert_eq ${size} 3 + + released = release ${handle} + assert ${released} +end + diff --git a/test/std/collections/set_remove_test.ds b/test/std/collections/set_remove_test.ds new file mode 100644 index 0000000..8d56ac6 --- /dev/null +++ b/test/std/collections/set_remove_test.ds @@ -0,0 +1,29 @@ + +fn test_remove + handle = set_new + + result = set_put ${handle} value + assert_eq ${result} true + + removed = set_remove ${handle} value + assert ${removed} + + empty = set_is_empty ${handle} + assert ${empty} + + release ${handle} +end + +fn test_remove_twice + handle = set_new + + result = set_put ${handle} value + assert_eq ${result} true + + removed = set_remove ${handle} value + assert ${removed} + removed = set_remove ${handle} value + assert_false ${removed} + + release ${handle} +end diff --git a/test/std/collections/set_size_test.ds b/test/std/collections/set_size_test.ds new file mode 100644 index 0000000..7ab0dd5 --- /dev/null +++ b/test/std/collections/set_size_test.ds @@ -0,0 +1,43 @@ + +fn test_size_empty + handle = set_new + + result = set_size ${handle} + assert_eq ${result} 0 + + release ${handle} +end + +fn test_size_emptied + handle = set_new + + result = set_put ${handle} value1 + assert_eq ${result} true + set_remove ${handle} value1 + + result = set_size ${handle} + assert_eq ${result} 0 + + release ${handle} +end + +fn test_size_not_empty + handle = set_new + + result = set_put ${handle} 1 + result = set_put ${handle} 2 + result = set_put ${handle} 3 + result = set_put ${handle} 1 + + result = set_size ${handle} + assert_eq ${result} 3 + + set_clear ${handle} + result = set_size ${handle} + assert_eq ${result} 0 + + result = set_is_empty ${handle} + assert ${result} + + release ${handle} +end