Skip to content

Commit 2cea11d

Browse files
authored
Merge pull request #360 from tgauth/add-mod-function
Add mod function
2 parents 9667b23 + 166d645 commit 2cea11d

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

dsc_lib/src/functions/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod concat;
1313
pub mod create_array;
1414
pub mod div;
1515
pub mod envvar;
16+
pub mod mod_function;
1617
pub mod mul;
1718
pub mod parameters;
1819
pub mod resource_id;
@@ -64,6 +65,7 @@ impl FunctionDispatcher {
6465
functions.insert("createArray".to_string(), Box::new(create_array::CreateArray{}));
6566
functions.insert("div".to_string(), Box::new(div::Div{}));
6667
functions.insert("envvar".to_string(), Box::new(envvar::Envvar{}));
68+
functions.insert("mod".to_string(), Box::new(mod_function::Mod{}));
6769
functions.insert("mul".to_string(), Box::new(mul::Mul{}));
6870
functions.insert("parameters".to_string(), Box::new(parameters::Parameters{}));
6971
functions.insert("resourceId".to_string(), Box::new(resource_id::ResourceId{}));

dsc_lib/src/functions/mod_function.rs

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use crate::DscError;
5+
use crate::configure::context::Context;
6+
use crate::functions::{AcceptedArgKind, Function};
7+
use serde_json::Value;
8+
use tracing::debug;
9+
10+
#[derive(Debug, Default)]
11+
pub struct Mod {}
12+
13+
impl Function for Mod {
14+
fn min_args(&self) -> usize {
15+
2
16+
}
17+
18+
fn max_args(&self) -> usize {
19+
2
20+
}
21+
22+
fn accepted_arg_types(&self) -> Vec<AcceptedArgKind> {
23+
vec![AcceptedArgKind::Number]
24+
}
25+
26+
fn invoke(&self, args: &[Value], _context: &Context) -> Result<Value, DscError> {
27+
debug!("mod function");
28+
if let (Some(arg1), Some(arg2)) = (args[0].as_i64(), args[1].as_i64()) {
29+
if arg2 == 0 {
30+
return Err(DscError::Parser("Cannot divide by zero".to_string()));
31+
}
32+
Ok(Value::Number((arg1 % arg2).into()))
33+
} else {
34+
Err(DscError::Parser("Invalid argument(s)".to_string()))
35+
}
36+
}
37+
}
38+
39+
#[cfg(test)]
40+
mod tests {
41+
use crate::configure::context::Context;
42+
use crate::parser::Statement;
43+
44+
#[test]
45+
fn numbers() {
46+
let mut parser = Statement::new().unwrap();
47+
let result = parser.parse_and_execute("[mod(7, 3)]", &Context::new()).unwrap();
48+
assert_eq!(result, 1);
49+
}
50+
51+
#[test]
52+
fn nested() {
53+
let mut parser = Statement::new().unwrap();
54+
let result = parser.parse_and_execute("[mod(18, mod(8, 3))]", &Context::new()).unwrap();
55+
assert_eq!(result, 0);
56+
}
57+
58+
#[test]
59+
fn invalid_one_parameter() {
60+
let mut parser = Statement::new().unwrap();
61+
let result = parser.parse_and_execute("[mod(5)]", &Context::new());
62+
assert!(result.is_err());
63+
}
64+
65+
#[test]
66+
fn invalid_div_by_zero() {
67+
let mut parser = Statement::new().unwrap();
68+
let result = parser.parse_and_execute("[mod(5, 0)]", &Context::new());
69+
assert!(result.is_err());
70+
}
71+
72+
#[test]
73+
fn overflow_input() {
74+
let mut parser = Statement::new().unwrap();
75+
// max value for i64 is 2^63 -1 (or 9,223,372,036,854,775,807)
76+
let result = parser.parse_and_execute("[mod(9223372036854775808, 2)]", &Context::new());
77+
assert!(result.is_err());
78+
}
79+
}

0 commit comments

Comments
 (0)