use super::contract::{
ArgvSlot, CommandLineContract, CommandParameterContract, DeclaredCommandContract,
EnvBindingContract,
};
use super::template::{FillPiece, FillTemplate};
pub(crate) fn encode(bytes: &mut Vec<u8>, command: &DeclaredCommandContract) {
text(bytes, &command.name);
len(bytes, command.parameters.len());
for parameter in &command.parameters {
parameter_bytes(bytes, parameter);
}
len(bytes, command.lines.len());
for line in &command.lines {
line_bytes(bytes, line);
}
len(bytes, command.env.len());
for binding in &command.env {
env_bytes(bytes, binding);
}
optional_text(bytes, command.cwd.as_deref());
optional_text(bytes, command.prior_form_refusal.as_deref());
}
fn parameter_bytes(bytes: &mut Vec<u8>, parameter: &CommandParameterContract) {
text(bytes, ¶meter.name);
optional_text(bytes, parameter.default.as_deref());
}
fn line_bytes(bytes: &mut Vec<u8>, line: &CommandLineContract) {
len(bytes, line.slots.len());
for slot in &line.slots {
slot_bytes(bytes, slot);
}
}
fn slot_bytes(bytes: &mut Vec<u8>, slot: &ArgvSlot) {
fill(bytes, &slot.fill);
text(bytes, &slot.label);
bytes.push(u8::from(slot.admits_leading_dash));
}
fn env_bytes(bytes: &mut Vec<u8>, binding: &EnvBindingContract) {
text(bytes, &binding.name);
text(bytes, &binding.value);
}
fn fill(bytes: &mut Vec<u8>, template: &FillTemplate) {
len(bytes, template.pieces.len());
for piece in &template.pieces {
match piece {
FillPiece::Literal { text: value } => {
bytes.push(0);
text(bytes, value);
}
FillPiece::Hole { parameter } => {
bytes.push(1);
text(bytes, parameter);
}
}
}
}
fn optional_text(bytes: &mut Vec<u8>, value: Option<&str>) {
match value {
Some(value) => {
bytes.push(1);
text(bytes, value);
}
None => bytes.push(0),
}
}
fn text(bytes: &mut Vec<u8>, value: &str) {
len(bytes, value.len());
bytes.extend_from_slice(value.as_bytes());
}
fn len(bytes: &mut Vec<u8>, value: usize) {
bytes.extend_from_slice(&(value as u64).to_be_bytes());
}