C++ Error Handling

RAII Everywhere

All HORUS C++ types use RAII — destructors clean up automatically:

{
    horus::Scheduler sched;           // creates Rust scheduler
    horus::TensorPool pool(1, 1024*1024, 64);  // creates SHM pool
    horus::Image img(pool, 640, 480); // allocates from pool

    // ... use them ...

}  // all destroyed in reverse order, SHM cleaned up

Move-only types prevent accidental copies:

auto pub = sched.advertise<horus::msg::CmdVel>("cmd");
auto pub2 = std::move(pub);   // OK — transfer ownership
// auto pub3 = pub2;           // ERROR — copy deleted

Null Safety

All C API functions handle null gracefully:

horus_scheduler_destroy(nullptr);      // no-op
horus_image_width(nullptr);            // returns 0
horus_params_has(nullptr, nullptr);    // returns false
horus_action_client_send_goal(nullptr, nullptr);  // returns nullptr

C++ wrappers check validity:

horus::TensorPool pool(1, 1024, 4);
if (!pool) {
    // Pool creation failed (e.g., SHM permission denied)
}

auto img = horus::Image(pool, 640, 480);
if (!img) {
    // Image allocation failed (pool full)
}

Exception Safety

The FFI boundary uses catch_unwind to prevent Rust panics from crossing into C++:

C++ tick lambda
  └─ extern "C" trampoline function
      └─ CppNode::tick() in Rust
          └─ std::panic::catch_unwind
              └─ your callback
                  └─ if panic → caught, node marked failed, continues

If a C++ exception is thrown inside a tick callback, it must be caught before returning. Unwinding through extern "C" is undefined behavior.

sched.add("safe_node")
    .tick([&] {
        try {
            risky_operation();
        } catch (const std::exception& e) {
            horus::log::error("node", e.what());
        }
    })
    .build();

Failed Nodes

If a Rust panic occurs in a node's tick, the node is disabled:

  • First panic: caught, logged, node marked failed
  • Subsequent ticks: silently skipped (no-op)
  • Other nodes continue running

This prevents one misbehaving node from taking down the entire system.

Error Logging

Use horus::log for structured error reporting:

horus::log::info("sensor", "Calibration complete");
horus::log::warn("controller", "PID output near saturation");
horus::log::error("safety", "Watchdog timeout on motor driver");
horus::blackbox::record("crash", "Segfault in vision pipeline");

All messages appear in horus log CLI output.