1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#![deny(missing_docs)]

//! The data structures representing a XIO instruction set.

#[macro_use]
extern crate serde_derive;

extern crate indexmap;
extern crate ommui_file_loading;
extern crate ommui_string_patterns;
extern crate serde;
extern crate xio_base_datatypes;

use indexmap::IndexMap;
use ommui_string_patterns::{
    freetextstring, idstring, idstring_maybe_empty,
};
use xio_base_datatypes as base;

mod hexnumber;

/// Functionality for loading a XIO instruction set from files.
pub mod filesystem;

/// A map containing instructions indexed by their identifier.
pub type InstructionMap = IndexMap<String, Instruction>;

/// Description of an instruction type.
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Instruction {
    /// The instruction code.
    #[serde(with = "hexnumber")]
    pub code: u16,

    /// The description of the instruction.
    #[serde(with = "freetextstring")]
    pub description: String,

    /// The format string in Qt format syntax.
    ///
    /// The Qt string formatting replaces %1, %2, …, %99 in the provided
    /// order. See http://doc.qt.io/qt-5/qstring.html#arg
    #[serde(
        with = "freetextstring",
        default,
        skip_serializing_if = "String::is_empty"
    )]
    pub formatstring: String,

    /// The parameters which are required for the instruction.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub parameters: Vec<InstructionParameter>,
}

/// Instruction categories.
pub enum InstructionCategory {
    /// Commands without a time extent (e.g. setValue).
    CommandWithoutTimeExtent,

    /// Commands with time extent (e.g. wait);
    CommandWithTimeExtent,

    /// Conditions for commands with time extent.
    Condition,

    /// Invalid category.
    Invalid,
}

impl Instruction {
    /// Get the category of an instruction.
    pub fn category(&self) -> InstructionCategory {
        use std::ops::Shr;
        use InstructionCategory::*;
        match self.code.shr(8) & 0b1111u16 {
            0b0000u16 => CommandWithoutTimeExtent,
            0b0100u16 => CommandWithTimeExtent,
            0b1000u16 => Condition,
            _ => Invalid,
        }
    }
}

/// Description of an instruction parameter type.
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct InstructionParameter {
    /// The id string of the parameter.
    #[serde(with = "idstring")]
    pub id: String,

    /// The group to which the parameter belongs.
    ///
    /// If empty, the parameter implicitly has it's own group where
    /// it is the only member.
    #[serde(
        with = "idstring_maybe_empty",
        default,
        skip_serializing_if = "String::is_empty"
    )]
    pub group: String,

    /// The allowed types of parameters.
    ///
    /// Each parameter in a group must have the same type.
    #[serde(rename = "type")]
    pub parameter_type: Vec<base::DataType>,

    /// The permitted storage type for the parameter.
    pub storage: base::StorageTypeWithMixed,

    /// A human-readable description of the parameter.
    #[serde(with = "freetextstring")]
    pub description: String,
}