Skip to content

Commit c0d02bd

Browse files
committed
Add SelectCommand implementation
- Fixes #14
1 parent 1f7ee3f commit c0d02bd

File tree

6 files changed

+77
-3
lines changed

6 files changed

+77
-3
lines changed

commands2/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
RepeatCommand,
2828
RunCommand,
2929
ScheduleCommand,
30+
SelectCommand,
3031
SequentialCommandGroup,
3132
StartEndCommand,
3233
Subsystem,
@@ -54,6 +55,7 @@
5455
"CommandGroupBase",
5556
"CommandScheduler",
5657
"ConditionalCommand",
58+
"SelectCommand",
5759
"FunctionalCommand",
5860
"InstantCommand",
5961
"MecanumControllerCommand",

commands2/src/SelectCommandKey.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
#include <robotpy_build.h>
4+
5+
// this assumes that the __hash__ of the python object isn't going to change
6+
// once added to the map of the SelectCommand. This is... probably reasonable?
7+
struct SelectCommandKey {
8+
9+
SelectCommandKey() = default;
10+
11+
SelectCommandKey &operator=(const py::handle src) {
12+
py::gil_scoped_acquire gil;
13+
m_v = py::reinterpret_borrow<py::object>(src);
14+
m_hash = m_v.attr("__hash__")().cast<std::size_t>();
15+
return *this;
16+
}
17+
18+
operator py::object() const { return m_v; }
19+
20+
py::object m_v;
21+
std::size_t m_hash;
22+
};
23+
24+
inline bool operator==(const SelectCommandKey &lhs,
25+
const SelectCommandKey &rhs) {
26+
py::gil_scoped_acquire gil;
27+
return lhs.m_v.attr("__eq__")(rhs.m_v).cast<bool>();
28+
}
29+
30+
template <> struct std::hash<SelectCommandKey> {
31+
std::size_t operator()(const SelectCommandKey &s) const noexcept {
32+
return s.m_hash;
33+
}
34+
};
35+
36+
namespace pybind11 {
37+
namespace detail {
38+
template <> struct type_caster<SelectCommandKey> {
39+
PYBIND11_TYPE_CASTER(SelectCommandKey, const_name("object"));
40+
bool load(handle src, bool) {
41+
value = src;
42+
return true;
43+
}
44+
45+
static handle cast(const SelectCommandKey &src,
46+
return_value_policy /* policy */, handle /* parent */) {
47+
return src.m_v;
48+
}
49+
};
50+
} // namespace detail
51+
} // namespace pybind11

commands2/src/include/frc2/command/SelectCommand.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class SelectCommand : public CommandBase {
7474
std::vector<std::pair<Key, std::shared_ptr<Command>>>&& commands)
7575
: m_selector{std::move(selector)} {
7676
for (auto&& command : commands) {
77-
CommandScheduler::GetInstance().RequireUngrouped(command.second.get());
77+
CommandScheduler::GetInstance().RequireUngrouped(command.second);
7878
}
7979

8080
for (auto&& command : commands) {

gen/SelectCommand.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
extra_includes:
44
- frc2/command/Command.h
55
- frc2/command/Subsystem.h
6+
- src/SelectCommandKey.h
67

78
functions:
89
Initialize:
@@ -29,4 +30,4 @@ templates:
2930
SelectCommand:
3031
qualname: frc2::SelectCommand
3132
params:
32-
- py::object
33+
- SelectCommandKey

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ RepeatCommand = "frc2/command/RepeatCommand.h"
110110
RunCommand = "frc2/command/RunCommand.h"
111111
ScheduleCommand = "frc2/command/ScheduleCommand.h"
112112
# TODO
113-
# SelectCommand = "frc2/command/SelectCommand.h"
113+
SelectCommand = "frc2/command/SelectCommand.h"
114114
SequentialCommandGroup = "frc2/command/SequentialCommandGroup.h"
115115
# SetUtilities = "frc2/command/SetUtilities.h"
116116
StartEndCommand = "frc2/command/StartEndCommand.h"

tests/test_select_command.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import commands2
2+
from util import ConditionHolder
3+
4+
5+
def test_select_command(scheduler: commands2.CommandScheduler):
6+
c = ConditionHolder()
7+
8+
def _assert_false():
9+
assert False
10+
11+
cmd1 = commands2.RunCommand(_assert_false)
12+
cmd2 = commands2.RunCommand(c.setTrue)
13+
cmd3 = commands2.RunCommand(_assert_false)
14+
15+
sc = commands2.SelectCommand(lambda: 2, [(1, cmd1), (2, cmd2), (3, cmd3)])
16+
17+
scheduler.schedule(sc)
18+
scheduler.run()
19+
20+
assert c.cond

0 commit comments

Comments
 (0)