brane_let/common.rs
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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
// COMMON.rs
// by Lut99
//
// Created:
// 14 Feb 2022, 14:21:21
// Last edited:
// 22 May 2023, 10:23:31
// Auto updated?
// Yes
//
// Description:
//! Contains common definitions across all executions.
//
use brane_ast::DataType;
use brane_exe::FullValue;
use log::debug;
use specifications::common::Parameter;
use specifications::package::PackageKind;
use crate::errors::LetError;
/***** CONSTANTS *****/
/// The time between each heartbeat update (in ms)
///
/// Shouldn't be longer than the timeout of heartbeats defined in brane-drv (10 seconds at the time of writing), as brane-drv considers the branelet dead if it didn't send a heartbeat in that time.
pub const HEARTBEAT_DELAY: u64 = 5000;
/***** CUSTOM TYPE DEFINITIONS *****/
/// Defines a shortcut for a map with string keys
pub type Map<T> = std::collections::HashMap<String, T>;
/***** ENUMS *****/
/// Defines the different ways a package can return.
pub enum PackageReturnState {
/// The package was forcefully stopped by some external force
Stopped { signal: i32 },
/// The package failed to execute on its own
Failed { code: i32, stdout: String, stderr: String },
/// The package completed successfully
Finished { stdout: String },
}
/// Defines a slightly higher level version of the PackageReturnState.
pub enum PackageResult {
/// The package was forcefully stopped by some external force
Stopped { signal: i32 },
/// The package failed to execute on its own
Failed { code: i32, stdout: String, stderr: String },
/// The package completed successfully
Finished { result: FullValue },
}
/***** HELPER FUNCTIONS *****/
/// Returns whether this type is allowed for the package's target type.
///
/// # Arguments
/// - `got`: The type we are given to use.
/// - `expected`: The type the package expected.
///
/// # Returns
/// Returns whether they are "the same" or not.
fn assert_type(got: &DataType, expected: &DataType) -> bool {
match (got, expected) {
// Specific cases
(DataType::String, DataType::Data) => true,
(DataType::String, DataType::IntermediateResult) => true,
// Recursive cases
(DataType::Array { elem_type: got }, DataType::Array { elem_type: expected }) => assert_type(got, expected),
// General cases
(DataType::Any, _) => true,
(_, DataType::Any) => true,
(got, expected) => got == expected,
}
}
/***** INITIALIZATION *****/
/// **Edited: now returning LetErrors.**
///
/// Tries to confirm that what we're told to put in the function is the same as the function accepts.
///
/// **Arguments**
/// * `parameters`: The list of what the function accepts as parameters as returned by container.yml.
/// * `arguments`: The arguments we got to pass to the function.
/// * `function`: The name of the function we're trying to evaluate (used for debugging purposes).
/// * `package`: The name of the internal package (used for debugging purposes).
/// * `kind`: The kind of the internal package (used for debugging purposes).
///
/// **Returns**
/// Nothing if the assert went alright, but a LetError describing why it failed on an error.
pub fn assert_input(parameters: &[Parameter], arguments: &Map<FullValue>, function: &str, package: &str, kind: PackageKind) -> Result<(), LetError> {
debug!("Asserting input arguments");
// Search through all the allowed parameters
for p in parameters {
// Get the expected type, but skip mounts(?)
let expected_type = DataType::from(p.data_type.as_str());
// Check if the user specified it
let argument = match arguments.get(&p.name) {
Some(argument) => argument,
None => {
return Err(LetError::MissingInputArgument {
function: function.to_string(),
package: package.to_string(),
kind,
name: p.name.clone(),
});
},
};
// Check if the type makes sense
// Note that we make a special case for data & intermediate results, since that will be converted to a type the package is comfortable with
let actual_type = argument.data_type();
if !assert_type(&actual_type, &expected_type) {
return Err(LetError::IncompatibleTypes {
function: function.to_string(),
package: package.to_string(),
kind,
name: p.name.clone(),
expected: expected_type,
got: actual_type,
});
}
}
// It all is allowed!
Ok(())
}