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.
(&self, name: &str, args: &[Value], context: &Context)
| 263 | /// |
| 264 | /// This function will return an error if the function fails to execute. |
| 265 | pub fn invoke(&self, name: &str, args: &[Value], context: &Context) -> Result<Value, DscError> { |
| 266 | let Some(function) = self.functions.get(name) else { |
| 267 | // if function name contains a period, it might be a user function |
| 268 | if name.contains('.') { |
| 269 | return invoke_user_function(name, args, context); |
| 270 | } |
| 271 | return Err(DscError::Parser(t!("functions.unknownFunction", name = name).to_string())); |
| 272 | }; |
| 273 | |
| 274 | let metadata = function.get_metadata(); |
| 275 | |
| 276 | // check if arg number are valid |
| 277 | let min_args = metadata.min_args; |
| 278 | let max_args = metadata.max_args; |
| 279 | if args.len() < min_args || args.len() > max_args { |
| 280 | if max_args == 0 { |
| 281 | return Err(DscError::Parser(t!("functions.noArgsAccepted", name = name).to_string())); |
| 282 | } |
| 283 | else if min_args == max_args { |
| 284 | return Err(DscError::Parser(t!("functions.invalidArgCount", name = name, count = min_args).to_string())); |
| 285 | } |
| 286 | else if max_args == usize::MAX { |
| 287 | return Err(DscError::Parser(t!("functions.minArgsRequired", name = name, count = min_args).to_string())); |
| 288 | } |
| 289 | |
| 290 | return Err(DscError::Parser(t!("functions.argCountRequired", name = name, min = min_args, max = max_args).to_string())); |
| 291 | } |
| 292 | |
| 293 | for (index, value) in args.iter().enumerate() { |
| 294 | if index >= metadata.accepted_arg_ordered_types.len() { |
| 295 | break; |
| 296 | } |
| 297 | |
| 298 | Self::check_arg_against_expected_types(name, value, &metadata.accepted_arg_ordered_types[index])?; |
| 299 | } |
| 300 | |
| 301 | // if we have remaining args, they must match one of the remaining_arg_types |
| 302 | if let Some(ref remaining_arg_types) = metadata.remaining_arg_accepted_types { |
| 303 | for value in args.iter().skip(metadata.accepted_arg_ordered_types.len()) { |
| 304 | Self::check_arg_against_expected_types(name, value, remaining_arg_types)?; |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | let accepts_lambda = metadata.accepted_arg_ordered_types.iter().any(|types| types.contains(&FunctionArgKind::Lambda)) |
| 309 | || metadata.remaining_arg_accepted_types.as_ref().is_some_and(|types| types.contains(&FunctionArgKind::Lambda)); |
| 310 | |
| 311 | if accepts_lambda { |
| 312 | let mut lambda_context = context.clone(); |
| 313 | lambda_context.process_mode = ProcessMode::Lambda; |
| 314 | function.invoke(args, &lambda_context) |
| 315 | } else { |
| 316 | function.invoke(args, context) |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | fn check_arg_against_expected_types(name: &str, arg: &Value, expected_types: &[FunctionArgKind]) -> Result<(), DscError> { |
| 321 | let is_lambda = arg.as_str().is_some_and(|s| s.starts_with("__lambda_")); |
no test coverage detected