@@ -24,12 +24,25 @@ namespace roboplan {
2424
2525using namespace nanobind ::literals;
2626
27- template <typename T, typename E> T unwrap_expected (const tl::expected<T, E>& ret) {
28- if (ret.has_value ()) {
29- return ret.value ();
30- } else {
31- throw std::runtime_error (" whoopsie daisey" );
32- }
27+ // / @brief Wrapper function for easily binding tl::expected return types with nanobind.
28+ // / @return The unwrapped value, or throw a runtime_error.
29+ template <typename Class, typename Ret, typename Err, typename ... Args>
30+ auto unwrap_expected (tl::expected<Ret, Err> (Class::*method)(Args...)) {
31+ return [method](Class& self, Args... args) -> Ret {
32+ auto result = (self.*method)(args...);
33+ if (result.has_value ()) {
34+ return result.value ();
35+ } else {
36+ // If the error is string convertible then we can pass it on. Otherwise
37+ // we do not know the details of the underlying exception.
38+ // TODO: Consider wrapping with a streamable option.
39+ if constexpr (std::is_convertible_v<Err, std::string>) {
40+ throw std::runtime_error (std::string (result.error ()));
41+ } else {
42+ throw std::runtime_error (" Unknown error occurred." );
43+ }
44+ }
45+ };
3346}
3447
3548NB_MODULE (roboplan, m) {
@@ -146,10 +159,7 @@ NB_MODULE(roboplan, m) {
146159
147160 nanobind::class_<RRT >(m_rrt, " RRT" )
148161 .def (nanobind::init<const std::shared_ptr<Scene>, const RRTOptions&>())
149- .def (" plan_expected" ,
150- [](RRT & self, const JointConfiguration& start, const JointConfiguration& goal) {
151- return unwrap_expected (self.plan_expected (start, goal));
152- })
162+ .def (" plan_expected" , unwrap_expected (&RRT ::plan_expected))
153163 .def (" plan" , &RRT ::plan)
154164 .def (" setRngSeed" , &RRT ::setRngSeed)
155165 .def (" getNodes" , &RRT ::getNodes);
0 commit comments