Skip to content

Commit

Permalink
fix clippy
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveL-MSFT committed Oct 20, 2023
1 parent 570ea40 commit d16b48b
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 57 deletions.
4 changes: 2 additions & 2 deletions dsc/src/resource_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub fn export(dsc: &mut DscManager, resource: &str, format: &Option<OutputFormat
let mut conf = Configuration::new();

match add_resource_export_results_to_configuration(&dsc_resource, &mut conf) {
Ok(_) => (),
Ok(()) => (),
Err(err) => {
error!("Error: {err}");
exit(EXIT_DSC_ERROR);
Expand Down Expand Up @@ -191,7 +191,7 @@ pub fn get_resource(dsc: &mut DscManager, resource: &str) -> DscResource {
}

match dsc.initialize_discovery() {
Ok(_) => (),
Ok(()) => (),
Err(err) => {
error!("Error: {err}");
exit(EXIT_DSC_ERROR);
Expand Down
4 changes: 2 additions & 2 deletions dsc/src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ pub fn validate_config(config: &str) {
};
let properties = resource_block["properties"].clone();
let _result: Result<(), ValidationError> = match compiled_schema.validate(&properties) {
Ok(_) => Ok(()),
Ok(()) => Ok(()),
Err(err) => {
let mut error = String::new();
for e in err {
Expand Down Expand Up @@ -304,7 +304,7 @@ pub fn resource(subcommand: &ResourceSubCommand, format: &Option<OutputFormat>,
match subcommand {
ResourceSubCommand::List { resource_name, description, tags } => {
match dsc.initialize_discovery() {
Ok(_) => (),
Ok(()) => (),
Err(err) => {
error!("Error: {err}");
exit(EXIT_DSC_ERROR);
Expand Down
2 changes: 1 addition & 1 deletion dsc_lib/src/dscresources/command_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ fn verify_json(resource: &ResourceManifest, cwd: &str, json: &str) -> Result<(),
};
let json: Value = serde_json::from_str(json)?;
let result = match compiled_schema.validate(&json) {
Ok(_) => Ok(()),
Ok(()) => Ok(()),
Err(err) => {
let mut error = String::new();
for e in err {
Expand Down
17 changes: 7 additions & 10 deletions dsc_lib/src/functions/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,35 @@ impl Function for Base64 {
1
}

fn invoke(&self, args: &Vec<FunctionArg>) -> Result<FunctionResult, DscError> {
let arg = match args.get(0).unwrap() {
FunctionArg::String(value) => value,
_ => {
return Err(DscError::Parser("Invalid argument type".to_string()));
}
fn invoke(&self, args: &[FunctionArg]) -> Result<FunctionResult, DscError> {
let FunctionArg::String(arg) = args.get(0).unwrap() else {
return Err(DscError::Parser("Invalid argument type".to_string()));
};
Ok(FunctionResult::String(general_purpose::STANDARD.encode(arg)))
}
}

#[cfg(test)]
mod tests {
use crate::parser::StatementParser;
use crate::parser::Statement;

#[test]
fn strings() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[base64('hello world')]").unwrap();
assert_eq!(result, "aGVsbG8gd29ybGQ=");
}

#[test]
fn numbers() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[base64(123)]");
assert!(result.is_err());
}

#[test]
fn nested() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[base64(base64('hello world'))]").unwrap();
assert_eq!(result, "YUdWc2JHOGdkMjl5YkdRPQ==");
}
Expand Down
16 changes: 8 additions & 8 deletions dsc_lib/src/functions/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Function for Concat {
vec![AcceptedArgKind::String, AcceptedArgKind::Integer]
}

fn invoke(&self, args: &Vec<FunctionArg>) -> Result<FunctionResult, DscError> {
fn invoke(&self, args: &[FunctionArg]) -> Result<FunctionResult, DscError> {
let mut result = String::new();
for arg in args {
match arg {
Expand All @@ -41,46 +41,46 @@ impl Function for Concat {

#[cfg(test)]
mod tests {
use crate::parser::StatementParser;
use crate::parser::Statement;

#[test]
fn strings() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[concat('a', 'b')]").unwrap();
assert_eq!(result, "ab");
}

#[test]
fn strings_with_spaces() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[concat('a ', ' ', ' b')]").unwrap();
assert_eq!(result, "a b");
}

#[test]
fn numbers() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[concat(1, 2)]").unwrap();
assert_eq!(result, "12");
}

#[test]
fn string_and_numbers() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[concat('a', 1, 'b', 2)]").unwrap();
assert_eq!(result, "a1b2");
}

#[test]
fn nested() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[concat('a', concat('b', 'c'), 'd')]").unwrap();
assert_eq!(result, "abcd");
}

#[test]
fn invalid_one_parameter() {
let mut parser = StatementParser::new().unwrap();
let mut parser = Statement::new().unwrap();
let result = parser.parse_and_execute("[concat('a')]");
assert!(result.is_err());
}
Expand Down
47 changes: 40 additions & 7 deletions dsc_lib/src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,42 @@ use tracing::debug;
pub mod base64;
pub mod concat;

/// The kind of argument that a function accepts.
#[derive(Debug, PartialEq)]
pub enum AcceptedArgKind {
String,
Integer,
Boolean,
}

/// A function that can be invoked.
pub trait Function {
/// The minimum number of arguments that the function accepts.
fn min_args(&self) -> usize;
/// The maximum number of arguments that the function accepts.
fn max_args(&self) -> usize;
/// The types of arguments that the function accepts.
fn accepted_arg_types(&self) -> Vec<AcceptedArgKind>;
fn invoke(&self, args: &Vec<FunctionArg>) -> Result<FunctionResult, DscError>;
/// Invoke the function.
///
/// # Arguments
///
/// * `args` - The arguments to the function.
///
/// # Errors
///
/// This function will return an error if the function fails to execute.
fn invoke(&self, args: &[FunctionArg]) -> Result<FunctionResult, DscError>;
}

/// A dispatcher for functions.
pub struct FunctionDispatcher {
functions: HashMap<String, Box<dyn Function>>,
}

impl FunctionDispatcher {
/// Create a new `FunctionDispatcher` instance.
#[must_use]
pub fn new() -> Self {
let mut functions: HashMap<String, Box<dyn Function>> = HashMap::new();
functions.insert("base64".to_string(), Box::new(base64::Base64{}));
Expand All @@ -37,33 +54,43 @@ impl FunctionDispatcher {
}
}

/// Invoke a function.
///
/// # Arguments
///
/// * `name` - The name of the function to invoke.
/// * `args` - The arguments to the function.
///
/// # Errors
///
/// This function will return an error if the function fails to execute.
pub fn invoke(&self, name: &str, args: &Vec<FunctionArg>) -> Result<FunctionResult, DscError> {
let function = self.functions.get(name);
match function {
Some(function) => {
// check if arg number are valid
if args.len() < function.min_args() {
return Err(DscError::Parser(format!("Function {0} requires at least {1} arguments", name, function.min_args())));
return Err(DscError::Parser(format!("Function '{name}' requires at least {0} arguments", function.min_args())));
}
if args.len() > function.max_args() {
return Err(DscError::Parser(format!("Function {0} requires at most {1} arguments", name, function.max_args())));
return Err(DscError::Parser(format!("Function '{name}' requires at most {0} arguments", function.max_args())));
}
// check if arg types are valid
for arg in args {
match arg {
FunctionArg::String(_) => {
if !function.accepted_arg_types().contains(&AcceptedArgKind::String) {
return Err(DscError::Parser(format!("Function {0} does not accept string arguments", name)));
return Err(DscError::Parser(format!("Function '{name}' does not accept string arguments")));
}
},
FunctionArg::Integer(_) => {
if !function.accepted_arg_types().contains(&AcceptedArgKind::Integer) {
return Err(DscError::Parser(format!("Function {0} does not accept integer arguments", name)));
return Err(DscError::Parser(format!("Function '{name}' does not accept integer arguments")));
}
},
FunctionArg::Boolean(_) => {
if !function.accepted_arg_types().contains(&AcceptedArgKind::Boolean) {
return Err(DscError::Parser(format!("Function {0} does not accept boolean arguments", name)));
return Err(DscError::Parser(format!("Function '{name}' does not accept boolean arguments")));
}
},
FunctionArg::Expression(_) => {
Expand All @@ -76,7 +103,13 @@ impl FunctionDispatcher {

function.invoke(args)
},
None => Err(DscError::Parser(format!("Unknown function {0}", name))),
None => Err(DscError::Parser(format!("Unknown function '{name}'"))),
}
}
}

impl Default for FunctionDispatcher {
fn default() -> Self {
Self::new()
}
}
18 changes: 17 additions & 1 deletion dsc_lib/src/parser/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ pub struct Expression<'a> {
}

impl<'a> Expression<'a> {
/// Create a new `Expression` instance.
///
/// # Arguments
///
/// * `function_dispatcher` - The function dispatcher to use.
/// * `statement` - The statement that the expression is part of.
/// * `expression` - The expression node.
///
/// # Errors
///
/// This function will return an error if the expression node is not valid.
pub fn new(function_dispatcher: &'a FunctionDispatcher, statement: &str, expression: &Node) -> Result<Self, DscError> {
let Some(function) = expression.child_by_field_name("function") else {
return Err(DscError::Parser("Function node not found".to_string()));
Expand Down Expand Up @@ -42,6 +53,11 @@ impl<'a> Expression<'a> {
})
}

/// Invoke the expression.
///
/// # Errors
///
/// This function will return an error if the expression fails to execute.
pub fn invoke(&self) -> Result<String, DscError> {
let result = self.function.invoke()?;
if let Some(member_access) = &self.member_access {
Expand All @@ -52,7 +68,7 @@ impl<'a> Expression<'a> {
FunctionResult::Object(object) => {
let mut value = object;
if !value.is_object() {
return Err(DscError::Parser(format!("Member access on non-object value {0}", value.to_string())));
return Err(DscError::Parser(format!("Member access on non-object value '{value}'")));
}
for member in member_access {
value = value[member].clone();
Expand Down
30 changes: 20 additions & 10 deletions dsc_lib/src/parser/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ pub enum FunctionResult {
}

impl<'a> Function<'a> {
/// Create a new `Function` instance.
///
/// # Arguments
///
/// * `function_dispatcher` - The function dispatcher to use.
/// * `statement` - The statement that the function is part of.
/// * `function` - The function node.
///
/// # Errors
///
/// This function will return an error if the function node is not valid.
pub fn new(function_dispatcher: &'a FunctionDispatcher, statement: &str, function: &Node) -> Result<Self, DscError> {
let Some(function_name) = function.child_by_field_name("name") else {
return Err(DscError::Parser("Function name node not found".to_string()));
Expand All @@ -44,30 +55,29 @@ impl<'a> Function<'a> {
args})
}

/// Invoke the function.
///
/// # Errors
///
/// This function will return an error if the function fails to execute.
pub fn invoke(&self) -> Result<FunctionResult, DscError> {
// if any args are expressions, we need to invoke those first
let mut resolved_args: Option<Vec<FunctionArg>> = None;
let mut resolved_args: Vec<FunctionArg> = vec![];
if let Some(args) = &self.args {
resolved_args = Some(vec![]);
for arg in args {
match arg {
FunctionArg::Expression(expression) => {
let value = expression.invoke()?;
resolved_args.as_mut().unwrap().push(FunctionArg::String(value));
resolved_args.push(FunctionArg::String(value));
},
_ => {
resolved_args.as_mut().unwrap().push(arg.clone());
resolved_args.push(arg.clone());
}
}
}
}

let args = match resolved_args {
Some(args) => args,
None => vec![],
};

self.function_dispatcher.invoke(&self.name, &args)
self.function_dispatcher.invoke(&self.name, &resolved_args)
}
}

Expand Down
Loading

0 comments on commit d16b48b

Please sign in to comment.