Skip to content

Commit 6049a84

Browse files
committed
idol: Add encoding for generic byte array parameters (#432)
This commit adds an additional encoding for command line arguments that represent array parameters to idol operations. This encoding is useful as it allows us to pass arbitrary byte arrays. To use this form the first and last characters must be an opening and closing suqare braces respectively. The substrings representing array elements between the square braces are separated by spaces: e.g. `--arguments array=[37 1 255 127]` The existing encoding is preserved.
1 parent 3629bfd commit 6049a84

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

humility-idol/src/lib.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,43 @@ fn lookup<'a>(
285285
}
286286
}
287287

288+
/// Convert array from hiffy `--argument` list string to a vector of bytes.
289+
///
290+
/// The humility hiffy cmd accepts multiple encodings of array arguments:
291+
/// - When passed a string of characters like `--arguments array=5432` the
292+
/// string is passed to the operation 'as_bytes'. An idol op that takes a
293+
/// 4 byte array will receive [ 53, 52, 51, 50 ] given the argument string
294+
/// above. This is intended as a mechanism for passing ASCII characters to a
295+
/// task.
296+
/// - To pass an array that's interpreted as the decimal representation of
297+
/// bytes instead of ASCII, provide the array as a string enclosed in square
298+
/// brackets with each array element separated by a space. The argument string
299+
/// `--argument array=[37 1 255 127]` will result in the task receiving the
300+
/// byte array `[ 37, 1, 255, 127 ]`.
301+
fn bytes_from_str(value: &str) -> Result<Vec<u8>> {
302+
if value.starts_with('[') && value.ends_with(']') {
303+
// use double ended iterator to drop first and last chars
304+
let mut chars = value.chars();
305+
chars.next();
306+
chars.next_back();
307+
let value = chars.as_str();
308+
309+
let mut bytes: Vec<u8> = Vec::new();
310+
for element in value.split(' ') {
311+
let element = element.trim();
312+
let byte: u8 = element.parse().context(format!(
313+
"cannot parse \"{}\" as u8 (is it base 10?)",
314+
element
315+
))?;
316+
bytes.push(byte);
317+
}
318+
319+
Ok(bytes)
320+
} else {
321+
Ok(Vec::from(value.as_bytes()))
322+
}
323+
}
324+
288325
//
289326
// Store a call argument to the specified payload
290327
//
@@ -398,14 +435,15 @@ fn call_arg(
398435
}
399436
match value {
400437
IdolArgument::String(value) => {
401-
if value.len() != count {
438+
let bytes = bytes_from_str(value)?;
439+
if bytes.len() != count {
402440
bail!(
403441
"Cannot convert '{value}' to [u8; {count}]; \
404442
wrong length"
405443
);
406444
}
407445
let dest = &mut buf[member.offset..member.offset + count];
408-
dest.copy_from_slice(value.as_bytes());
446+
dest.copy_from_slice(&bytes);
409447
}
410448
IdolArgument::Scalar(v) => {
411449
bail!("Cannot convert scalar {v} to [u8; {count}]")

0 commit comments

Comments
 (0)