Program Listing for File pybind11_utils.hpp

Return to documentation for file (include/yasmin/pybind11_utils.hpp)

// Copyright (C) 2025 Miguel Ángel González Santamarta
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef YASMIN_PYBIND11_UTILS_HPP
#define YASMIN_PYBIND11_UTILS_HPP

#include <memory>
#include <pybind11/pybind11.h>

#include "yasmin/blackboard.hpp"
#include "yasmin/blackboard_pywrapper.hpp"

namespace py = pybind11;

namespace yasmin {
namespace pybind11_utils {

inline std::shared_ptr<yasmin::Blackboard>
convert_blackboard_from_python(py::object blackboard_obj) {
  std::shared_ptr<yasmin::Blackboard> blackboard;

  // Case 1: None or not provided - create new Blackboard
  if (blackboard_obj.is_none()) {
    blackboard = std::make_shared<yasmin::Blackboard>();
  }
  // Case 2: Check if it's a BlackboardPyWrapper
  else if (py::isinstance<yasmin::BlackboardPyWrapper>(blackboard_obj)) {
    auto wrapper = blackboard_obj.cast<yasmin::BlackboardPyWrapper>();
    // Get the shared pointer directly instead of copying
    blackboard = wrapper.get_cpp_blackboard();
  }
  // Case 3: Check if it's a Blackboard
  else if (py::isinstance<yasmin::Blackboard>(blackboard_obj)) {
    blackboard = blackboard_obj.cast<std::shared_ptr<yasmin::Blackboard>>();
  }
  // Case 4: Unknown type - create a new blackboard
  else {
    blackboard = std::make_shared<yasmin::Blackboard>();
  }

  return blackboard;
}

template <typename Func> inline auto wrap_blackboard_callback(py::function cb) {
  return [cb](std::shared_ptr<yasmin::Blackboard> blackboard, auto... args) {
    py::gil_scoped_acquire acquire;
    yasmin::BlackboardPyWrapper wrapper(blackboard);
    cb(wrapper, args...);
  };
}

template <typename ReturnType>
inline auto wrap_blackboard_callback_with_return(py::function cb) {
  return [cb](std::shared_ptr<yasmin::Blackboard> blackboard) -> ReturnType {
    py::gil_scoped_acquire acquire;
    yasmin::BlackboardPyWrapper wrapper(blackboard);
    return cb(wrapper).cast<ReturnType>();
  };
}

template <typename ClassType, typename StateType>
inline void add_call_operator(ClassType &cls) {
  cls.def(
      "__call__",
      [](StateType &self, py::object blackboard_obj = py::none()) {
        auto blackboard = convert_blackboard_from_python(blackboard_obj);
        // Release GIL to allow C++ threads (important for Concurrence) to run
        py::gil_scoped_release release;
        return self(blackboard);
      },
      "Execute the state and return the outcome",
      py::arg("blackboard") = py::none());
}

} // namespace pybind11_utils
} // namespace yasmin

#endif // YASMIN_PYBIND11_UTILS_HPP