new-home-application 0.1.3

New Home iot application framework. Meant to build application for the New Home Core
Documentation
use std::collections::HashMap;

use serde_json::Value;

use crate::communication::parser_error::ParserError;
use crate::method::method_structure::{MethodArgument, MethodArguments};

/// Implementation for the argument parser
/// Used to parse the argument from a given `Vec<MethodArgument>` definition
/// Outputting a `Result` which contains a `ParserError` when an error occurred
pub struct ClientArgumentParserImpl {}

/// Interface for the argument parser, used to parse and validates the received JSON arguments
/// against the applications definitions
pub trait ClientArgumentParser {
    /// Parses the arguments into a `MethodArguments` object
    /// Returns the `MethodArguments` on success which can be empty or filled with the given,
    /// required arguments
    /// Will return a `ParserError` when no arguments are given from the request, not matching the
    /// required type of object Error will only be thrown if arguments are defined by the called
    /// method
    fn parse(&self, method_arguments: Vec<MethodArgument>, arguments: &Value) -> Result<MethodArguments, ParserError>;
}

impl ClientArgumentParser for ClientArgumentParserImpl {
    fn parse(&self, method_arguments: Vec<MethodArgument>, arguments: &Value) -> Result<MethodArguments, ParserError> {
        if method_arguments.len() == 0 {
            return Ok(MethodArguments::empty());
        }

        if !arguments.is_object() {
            return Err(ParserError::new(None, String::from("Arguments has to be an object")));
        }

        self.parse_arguments_to_list(&method_arguments, &arguments)
    }
}

impl ClientArgumentParserImpl {
    fn parse_arguments_to_list(&self, method_arguments: &Vec<MethodArgument>, arguments: &Value) -> Result<MethodArguments, ParserError> {
        let mut argument_map: HashMap<String, Value> = HashMap::new();
        let arguments_object = arguments.as_object().unwrap();

        for argument in method_arguments {
            let argument_value = arguments_object.get(&argument.name);

            if argument_value.is_none() && !argument.required {
                continue;
            }

            if argument_value.is_none() {
                return Err(ParserError::new(None, String::from(format!("Argument {} is required", argument.name))));
            }

            argument_map.insert(argument.name.clone(), argument_value.unwrap().clone().take());
        }

        Ok(MethodArguments::new(argument_map))
    }
}