Skip to content

Commit

Permalink
chore: start with working options
Browse files Browse the repository at this point in the history
  • Loading branch information
raklaptudirm committed Apr 26, 2024
1 parent 7109ec7 commit 69d2900
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 19 deletions.
20 changes: 13 additions & 7 deletions uai/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use super::{Command, FlagValues, RunError, RunErrorType};
/// Commands sent from the GUI are automatically parsed and executed according
/// to the Command schema provided by the user to the Client.
pub struct Client<T: Send, E: RunError> {
context: inbuilt::Context,
initial_context: inbuilt::Context,
commands: HashMap<String, Command<T, E>>,
}

Expand All @@ -41,7 +41,7 @@ impl<T: Send + 'static, E: RunError + 'static> Client<T, E> {

// Make the context thread safe to allow commands to run in parallel.
let context = Arc::new(Mutex::new(context));
let our_ctx = Arc::new(Mutex::new(self.context.clone()));
let our_ctx = Arc::new(Mutex::new(self.initial_context.clone()));

// Iterate over the lines in the input, since Commands for the GUI are
// separated by newlines and we want to parse each Command separately.
Expand Down Expand Up @@ -139,7 +139,8 @@ impl<T: Send + 'static, E: RunError + 'static> Client<T, E> {
}

// Parsing complete, run the Command and handle any errors.
cmd.run(context, flags).map_err(|e| e.into())
cmd.run(context, flags, self.initial_context.option_values.clone())
.map_err(|e| e.into())
}
}

Expand All @@ -155,7 +156,7 @@ impl<T: Send, E: RunError> Client<T, E> {
#[rustfmt::skip]
pub fn new() -> Self {
Client::<T, E> {
context: Default::default(),
initial_context: Default::default(),
commands: HashMap::new(),
}
}
Expand All @@ -178,17 +179,22 @@ impl<T: Send, E: RunError> Client<T, E> {
}

pub fn option(mut self, name: &str, option: Parameter) -> Self {
self.context.options.insert(name.to_string(), option);
self.initial_context
.options
.insert(name.to_string(), option.clone());
self.initial_context
.option_values
.insert_default(name.to_string(), &option);
self
}

pub fn engine(mut self, name: &str) -> Self {
self.context.engine = name.to_owned();
self.initial_context.engine = name.to_owned();
self
}

pub fn author(mut self, name: &str) -> Self {
self.context.author = name.to_owned();
self.initial_context.author = name.to_owned();
self
}
}
11 changes: 8 additions & 3 deletions uai/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::fmt;
use std::sync::{Arc, Mutex};
use std::thread;

use crate::Context;
use crate::{Context, ParameterValues};

use super::{Flag, FlagValues};

Expand All @@ -38,9 +38,14 @@ impl<T: Send + 'static, E: RunError + 'static> Command<T, E> {
/// run runs the current Command with the given context and flag values.
/// A new thread is spawned and detached to run parallel Commands. It returns
/// the error returned by the Command's execution, or [`Ok`] for parallel.
pub fn run(&self, context: &Arc<Mutex<T>>, flags: FlagValues) -> Result<(), E> {
pub fn run(
&self,
context: &Arc<Mutex<T>>,
flags: FlagValues,
options: ParameterValues,
) -> Result<(), E> {
// Clone values which might be moved by spawning a new thread.
let context = Context::new(context, flags);
let context = Context::new(context, flags, options);
let func = self.run_fn;

if self.parallel {
Expand Down
23 changes: 20 additions & 3 deletions uai/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use std::sync::{Arc, Mutex, MutexGuard};

use crate::FlagValues;
use crate::{FlagValues, Number, ParameterValues};

pub struct Context<T: Send> {
context: Arc<Mutex<T>>,
flags: FlagValues,
options: ParameterValues,
}

impl<T: Send> Context<T> {
pub fn new(context: &Arc<Mutex<T>>, flags: FlagValues) -> Context<T> {
pub fn new(context: &Arc<Mutex<T>>, flags: FlagValues, options: ParameterValues) -> Context<T> {
let context = Arc::clone(context);
Context { context, flags }
Context {
context,
flags,
options,
}
}

pub fn lock(&self) -> MutexGuard<'_, T> {
Expand All @@ -28,4 +33,16 @@ impl<T: Send> Context<T> {
pub fn get_array_flag(&self, name: &str) -> Option<Vec<String>> {
self.flags.get_array(name)
}

pub fn get_check_option(&self, name: &str) -> Option<bool> {
self.options.get_check(name)
}

pub fn get_string_option(&self, name: &str) -> Option<String> {
self.options.get_string(name)
}

pub fn get_spin_option(&self, name: &str) -> Option<Number> {
self.options.get_spin(name)
}
}
74 changes: 69 additions & 5 deletions uai/src/inbuilt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,82 @@

use std::collections::HashMap;

use crate::{quit, Parameter, RunErrorType};
use crate::{error, quit, Flag, Parameter, ParameterValues, RunErrorType};
use lazy_static::lazy_static;

pub type Command = crate::Command<Context, RunErrorType>;

lazy_static! {
pub static ref COMMANDS: HashMap<String, Command> = HashMap::from(
[
("quit", Command::new(|_ctx, _flags| quit!())),
("quit", Command::new(|_ctx| quit!())),
(
"isready",
Command::new(|_ctx, _flags| {
Command::new(|_ctx| {
println!("readyok");
Ok(())
})
),
(
"uai",
Command::new(|ctx, _flags| {
let ctx = ctx.lock().unwrap();
Command::new(|ctx| {
let ctx = ctx.lock();

println!("id name {}", ctx.engine);
println!("id author {}", ctx.author);
println!();
if !ctx.options.is_empty() {
for (name, option) in ctx.options.clone() {
println!("option name {} type {}", name, option);
}

println!();
}
println!("uaiok");

Ok(())
})
),
(
"setoption",
Command::new(|ctx| {
let name = ctx.get_single_flag("name");
let value = ctx.get_array_flag("value");

if name.is_none() || value.is_none() {
return error!("expected \"name\" and \"value\" flags");
}

let name = name.unwrap();
let value = value.unwrap().join(" ");

let mut ctx = ctx.lock();

ctx.setoption(&name, &value).map_err(RunErrorType::Error)
})
.flag("name", Flag::Single)
.flag("value", Flag::Variadic)
),
(
"options",
Command::new(|ctx| {
let ctx = ctx.lock();

for (name, option) in ctx.options.clone() {
print!("option name {} value ", name);
match option {
Parameter::Check(_) => {
println!("{}", ctx.option_values.get_check(&name).unwrap())
}
Parameter::String(_) | Parameter::Combo(_, _) => {
println!("{}", ctx.option_values.get_string(&name).unwrap())
}
Parameter::Spin(_, _, _) => {
println!("{}", ctx.option_values.get_spin(&name).unwrap())
}
}
}

Ok(())
})
)
Expand All @@ -56,6 +106,19 @@ pub struct Context {
pub author: String,

pub options: HashMap<String, Parameter>,
pub option_values: ParameterValues,
}

impl Context {
fn setoption(&mut self, name: &str, value: &str) -> Result<(), String> {
let option = self.options.get(name);
if option.is_none() {
return Err(format!("unknown option \"{}\"", name));
}

self.option_values
.insert(name.to_owned(), option.unwrap(), value)
}
}

impl Default for Context {
Expand All @@ -64,6 +127,7 @@ impl Default for Context {
engine: "Nameless v0.0.0".to_string(),
author: "Anonymous".to_string(),
options: HashMap::new(),
option_values: Default::default(),
}
}
}
119 changes: 118 additions & 1 deletion uai/src/parameter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use std::collections::HashMap;
use std::fmt;

pub type Number = i32;

#[derive(Clone)]
pub enum Parameter {
/// Check represents a checkbox parameter which can be true or false.
Expand All @@ -16,7 +21,7 @@ pub enum Parameter {
/// value, and the third argument is the maximum value of this parameter. The
/// minimum and maximum bounds are inclusive and and the default must be in
/// the range defined by them.
Spin(i32, i32, i32),
Spin(Number, Number, Number),

/// Combo represents a combo box which can have the value of one of the
/// predefined strings.
Expand All @@ -25,3 +30,115 @@ pub enum Parameter {
/// list of predefined strings. The default value must be included in the list.
Combo(String, Vec<String>),
}

#[derive(Clone, Default)]
pub struct ParameterValues {
checks: HashMap<String, bool>,
strings: HashMap<String, String>,
numbers: HashMap<String, Number>,
}

impl ParameterValues {
pub fn get_check(&self, name: &str) -> Option<bool> {
self.checks.get(name).copied()
}

pub fn get_string(&self, name: &str) -> Option<String> {
self.strings.get(name).cloned()
}

pub fn get_spin(&self, name: &str) -> Option<Number> {
self.numbers.get(name).copied()
}
}

impl ParameterValues {
pub fn insert(
&mut self,
name: String,
option: &Parameter,
value_str: &str,
) -> Result<(), String> {
match option {
Parameter::Check(_) => {
let value = value_str.parse();
if value.is_err() {
return Err(format!(
"option {}: expected boolean, received {}",
name, value_str
));
}
self.checks.insert(name, value.unwrap());
}
Parameter::String(_) => {
self.strings.insert(name, value_str.to_owned());
}
Parameter::Spin(_, min, max) => {
let value = value_str.parse();
if value.is_err() {
return Err(format!(
"option {}: expected a number, received {}",
name, value_str
));
}

let value = value.unwrap();
if value < *min || value > *max {
return Err(format!(
"option {}: expected a number between {} and {} (inclusive), received {}",
name, min, max, value_str
));
}
self.numbers.insert(name, value);
}
Parameter::Combo(_, strings) => {
let value = value_str.to_owned();
if strings.contains(&value) {
return Err(format!(
"option {}: {} is not one of the combo strings",
name, value
));
}
self.strings.insert(name, value);
}
};

Ok(())
}

pub fn insert_default(&mut self, name: String, option: &Parameter) {
match option {
Parameter::Check(default) => {
self.checks.insert(name, *default);
}
Parameter::String(default) => {
self.strings.insert(name, default.clone());
}
Parameter::Spin(default, _, _) => {
self.numbers.insert(name, *default);
}
Parameter::Combo(default, _) => {
self.strings.insert(name, default.clone());
}
};
}
}

impl fmt::Display for Parameter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Parameter::Check(default) => write!(f, "check default {}", default),
Parameter::String(default) => write!(f, "string default {}", default),
Parameter::Spin(default, min, max) => {
write!(f, "spin default {} min {} max {}", default, min, max)
}
Parameter::Combo(default, combos) => {
write!(f, "combo default {}", default)?;
for combo in combos {
write!(f, " var {}", combo)?
}
Ok(())
}
}
}
}

0 comments on commit 69d2900

Please sign in to comment.