Skip to content

Commit a561031

Browse files
authored
Add bool support to Idol calls (#112)
This encodes a single `bool` as a `u8`, since they normally don't have a `zerocopy` representation.
1 parent a8b0a33 commit a561031

File tree

2 files changed

+59
-61
lines changed

2 files changed

+59
-61
lines changed

humility-cmd/src/idol.rs

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -47,78 +47,74 @@ impl<'a> IdolOperation<'a> {
4747
}
4848

4949
pub fn payload(&self, args: &[(&str, IdolArgument)]) -> Result<Vec<u8>> {
50-
let mut map = IndexMap::new();
5150
let hubris = self.hubris;
5251
let module = hubris.lookup_module(self.task)?;
5352

54-
for arg in args {
55-
map.insert(arg.0, &arg.1);
56-
}
53+
let mut map: IndexMap<_, _> =
54+
args.iter().map(|arg| (arg.0, &arg.1)).collect();
5755

5856
let mut payload = vec![0u8; self.args.size];
5957

6058
for arg in &self.operation.args {
61-
if let Some(val) = map.remove(arg.0 as &str) {
62-
if let RecvStrategy::FromBytes = arg.1.recv {
63-
let member = self
64-
.args
65-
.members
66-
.iter()
67-
.find(|&m| m.name == *arg.0)
68-
.ok_or_else(|| {
69-
anyhow!("did not find {} in {:?}", arg.0, self.args)
70-
})?;
59+
let val = map.remove(arg.0 as &str).ok_or_else(|| {
60+
anyhow!("argument \"{}\" is not specified", arg.0)
61+
})?;
62+
63+
// Find the expected name of the argument in the struct, based
64+
// on its encoding strategy (with a special case for `bool`, which
65+
// is packed into a single `u8`).
66+
let ty = &arg.1.ty.0;
67+
let arg_name = match arg.1.recv {
68+
RecvStrategy::FromBytes if ty != "bool" => arg.0.to_string(),
69+
_ => format!("raw_{}", arg.0),
70+
};
71+
72+
let member = self
73+
.args
74+
.members
75+
.iter()
76+
.find(|&m| m.name == arg_name)
77+
.ok_or_else(|| {
78+
anyhow!("did not find {} in {:?}", arg.0, self.args)
79+
})?;
80+
81+
// Now, we have to decide how to pack the argument into the payload
82+
//
83+
// The easiest option is if we're doing `FromBytes`, which encodes
84+
// the value directly (with a special case for booleans).
85+
if matches!(arg.1.recv, RecvStrategy::FromBytes) {
86+
if ty != "bool" {
7187
call_arg(hubris, member, val, &mut payload)?;
7288
} else {
73-
let raw = format!("raw_{}", arg.0);
74-
75-
let member = self
76-
.args
77-
.members
78-
.iter()
79-
.find(|&m| m.name == raw)
80-
.ok_or_else(|| {
81-
anyhow!(
82-
"did not find {} or {} in {:?}",
83-
arg.0,
84-
raw,
85-
self.args
86-
)
87-
})?;
88-
89-
let ty = &arg.1.ty.0;
90-
91-
//
92-
// We have a raw type, so we need to figure out how
93-
// to encode it. First, see if we can look up the
94-
// AttributedType as an enum...
95-
//
96-
if let Ok(e) = module.lookup_enum_byname(hubris, ty) {
97-
#[rustfmt::skip]
98-
call_arg_enum(
99-
hubris, arg.0, member, e, val, &mut payload,
100-
)?;
101-
continue;
102-
}
103-
104-
//
105-
// Now look it up as a structure. If it's a structure,
106-
// we will allow it if it's a newtype -- otherwise we'll
107-
// toss.
108-
//
109-
if let Ok(s) = module.lookup_struct_byname(hubris, ty) {
110-
if s.newtype().is_some() {
111-
call_arg(hubris, &s.members[0], val, &mut payload)?;
112-
continue;
113-
}
114-
115-
bail!("structure arguments currently unsupported");
116-
}
117-
118-
bail!("don't know what to do with {:?}", self.args);
89+
let v = IdolArgument::String(match val {
90+
IdolArgument::String("true") => "1",
91+
IdolArgument::String("false") => "0",
92+
_ => bail!("Invalid bool argument {:?}", val),
93+
});
94+
call_arg(hubris, member, &v, &mut payload)?;
95+
}
96+
}
97+
//
98+
// We have a raw type, so we need to figure out how
99+
// to encode it. First, see if we can look up the
100+
// AttributedType as an enum...
101+
//
102+
else if let Ok(e) = module.lookup_enum_byname(hubris, ty) {
103+
call_arg_enum(hubris, arg.0, member, e, val, &mut payload)?;
104+
}
105+
//
106+
// Now look it up as a structure. If it's a structure,
107+
// we will allow it if it's a newtype -- otherwise we'll
108+
// toss.
109+
//
110+
else if let Ok(s) = module.lookup_struct_byname(hubris, ty) {
111+
if s.newtype().is_some() {
112+
call_arg(hubris, &s.members[0], val, &mut payload)?;
113+
} else {
114+
bail!("structure arguments currently unsupported");
119115
}
120116
} else {
121-
bail!("argument \"{}\" is not specified", arg.0);
117+
bail!("don't know what to do with {:?}", self.args);
122118
}
123119
}
124120

humility-core/src/hubris.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3480,6 +3480,8 @@ impl HubrisArchive {
34803480
if let Some(v) = self.basetypes.get(&goff) {
34813481
if v.encoding == HubrisEncoding::Float {
34823482
write!(rval, "{}", readfloat(buf, 0, v.size)?)?;
3483+
} else if v.encoding == HubrisEncoding::Bool {
3484+
write!(rval, "{}", buf[0] != 0)?;
34833485
} else if v.size == 0 {
34843486
write!(rval, "()")?;
34853487
} else {

0 commit comments

Comments
 (0)