new-home-application 1.0.2

New Home iot application framework. Meant to build application for the New Home Core
Documentation
//! This module contains all required structs to implement a method
//!
//! It is recommended to implement methods with the derive macro, provided by the
//! new_home_application_macro crate. For more documentation on how to use the macro, see the docs
//! of this crate.
//!

use std::collections::HashMap;
use std::error::Error;
use std::fmt::{Debug, Display};
use std::{fmt, io};

use serde::export::Formatter;
use serde_json::Value;

use crate::communication::{MethodCall, MethodResult};
use std::any::Any;

pub type Result<T> = std::result::Result<T, MethodError>;

/// This struct represents a generic error used in methods.
///
/// This error may also be used throughout the whole application.
pub struct MethodError {
    display: String,
    debug: String,
}

impl MethodError {
    pub fn message(message: impl ToString) -> Self {
        Self {
            display: message.to_string(),
            debug: message.to_string(),
        }
    }
}

impl From<io::Error> for MethodError {
    fn from(error: io::Error) -> Self {
        Self {
            display: format!("{}", &error),
            debug: format!("{:?}", &error),
        }
    }
}

impl From<Box<dyn Any + Send + 'static>> for MethodError {
    fn from(error: Box<dyn Any + Send + 'static>) -> Self {
        Self {
            display: format!("{:?}", &error),
            debug: format!("{:?}", &error),
        }
    }
}

impl From<serde_json::Error> for MethodError {
    fn from(error: serde_json::Error) -> Self {
        Self {
            display: format!("{}", &error),
            debug: format!("{:?}", &error),
        }
    }
}

impl Error for MethodError {}

impl Display for MethodError {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
        formatter.write_str(self.display.as_str())
    }
}

impl Debug for MethodError {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
        formatter.write_str(self.debug.as_str())
    }
}

/// This trait is used for providing basic information about a method struct
/// This can be derived using the derive macro from the new_home_application_macro crate.
pub trait Method {
    /// This method provides a name for the method. It is used to identify the method when its called
    ///
    /// When using the derive macro the value returned here is a snake_case version of the struct name.
    fn name(&self) -> String;

    /// Returns a couple words as a description for the method. For more detailed "helpful" info use
    /// the help method.
    ///
    /// When derived, this field will be filled from the `#description` attribute
    fn description(&self) -> String;

    /// This provides a more detailed overview up to a help for what the method does, and when it does
    /// things.
    ///
    /// When derived, this field will be filled from the `#help` attribute
    fn help(&self) -> String;

    /// This method is used to fill the method's arguments fields.
    /// These fields can even be a map stored on the method struct.
    ///
    /// When used with the derive macro this method is generated automatically and will fill fields
    /// on the struct itself when they are marked as `#argument`. For more detailed view, look into
    /// the macro crate.
    ///
    /// # Errors
    ///
    /// An error can be thrown when, for example, an argument is missing in the map or has the wrong
    /// type. The error has to contain a helpful message which can be send back to the user.
    ///
    /// When derived an error will occur when an argument is missing. The message will contain which
    /// field is missing.
    fn set_arguments(&mut self, arguments: HashMap<String, Value>) -> Result<()>;
}

/// Methods are defined by this trait.
/// A method struct has to first implement the informational [Method] trait and then it can implement
/// this struct for executing stuff actually.
///
/// This trait cannot be derived by any macro.
pub trait MethodCallable: Method {
    /// This method gets called when the method is called. It gets a context which contains (again)
    /// all the arguments and the name of the method.
    ///
    /// # Return
    ///
    /// The response has to have a response code and (optionally) a response value which is represented
    /// as a [serde_json::Value]. This value has to contain
    fn call(&mut self, context: MethodCall) -> MethodResult;
}