[robotpy] Run wpiformat on non-python robotpy files (#8362)

This turns the styleguide on for the non-python robotpy files.

The overwhelming amount of changes were
related to whitespace, followed by some IWYU for standard library
headers.
This commit is contained in:
PJ Reiniger
2026-06-21 22:36:03 -04:00
committed by GitHub
parent 6bc7051e23
commit 4a2cd3e5d0
71 changed files with 877 additions and 739 deletions

View File

@@ -13,7 +13,10 @@ generatedFileExclude {
docs/theme\.css$
generated/
hal/src/main/native/systemcore/rev/
python/
src/main/python/.*/type_casters/
src/main/python/.*\.py$
src/test/python/.*\.py$
robotpyExamples/
resources/
thirdparty/
@@ -41,4 +44,7 @@ licenseUpdateExclude {
wpiutil/src/main/native/cpp/sha1\.cpp$
wpiutil/src/main/native/include/wpi/util/sha1\.hpp$
wpinet/src/main/native/linux/AvahiClient\.hpp$
src/main/python/
src/test/python/
}

View File

@@ -1,4 +1,6 @@
#include "semiwrap_init.robotpy_apriltag._apriltag.hpp"
SEMIWRAP_PYBIND11_MODULE(m) { initWrapper(m); }
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}

View File

@@ -32,7 +32,7 @@ classes:
// We are going to move the detection result into this shared_ptr
// so that python can keep it alive. We don't expose the result directly
// to the user because we'd have to pretend it's a list, and that would
// be annoying.
// be annoying.
std::shared_ptr<AprilTagDetector::Results> c_result;
{
py::gil_scoped_release unlock;

View File

@@ -33,4 +33,4 @@ source = "vcs"
packages = ["commands2"]
[tool.hatch.build.targets.wheel]
packages = ["commands2"]
packages = ["commands2"]

View File

@@ -38,4 +38,4 @@ name = "datalog"
includedir = "src/native/datalog/include"
libdir = "src/native/datalog/lib"
shared_libraries = ["datalog"]
requires = ["robotpy-native-wpiutil"]
requires = ["robotpy-native-wpiutil"]

View File

@@ -1,6 +1,6 @@
#include <semiwrap_init.wpilog._wpilog.hpp>
#include "semiwrap_init.wpilog._wpilog.hpp"
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
initWrapper(m);
}

View File

@@ -1,21 +1,21 @@
#include <semiwrap_init.hal.simulation._simulation.hpp>
#include <pybind11/functional.h>
#include "semiwrap_init.hal.simulation._simulation.hpp"
#include "sim_cb.h"
#include "sim_value_cb.h"
void HALSIM_ResetGlobalHandles();
SEMIWRAP_PYBIND11_MODULE(m) {
py::class_<SimCB> cls_SimCB(m, "SimCB");
cls_SimCB.doc() = "Simulation callback handle";
cls_SimCB.def("cancel", &SimCB::Cancel, py::doc("Cancel the callback"));
py::class_<SimValueCB> cls_SimValueCB(m, "SimValueCB");
cls_SimValueCB.doc() = "Simulation callback handle";
cls_SimValueCB.def("cancel", &SimValueCB::Cancel, py::doc("Cancel the callback"));
cls_SimValueCB.def("cancel", &SimValueCB::Cancel,
py::doc("Cancel the callback"));
initWrapper(m);

View File

@@ -4,12 +4,11 @@
#include "wpi/hal/simulation/NotifierData.h"
void HALSIM_ResetGlobalHandles() {
// if we just reset the handles, notifiers might hang forever,
// so we just enumerate and cancel them all
auto sz = HALSIM_GetNotifierInfo(nullptr, 0);
if (sz > 0) {
struct HALSIM_NotifierInfo *info = new struct HALSIM_NotifierInfo[sz];
struct HALSIM_NotifierInfo* info = new struct HALSIM_NotifierInfo[sz];
HALSIM_GetNotifierInfo(info, sz);
for (int i = 0; i < sz; i++) {

View File

@@ -1,33 +1,29 @@
#pragma once
#include <cstdint>
#include <functional>
class SimCB {
public:
public:
SimCB(std::function<void(void)> fn, std::function<void(int32_t)> cancel)
: m_fn(fn), m_cancel(cancel) {}
SimCB(std::function<void(void)> fn, std::function<void(int32_t)> cancel) :
m_fn(fn),
m_cancel(cancel)
{}
void SetUID(int32_t uid) { m_uid = uid; }
void SetUID(int32_t uid) {
m_uid = uid;
~SimCB() { Cancel(); }
void Cancel() {
if (m_valid) {
m_cancel(m_uid);
m_valid = false;
}
}
~SimCB() {
Cancel();
}
std::function<void(void)> m_fn;
void Cancel() {
if (m_valid) {
m_cancel(m_uid);
m_valid = false;
}
}
std::function<void(void)> m_fn;
private:
bool m_valid = true;
int32_t m_uid;
std::function<void(int32_t)> m_cancel;
};
private:
bool m_valid = true;
int32_t m_uid;
std::function<void(int32_t)> m_cancel;
};

View File

@@ -1,37 +1,33 @@
#pragma once
#include <functional>
#include "wpi/hal/SimDevice.h"
class SimValueCB {
public:
public:
using FnType = std::function<void(const char*, HAL_SimValueHandle,
HAL_SimValueDirection, HAL_Value)>;
using FnType = std::function<void(const char *, HAL_SimValueHandle, HAL_SimValueDirection, HAL_Value)>;
SimValueCB(FnType fn, std::function<void(int32_t)> cancel)
: m_fn(fn), m_cancel(cancel) {}
SimValueCB(FnType fn, std::function<void(int32_t)> cancel) :
m_fn(fn),
m_cancel(cancel)
{}
void SetUID(int32_t uid) { m_uid = uid; }
void SetUID(int32_t uid) {
m_uid = uid;
~SimValueCB() { Cancel(); }
void Cancel() {
if (m_valid) {
m_cancel(m_uid);
m_valid = false;
}
}
~SimValueCB() {
Cancel();
}
FnType m_fn;
void Cancel() {
if (m_valid) {
m_cancel(m_uid);
m_valid = false;
}
}
FnType m_fn;
private:
bool m_valid = true;
int32_t m_uid;
std::function<void(int32_t)> m_cancel;
};
private:
bool m_valid = true;
int32_t m_uid;
std::function<void(int32_t)> m_cancel;
};

View File

@@ -1,5 +1,7 @@
#pragma once
#include <string>
#include <pybind11/pybind11.h>
#include "wpi/hal/DriverStationTypes.h"
@@ -8,23 +10,23 @@ namespace pybind11 {
template <>
struct format_descriptor<HAL_JoystickPOV> {
static constexpr const char c = 'B';
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
static constexpr const char c = 'B';
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
};
template <>
struct format_descriptor<HAL_JoystickTouchpad> {
static constexpr const char c = 'B';
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
static constexpr const char c = 'B';
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
};
template <>
struct format_descriptor<HAL_JoystickTouchpadFinger> {
static constexpr const char c = 'B';
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
static constexpr const char c = 'B';
static constexpr const char value[2] = {c, '\0'};
static std::string format() { return std::string(1, c); }
};
}
} // namespace pybind11

View File

@@ -1,25 +1,26 @@
#include "wpi/hal/HAL.h"
#include "semiwrap_init.hal._wpiHal.hpp"
#include "wpi/hal/DriverStation.hpp"
#include "wpi/hal/Value.h"
#include <semiwrap_init.hal._wpiHal.hpp>
using namespace pybind11::literals;
static py::module_ sys_module;
SEMIWRAP_PYBIND11_MODULE(m) {
// Add this manually so it can be used from SimValue
py::enum_<HAL_Type>(m, "Type")
.value("UNASSIGNED", HAL_Type::HAL_UNASSIGNED)
.value("BOOLEAN", HAL_Type::HAL_BOOLEAN)
.value("DOUBLE", HAL_Type::HAL_DOUBLE)
.value("ENUM", HAL_Type::HAL_ENUM)
.value("INT", HAL_Type::HAL_INT)
.value("LONG", HAL_Type::HAL_LONG);
.value("UNASSIGNED", HAL_Type::HAL_UNASSIGNED)
.value("BOOLEAN", HAL_Type::HAL_BOOLEAN)
.value("DOUBLE", HAL_Type::HAL_DOUBLE)
.value("ENUM", HAL_Type::HAL_ENUM)
.value("INT", HAL_Type::HAL_INT)
.value("LONG", HAL_Type::HAL_LONG);
// clang-format off
// Add this manually because it would be annoying to do otherwise
py::class_<HAL_Value>(m, "Value")
.def_readonly("type", &HAL_Value::type)
@@ -57,6 +58,7 @@ SEMIWRAP_PYBIND11_MODULE(m) {
return "<Value type=invalid>";
}
});
// clang-format on
initWrapper(m);
@@ -67,15 +69,18 @@ SEMIWRAP_PYBIND11_MODULE(m) {
m.attr("__halplatform__") = "sim";
m.attr("__hal_simulation__") = true;
// clang-format off
m.def("__test_senderr", []() {
wpi::hal::SendError(1, 2, "\xfa" "badmessage", "location", "callstack", 1);
}, release_gil());
// clang-format on
#endif
// Redirect stderr to python stderr
sys_module = py::module_::import("sys");
// clang-format off
HAL_SetPrintErrorImpl([](const struct WPI_String* line) {
if (line == nullptr || line->str == nullptr || line->len == 0) {
return;
@@ -90,7 +95,9 @@ SEMIWRAP_PYBIND11_MODULE(m) {
py::print(py::reinterpret_steal<py::str>(o), "file"_a=sys_module.attr("stderr"));
}
});
// clang-format on
// clang-format off
// Do cleanup on module unload
static int unused; // the capsule needs something to reference
py::capsule cleanup(&unused, [](void *) {
@@ -106,5 +113,6 @@ SEMIWRAP_PYBIND11_MODULE(m) {
HAL_Shutdown();
}
});
// clang-format on
m.add_object("_cleanup", cleanup);
}

View File

@@ -60,4 +60,4 @@ name = "wpihal"
includedir = "src/native/wpihal/include"
libdir = "src/native/wpihal/lib"
shared_libraries = ["wpiHal"]
requires = ["robotpy-native-wpiutil", "robotpy-native-ntcore", "robotpy-native-mrclib"]
requires = ["robotpy-native-wpiutil", "robotpy-native-ntcore", "robotpy-native-mrclib"]

View File

@@ -10,4 +10,3 @@ strip_prefixes:
enums:
HAL_SimValueDirection:

View File

@@ -1,3 +1,9 @@
#pragma once
#include <string>
#include <utility>
// clang-format off
cls_NetworkTable
.def("getValue", [](const NetworkTable &self, std::string_view key, py::object defaultValue) -> py::object {
wpi::nt::NetworkTableEntry entry;
@@ -54,3 +60,4 @@ cls_NetworkTable
return self.ContainsKey(key);
}, release_gil())
;
// clang-format on

View File

@@ -1,3 +1,8 @@
#pragma once
#include <string>
// clang-format off
cls_NetworkTableEntry
.def_property_readonly("value", [](const wpi::nt::NetworkTableEntry &self) {
wpi::nt::Value v;
@@ -46,3 +51,4 @@ cls_NetworkTableEntry
return self->SetDefaultValue(pyntcore::py2ntvalue(value));
}, py::arg("value"))
;
// clang-format on

View File

@@ -1,56 +1,61 @@
#include <semiwrap.h>
#include "nt_instance.h"
#include "wpi/nt/ntcore_cpp.hpp"
#include <set>
#include <semiwrap.h>
#include "wpi/nt/ntcore_cpp.hpp"
// only accessed under GIL
static std::set<NT_Inst> g_known_instances;
namespace pyntcore {
void onInstanceStart(wpi::nt::NetworkTableInstance *instance) {
g_known_instances.emplace(instance->GetHandle());
void onInstanceStart(wpi::nt::NetworkTableInstance* instance) {
g_known_instances.emplace(instance->GetHandle());
py::module::import("ntcore._logutil")
.attr("NtLogForwarder").attr("onInstanceStart")(instance);
py::module::import("ntcore._logutil")
.attr("NtLogForwarder")
.attr("onInstanceStart")(instance);
}
void onInstancePreReset(wpi::nt::NetworkTableInstance *instance) {
py::module::import("ntcore._logutil")
.attr("NtLogForwarder").attr("onInstanceDestroy")(instance);
void onInstancePreReset(wpi::nt::NetworkTableInstance* instance) {
py::module::import("ntcore._logutil")
.attr("NtLogForwarder")
.attr("onInstanceDestroy")(instance);
}
void onInstancePostReset(wpi::nt::NetworkTableInstance *instance) {
py::module::import("ntcore.util")
.attr("_NtProperty").attr("onInstancePostReset")(instance);
void onInstancePostReset(wpi::nt::NetworkTableInstance* instance) {
py::module::import("ntcore.util")
.attr("_NtProperty")
.attr("onInstancePostReset")(instance);
}
void onInstanceDestroy(wpi::nt::NetworkTableInstance *instance) {
py::module::import("ntcore._logutil")
.attr("NtLogForwarder").attr("onInstanceDestroy")(instance);
py::module::import("ntcore.util")
.attr("_NtProperty").attr("onInstanceDestroy")(instance);
void onInstanceDestroy(wpi::nt::NetworkTableInstance* instance) {
py::module::import("ntcore._logutil")
.attr("NtLogForwarder")
.attr("onInstanceDestroy")(instance);
py::module::import("ntcore.util")
.attr("_NtProperty")
.attr("onInstanceDestroy")(instance);
g_known_instances.erase(instance->GetHandle());
g_known_instances.erase(instance->GetHandle());
}
// reset all instances to clear out any potential python references that
// might be hanging around in a callback or something
void resetAllInstances()
{
std::set<NT_Inst> known_instances;
known_instances.swap(g_known_instances);
void resetAllInstances() {
std::set<NT_Inst> known_instances;
known_instances.swap(g_known_instances);
// always reset the default instance
known_instances.emplace(wpi::nt::GetDefaultInstance());
// always reset the default instance
known_instances.emplace(wpi::nt::GetDefaultInstance());
py::gil_scoped_release unlock;
py::gil_scoped_release unlock;
for (auto &inst: known_instances) {
wpi::nt::ResetInstance(inst);
}
for (auto& inst : known_instances) {
wpi::nt::ResetInstance(inst);
}
}
}; // namespace pyntcore
} // namespace pyntcore

View File

@@ -1,16 +1,16 @@
#pragma once
#include "wpi/nt/ntcore.h"
#include "wpi/nt/NetworkTableInstance.hpp"
#include "wpi/nt/ntcore.h"
namespace pyntcore {
void onInstanceStart(wpi::nt::NetworkTableInstance *instance);
void onInstancePreReset(wpi::nt::NetworkTableInstance *instance);
void onInstancePostReset(wpi::nt::NetworkTableInstance *instance);
void onInstanceDestroy(wpi::nt::NetworkTableInstance *instance);
void onInstanceStart(wpi::nt::NetworkTableInstance* instance);
void onInstancePreReset(wpi::nt::NetworkTableInstance* instance);
void onInstancePostReset(wpi::nt::NetworkTableInstance* instance);
void onInstanceDestroy(wpi::nt::NetworkTableInstance* instance);
void resetAllInstances();
}; // namespace pyntcore
} // namespace pyntcore

View File

@@ -1,39 +1,41 @@
#pragma once
#include <vector>
#include <pybind11/pybind11.h>
namespace pybind11 {
namespace detail {
namespace pybind11::detail {
// ntcore uses std::vector<uint8_t> anytime there is a raw value, so
// add this specialization to convert to/from bytes directly
template<>
template <>
struct type_caster<std::vector<uint8_t>> {
using vector_type = std::vector<uint8_t>;
PYBIND11_TYPE_CASTER(vector_type, const_name("bytes"));
using vector_type = std::vector<uint8_t>;
PYBIND11_TYPE_CASTER(vector_type, const_name("bytes"));
bool load(handle src, bool convert) {
if (!isinstance<buffer>(src)) {
return false;
}
auto buf = reinterpret_borrow<buffer>(src);
auto req = buf.request();
if (req.ndim != 1) {
return false;
}
auto begin = (const uint8_t*)req.ptr;
auto end = begin + req.size*req.itemsize;
value = std::vector<uint8_t>(begin, end);
return true;
bool load(handle src, bool convert) {
if (!isinstance<buffer>(src)) {
return false;
}
auto buf = reinterpret_borrow<buffer>(src);
auto req = buf.request();
if (req.ndim != 1) {
return false;
}
static handle cast(const std::vector<uint8_t> &src, return_value_policy policy, handle parent) {
return py::bytes((char*)src.data(), src.size()).release();
}
auto begin = (const uint8_t*)req.ptr;
auto end = begin + req.size * req.itemsize;
value = std::vector<uint8_t>(begin, end);
return true;
}
static handle cast(const std::vector<uint8_t>& src,
return_value_policy policy, handle parent) {
return py::bytes(reinterpret_cast<const char*>(src.data()), src.size())
.release();
}
};
}
}
} // namespace pybind11::detail

View File

@@ -1,14 +1,12 @@
#include <semiwrap_init.ntcore._ntcore.hpp>
#include "nt_instance.h"
#include "semiwrap_init.ntcore._ntcore.hpp"
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
static int unused;
py::capsule cleanup(&unused, [](void *) {
pyntcore::resetAllInstances();
});
py::capsule cleanup(&unused, [](void*) { pyntcore::resetAllInstances(); });
m.add_object("_st_cleanup", cleanup);
}
}

View File

@@ -1,111 +1,110 @@
#include "py2value.h"
#include <string>
#include <utility>
#include <vector>
// type casters
#include <pybind11/stl.h>
#include <wpi_span_type_caster.h>
namespace pyntcore {
const char * nttype2str(NT_Type type) {
const char* nttype2str(NT_Type type) {
switch (type) {
case NT_BOOLEAN:
return "bool";
case NT_DOUBLE:
return "double";
case NT_STRING:
return "string";
case NT_RAW:
return "raw";
case NT_BOOLEAN_ARRAY:
return "bool[]";
case NT_DOUBLE_ARRAY:
return "double[]";
case NT_STRING_ARRAY:
return "string[]";
case NT_INTEGER:
return "int";
case NT_FLOAT:
return "float";
case NT_INTEGER_ARRAY:
return "int[]";
case NT_FLOAT_ARRAY:
return "float[]";
default:
return "invalid";
case NT_BOOLEAN:
return "bool";
case NT_DOUBLE:
return "double";
case NT_STRING:
return "string";
case NT_RAW:
return "raw";
case NT_BOOLEAN_ARRAY:
return "bool[]";
case NT_DOUBLE_ARRAY:
return "double[]";
case NT_STRING_ARRAY:
return "string[]";
case NT_INTEGER:
return "int";
case NT_FLOAT:
return "float";
case NT_INTEGER_ARRAY:
return "int[]";
case NT_FLOAT_ARRAY:
return "float[]";
default:
return "invalid";
}
}
py::object ntvalue2py(const wpi::nt::Value &ntvalue) {
auto &v = ntvalue.value();
py::object ntvalue2py(const wpi::nt::Value& ntvalue) {
auto& v = ntvalue.value();
switch (v.type) {
case NT_BOOLEAN:
return py::bool_(v.data.v_boolean);
case NT_BOOLEAN:
return py::bool_(v.data.v_boolean);
case NT_DOUBLE:
return py::float_(v.data.v_double);
case NT_DOUBLE:
return py::float_(v.data.v_double);
case NT_STRING:
return py::str(v.data.v_string.str, v.data.v_string.len);
case NT_STRING:
return py::str(v.data.v_string.str, v.data.v_string.len);
case NT_RAW:
return py::bytes((const char *)v.data.v_raw.data, v.data.v_raw.size);
case NT_RAW:
return py::bytes((const char*)v.data.v_raw.data, v.data.v_raw.size);
case NT_BOOLEAN_ARRAY: {
py::list l(v.data.arr_boolean.size);
for (size_t i = 0; i < v.data.arr_boolean.size; i++) {
auto b = py::bool_(v.data.arr_boolean.arr[i]);
PyList_SET_ITEM(l.ptr(), i, b.release().ptr());
case NT_BOOLEAN_ARRAY: {
py::list l(v.data.arr_boolean.size);
for (size_t i = 0; i < v.data.arr_boolean.size; i++) {
auto b = py::bool_(v.data.arr_boolean.arr[i]);
PyList_SET_ITEM(l.ptr(), i, b.release().ptr());
}
return std::move(l);
}
return std::move(l);
}
case NT_DOUBLE_ARRAY: {
py::list l(v.data.arr_double.size);
for (size_t i = 0; i < v.data.arr_double.size; i++) {
auto d = py::float_(v.data.arr_double.arr[i]);
PyList_SET_ITEM(l.ptr(), i, d.release().ptr());
case NT_DOUBLE_ARRAY: {
py::list l(v.data.arr_double.size);
for (size_t i = 0; i < v.data.arr_double.size; i++) {
auto d = py::float_(v.data.arr_double.arr[i]);
PyList_SET_ITEM(l.ptr(), i, d.release().ptr());
}
return std::move(l);
}
return std::move(l);
}
case NT_STRING_ARRAY: {
return py::cast(ntvalue.GetStringArray());
}
case NT_INTEGER: {
return py::int_(v.data.v_int);
}
case NT_FLOAT: {
return py::float_(v.data.v_float);
}
case NT_INTEGER_ARRAY: {
py::list l(v.data.arr_int.size);
for (size_t i = 0; i < v.data.arr_int.size; i++) {
auto d = py::int_(v.data.arr_int.arr[i]);
PyList_SET_ITEM(l.ptr(), i, d.release().ptr());
case NT_STRING_ARRAY: {
return py::cast(ntvalue.GetStringArray());
}
return std::move(l);
}
case NT_FLOAT_ARRAY: {
py::list l(v.data.arr_float.size);
for (size_t i = 0; i < v.data.arr_float.size; i++) {
auto d = py::float_(v.data.arr_float.arr[i]);
PyList_SET_ITEM(l.ptr(), i, d.release().ptr());
case NT_INTEGER: {
return py::int_(v.data.v_int);
}
return std::move(l);
}
default:
return py::none();
case NT_FLOAT: {
return py::float_(v.data.v_float);
}
case NT_INTEGER_ARRAY: {
py::list l(v.data.arr_int.size);
for (size_t i = 0; i < v.data.arr_int.size; i++) {
auto d = py::int_(v.data.arr_int.arr[i]);
PyList_SET_ITEM(l.ptr(), i, d.release().ptr());
}
return std::move(l);
}
case NT_FLOAT_ARRAY: {
py::list l(v.data.arr_float.size);
for (size_t i = 0; i < v.data.arr_float.size; i++) {
auto d = py::float_(v.data.arr_float.arr[i]);
PyList_SET_ITEM(l.ptr(), i, d.release().ptr());
}
return std::move(l);
}
default:
return py::none();
}
}
@@ -143,38 +142,39 @@ wpi::nt::Value py2ntvalue(py::handle h) {
auto v = h.cast<std::vector<std::string>>();
return wpi::nt::Value::MakeStringArray(v);
} else {
throw py::value_error("Can only put bool/int/float/str/bytes or lists/tuples of them");
throw py::value_error(
"Can only put bool/int/float/str/bytes or lists/tuples of them");
}
}
py::function valueFactoryByType(wpi::nt::NetworkTableType type) {
py::object PyNtValue = py::module::import("ntcore").attr("Value");
switch (type) {
case wpi::nt::NetworkTableType::BOOLEAN:
return PyNtValue.attr("makeBoolean");
case wpi::nt::NetworkTableType::DOUBLE:
return PyNtValue.attr("makeDouble");
case wpi::nt::NetworkTableType::STRING:
return PyNtValue.attr("makeString");
case wpi::nt::NetworkTableType::RAW:
return PyNtValue.attr("makeRaw");
case wpi::nt::NetworkTableType::BOOLEAN_ARRAY:
return PyNtValue.attr("makeBooleanArray");
case wpi::nt::NetworkTableType::DOUBLE_ARRAY:
return PyNtValue.attr("makeDoubleArray");
case wpi::nt::NetworkTableType::STRING_ARRAY:
return PyNtValue.attr("makeStringArray");
case wpi::nt::NetworkTableType::INTEGER:
return PyNtValue.attr("makeInteger");
case wpi::nt::NetworkTableType::FLOAT:
return PyNtValue.attr("makeFloat");
case wpi::nt::NetworkTableType::INTEGER_ARRAY:
return PyNtValue.attr("makeIntegerArray");
case wpi::nt::NetworkTableType::FLOAT_ARRAY:
return PyNtValue.attr("makeFloatArray");
default:
throw py::type_error("empty nt value");
case wpi::nt::NetworkTableType::BOOLEAN:
return PyNtValue.attr("makeBoolean");
case wpi::nt::NetworkTableType::DOUBLE:
return PyNtValue.attr("makeDouble");
case wpi::nt::NetworkTableType::STRING:
return PyNtValue.attr("makeString");
case wpi::nt::NetworkTableType::RAW:
return PyNtValue.attr("makeRaw");
case wpi::nt::NetworkTableType::BOOLEAN_ARRAY:
return PyNtValue.attr("makeBooleanArray");
case wpi::nt::NetworkTableType::DOUBLE_ARRAY:
return PyNtValue.attr("makeDoubleArray");
case wpi::nt::NetworkTableType::STRING_ARRAY:
return PyNtValue.attr("makeStringArray");
case wpi::nt::NetworkTableType::INTEGER:
return PyNtValue.attr("makeInteger");
case wpi::nt::NetworkTableType::FLOAT:
return PyNtValue.attr("makeFloat");
case wpi::nt::NetworkTableType::INTEGER_ARRAY:
return PyNtValue.attr("makeIntegerArray");
case wpi::nt::NetworkTableType::FLOAT_ARRAY:
return PyNtValue.attr("makeFloatArray");
default:
throw py::type_error("empty nt value");
}
}
}
} // namespace pyntcore

View File

@@ -1,25 +1,27 @@
#pragma once
#include <semiwrap.h>
#include "wpi/nt/NetworkTableValue.hpp"
#include "wpi/nt/NetworkTableType.hpp"
#include <fmt/format.h>
#include <semiwrap.h>
#include "wpi/nt/NetworkTableType.hpp"
#include "wpi/nt/NetworkTableValue.hpp"
namespace pyntcore {
const char * nttype2str(NT_Type type);
const char* nttype2str(NT_Type type);
py::object ntvalue2py(const wpi::nt::Value &ntvalue);
py::object ntvalue2py(const wpi::nt::Value& ntvalue);
wpi::nt::Value py2ntvalue(py::handle h);
py::function valueFactoryByType(wpi::nt::NetworkTableType type);
inline void ensure_value_is(NT_Type expected, wpi::nt::Value *v) {
if (v->type() != expected) {
throw py::value_error(fmt::format(
"Value type is {}, not {}", nttype2str(v->type()), nttype2str(expected)
));
}
inline void ensure_value_is(NT_Type expected, wpi::nt::Value* v) {
if (v->type() != expected) {
throw py::value_error(fmt::format("Value type is {}, not {}",
nttype2str(v->type()),
nttype2str(expected)));
}
}
};
} // namespace pyntcore

View File

@@ -1,141 +1,179 @@
#include "pyentry.h"
#include "py2value.h"
#include <string>
#include <utility>
#include <pybind11/stl.h>
#include <wpi_span_type_caster.h>
#include "py2value.h"
namespace pyntcore {
py::object GetBooleanEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_BOOLEAN) return defaultValue;
return py::cast(value.GetBoolean());
py::object GetBooleanEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_BOOLEAN) {
return defaultValue;
}
return py::cast(value.GetBoolean());
}
py::object GetDoubleEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_DOUBLE) return defaultValue;
return py::cast(value.GetDouble());
py::object GetDoubleEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_DOUBLE) {
return defaultValue;
}
return py::cast(value.GetDouble());
}
py::object GetFloatEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_FLOAT) return defaultValue;
return py::cast(value.GetFloat());
py::object GetFloatEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_FLOAT) {
return defaultValue;
}
return py::cast(value.GetFloat());
}
py::object GetIntegerEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_INTEGER) return defaultValue;
return py::cast(value.GetInteger());
py::object GetIntegerEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_INTEGER) {
return defaultValue;
}
return py::cast(value.GetInteger());
}
py::object GetStringEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_STRING) return defaultValue;
auto s = value.GetString();
return py::str(s.data(), s.size());
py::object GetStringEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_STRING) {
return defaultValue;
}
auto s = value.GetString();
return py::str(s.data(), s.size());
}
py::object GetRawEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_RAW) return defaultValue;
return py::cast(value.GetRaw());
py::object GetRawEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_RAW) {
return defaultValue;
}
return py::cast(value.GetRaw());
}
py::object GetBooleanArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_BOOLEAN_ARRAY) return defaultValue;
// ntcore will return bit vector by default. Convert to List[bool]
auto v = value.value();
py::list l(v.data.arr_boolean.size);
for (size_t i = 0; i < v.data.arr_boolean.size; i++) {
auto b = py::bool_(v.data.arr_boolean.arr[i]);
PyList_SET_ITEM(l.ptr(), i, b.release().ptr());
}
return std::move(l);
py::object GetBooleanArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_BOOLEAN_ARRAY) {
return defaultValue;
}
// ntcore will return bit vector by default. Convert to List[bool]
auto v = value.value();
py::list l(v.data.arr_boolean.size);
for (size_t i = 0; i < v.data.arr_boolean.size; i++) {
auto b = py::bool_(v.data.arr_boolean.arr[i]);
PyList_SET_ITEM(l.ptr(), i, b.release().ptr());
}
return std::move(l);
}
py::object GetDoubleArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_DOUBLE_ARRAY) return defaultValue;
return py::cast(value.GetDoubleArray());
py::object GetDoubleArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_DOUBLE_ARRAY) {
return defaultValue;
}
return py::cast(value.GetDoubleArray());
}
py::object GetFloatArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_FLOAT_ARRAY) return defaultValue;
return py::cast(value.GetFloatArray());
py::object GetFloatArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_FLOAT_ARRAY) {
return defaultValue;
}
return py::cast(value.GetFloatArray());
}
py::object GetIntegerArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_INTEGER_ARRAY) return defaultValue;
return py::cast(value.GetIntegerArray());
py::object GetIntegerArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_INTEGER_ARRAY) {
return defaultValue;
}
return py::cast(value.GetIntegerArray());
}
py::object GetStringArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_STRING_ARRAY) return defaultValue;
std::span<const std::string> rval = value.GetStringArray();
return py::cast(rval);
py::object GetStringArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value || value.type() != NT_STRING_ARRAY) {
return defaultValue;
}
std::span<const std::string> rval = value.GetStringArray();
return py::cast(rval);
}
py::object GetValueEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value) return defaultValue;
return ntvalue2py(value);
py::object GetValueEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue) {
wpi::nt::Value value;
{
py::gil_scoped_release release;
value = wpi::nt::GetEntryValue(entry.GetHandle());
}
if (!value) {
return defaultValue;
}
return ntvalue2py(value);
}
}; // pyntcore
} // namespace pyntcore

View File

@@ -1,21 +1,35 @@
#pragma once
#include <semiwrap.h>
#include "wpi/nt/NetworkTableEntry.hpp"
#include "wpi/nt/NetworkTableValue.hpp"
namespace pyntcore {
py::object GetBooleanEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetDoubleEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetFloatEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetIntegerEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetStringEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetRawEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetBooleanArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetDoubleArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetFloatArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetIntegerArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetStringArrayEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetValueEntry(const wpi::nt::NetworkTableEntry &entry, py::object defaultValue);
py::object GetBooleanEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetDoubleEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetFloatEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetIntegerEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetStringEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetRawEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetBooleanArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetDoubleArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetFloatArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetIntegerArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetStringArrayEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
py::object GetValueEntry(const wpi::nt::NetworkTableEntry& entry,
py::object defaultValue);
};
} // namespace pyntcore

View File

@@ -21,8 +21,6 @@
#include "wpi/nt/NetworkTableValue.hpp"
#include "wpi/util/raw_ostream.hpp"
using namespace std::string_literals;
namespace wpi::nt::net {
namespace {
@@ -119,6 +117,7 @@ std::pair<int, Value> DecodeBinary(std::span<const uint8_t> data,
}
ClientMessage Publish(int pubuid, std::string_view name) {
using namespace std::literals;
return ClientMessage{PublishMsg{
pubuid, std::string{name}, "double"s, wpi::util::json::object(), {}}};
}

View File

@@ -1,6 +1,6 @@
#include <semiwrap_init.romi._romi.hpp>
#include "semiwrap_init.romi._romi.hpp"
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}
initWrapper(m);
}

View File

@@ -1,7 +1,7 @@
[build-system]
build-backend = "hatchling.build"
requires = [
"hatchling",
"hatchling",
"hatch-robotpy~=0.2.1",
]
@@ -38,4 +38,4 @@ libs = ["halsim_ds_socket"]
[tool.hatch.build.targets.wheel]
packages = ["halsim_ds_socket"]
packages = ["halsim_ds_socket"]

View File

@@ -1,20 +1,19 @@
#include <semiwrap_init.halsim_gui._ext._halsim_gui_ext.hpp>
#include <functional>
#include <wpi/halsim/gui/HALSimGuiExt.hpp>
#include <wpi/hal/Extensions.h>
#include <wpi/halsim/gui/HALSimGuiExt.hpp>
#include "semiwrap_init.halsim_gui._ext._halsim_gui_ext.hpp"
std::function<void()> g_gui_exit;
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
m.def("_kill_on_signal", []() {
HAL_RegisterExtensionListener(
nullptr, [](void *, const char *name, void *data) {
nullptr, [](void*, const char* name, void* data) {
std::string_view name_view{name};
if (name_view == HALSIMGUI_EXT_GUIEXIT) {
g_gui_exit = (halsimgui::GuiExitFn)data;
@@ -23,14 +22,14 @@ SEMIWRAP_PYBIND11_MODULE(m) {
AddGuiLateExecute([] {
py::gil_scoped_acquire gil;
if (PyErr_CheckSignals() == -1) {
// If a python signal has been triggered, the GUI needs to exit. It's
// not safe to throw an exception here on all platforms so we just
// assume that the only eventual caller of this function is HAL_RunMain,
// and our wrapper around that function will check if a python error is
// set and throw from there.
// If a python signal has been triggered, the GUI needs to exit.
// It's not safe to throw an exception here on all platforms so
// we just assume that the only eventual caller of this function
// is HAL_RunMain, and our wrapper around that function will
// check if a python error is set and throw from there.
//
// Reference: https://github.com/wpilibsuite/allwpilib/issues/8528
// Reference:
// https://github.com/wpilibsuite/allwpilib/issues/8528
if (g_gui_exit) {
g_gui_exit();
} else {
@@ -41,4 +40,4 @@ SEMIWRAP_PYBIND11_MODULE(m) {
}
});
});
}
}

View File

@@ -18,8 +18,8 @@ modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY ROBOTPY AND CONTRIBUTORS``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ROBOTPY OR CONTRIBUTORS BE LIABLE FOR
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ROBOTPY OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
@@ -45,12 +45,11 @@ Code for WPILib was derived from code using the following license:
*
* THIS SOFTWARE IS PROVIDED BY FIRST AND CONTRIBUTORS``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR
* WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -24,7 +24,7 @@ classes:
ColorOrder:
inline_code: |
.def("setData", [](wpi::AddressableLED& self, const wpi::AddressableLEDBuffer& data) {
return self.SetData(data);
return self.SetData(data);
}, release_gil(), py::prepend());
wpi::AddressableLED::LEDData:
force_no_trampoline: true

View File

@@ -6,11 +6,11 @@
namespace wpi::impl {
void ResetSmartDashboardInstance();
void ResetMotorSafety();
} // namespace wpi::impl
} // namespace wpi::impl
namespace wpi::util::impl {
void ResetSendableRegistry();
} // namespace wpi::impl
} // namespace wpi::util::impl
void resetWpilibSimulationData() {
wpi::impl::ResetSmartDashboardInstance();

View File

@@ -1,4 +1,6 @@
#include "semiwrap_init.wpilib._wpilib.hpp"
SEMIWRAP_PYBIND11_MODULE(m) { initWrapper(m); }
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}

View File

@@ -4,8 +4,8 @@
#include "rpy/AddressableLEDBuffer.h"
#include <stdexcept>
#include <span>
#include <stdexcept>
namespace wpi {
@@ -21,17 +21,22 @@ void AddressableLEDBuffer::SetLED(size_t index, const wpi::util::Color& color) {
m_buffer.at(index).SetLED(color);
}
void AddressableLEDBuffer::SetLED(size_t index, const wpi::util::Color8Bit& color) {
void AddressableLEDBuffer::SetLED(size_t index,
const wpi::util::Color8Bit& color) {
m_buffer.at(index).SetLED(color);
}
int AddressableLEDBuffer::GetRed(size_t index) const { return m_buffer.at(index).r; }
int AddressableLEDBuffer::GetRed(size_t index) const {
return m_buffer.at(index).r;
}
int AddressableLEDBuffer::GetGreen(size_t index) const {
return m_buffer.at(index).g;
}
int AddressableLEDBuffer::GetBlue(size_t index) const { return m_buffer.at(index).b; }
int AddressableLEDBuffer::GetBlue(size_t index) const {
return m_buffer.at(index).b;
}
wpi::util::Color AddressableLEDBuffer::GetLED(size_t index) const {
const auto& led = m_buffer.at(index);
@@ -64,7 +69,8 @@ void AddressableLEDBuffer::View::SetHSV(size_t index, int h, int s, int v) {
at(index).SetHSV(h, s, v);
}
void AddressableLEDBuffer::View::SetLED(size_t index, const wpi::util::Color& color) {
void AddressableLEDBuffer::View::SetLED(size_t index,
const wpi::util::Color& color) {
at(index).SetLED(color);
}
@@ -81,8 +87,7 @@ AddressableLED::LEDData& AddressableLEDBuffer::View::at(size_t index) {
return m_data[index];
}
AddressableLED::LEDData& AddressableLEDBuffer::View::operator[](
size_t index) {
AddressableLED::LEDData& AddressableLEDBuffer::View::operator[](size_t index) {
return at(index);
}
@@ -105,7 +110,8 @@ wpi::util::Color AddressableLEDBuffer::View::GetLED(size_t index) const {
return wpi::util::Color{led.r / 255.0, led.g / 255.0, led.b / 255.0};
}
wpi::util::Color8Bit AddressableLEDBuffer::View::GetLED8Bit(size_t index) const {
wpi::util::Color8Bit AddressableLEDBuffer::View::GetLED8Bit(
size_t index) const {
const auto& led = at(index);
return wpi::util::Color8Bit{led.r, led.g, led.b};
}

View File

@@ -7,6 +7,7 @@
#include <span>
#include <stdexcept>
#include <vector>
#include "pybind11/pytypes.h"
#include "wpi/hardware/led/AddressableLED.hpp"
#include "wpi/util/Color.hpp"
@@ -151,8 +152,9 @@ class AddressableLEDBuffer {
auto end() { return m_buffer.end(); }
/**
* A view of another addressable LED buffer. Views provide an easy way to split a large LED
* strip into smaller sections that can be animated individually.
* A view of another addressable LED buffer. Views provide an easy way to
* split a large LED strip into smaller sections that can be animated
* individually.
*/
class View {
public:
@@ -251,9 +253,7 @@ class AddressableLEDBuffer {
/**
* Implicit conversion to span of LED data
*/
operator std::span<wpi::AddressableLED::LEDData>() {
return m_data;
}
operator std::span<wpi::AddressableLED::LEDData>() { return m_data; }
/**
* Implicit conversion to span of const LED data
@@ -272,7 +272,8 @@ class AddressableLEDBuffer {
/**
* Creates a read/write view of this buffer.
*
* @param slice the desired slice of the buffer (e.g. 2:4), step must be unspecified or 1
* @param slice the desired slice of the buffer (e.g. 2:4), step must be
* unspecified or 1
* @return View object representing the view
* @throws std::out_of_range if the view would exceed buffer bounds
*/
@@ -282,4 +283,4 @@ class AddressableLEDBuffer {
std::vector<wpi::AddressableLED::LEDData> m_buffer;
};
} // namespace frc
} // namespace wpi

View File

@@ -1,6 +1,8 @@
#pragma once
#include <string>
#include "wpi/util/fs.hpp"
namespace robotpy::filesystem {
@@ -16,8 +18,8 @@ std::string GetOperatingDirectory();
/**
* Obtains the deploy directory of the program, which is the remote location
* the deploy directory is deployed to by default. On the robot, this is
* /home/systemcore/py/deploy. In simulation, it is where the simulation was launched
* from, in the subdirectory "deploy" (`dirname(robot.py)`/deploy).
* /home/systemcore/py/deploy. In simulation, it is where the simulation was
* launched from, in the subdirectory "deploy" (`dirname(robot.py)`/deploy).
*
* @return The result of the operating directory lookup
*/
@@ -28,6 +30,6 @@ fs::path GetOperatingDirectoryFs();
// intended to be used by C++ bindings, returns same as GetDeployDirectory
fs::path GetDeployDirectoryFs();
} // namespace robotpy::filesystem
} // namespace robotpy::filesystem
#include "Filesystem.inc"

View File

@@ -1,5 +1,9 @@
#pragma once
// TODO: this should be in a shared library, but robotpy-build does not support that
// TODO: this should be in a shared library, but robotpy-build does not support
// that
#include <string>
#include <pybind11/eval.h>
#include <semiwrap.h>
@@ -42,13 +46,17 @@ inline std::string GetOperatingDirectory() {
return GetOperatingDirectoryFs().string();
}
inline std::string GetDeployDirectory() { return GetDeployDirectoryFs().string(); }
inline std::string GetDeployDirectory() {
return GetDeployDirectoryFs().string();
}
inline fs::path GetOperatingDirectoryFs() {
static fs::path operatingPath = getMainPath();
return operatingPath;
}
inline fs::path GetDeployDirectoryFs() { return GetOperatingDirectoryFs() / "deploy"; }
inline fs::path GetDeployDirectoryFs() {
return GetOperatingDirectoryFs() / "deploy";
}
} // namespace robotpy::filesystem
} // namespace robotpy::filesystem

View File

@@ -40,7 +40,9 @@ void PyMotorControllerGroup::SetInverted(bool isInverted) {
m_isInverted = isInverted;
}
bool PyMotorControllerGroup::GetInverted() const { return m_isInverted; }
bool PyMotorControllerGroup::GetInverted() const {
return m_isInverted;
}
void PyMotorControllerGroup::Disable() {
for (auto motorController : m_motorControllers) {
@@ -51,6 +53,7 @@ void PyMotorControllerGroup::Disable() {
void PyMotorControllerGroup::InitSendable(wpi::util::SendableBuilder& builder) {
builder.SetSmartDashboardType("Motor Controller");
builder.SetActuator(true);
builder.AddDoubleProperty("Value", [=, this]() { return GetThrottle(); },
[=, this](double value) { SetThrottle(value); });
builder.AddDoubleProperty(
"Value", [=, this]() { return GetThrottle(); },
[=, this](double value) { SetThrottle(value); });
}

View File

@@ -5,9 +5,8 @@
#pragma once
#include <functional>
#include <vector>
#include <memory>
#include <vector>
#include "wpi/hardware/motor/MotorController.hpp"
#include "wpi/util/sendable/Sendable.hpp"
@@ -15,12 +14,14 @@
namespace wpi {
class PyMotorControllerGroup : public wpi::util::Sendable,
public MotorController,
public wpi::util::SendableHelper<PyMotorControllerGroup> {
class PyMotorControllerGroup
: public wpi::util::Sendable,
public MotorController,
public wpi::util::SendableHelper<PyMotorControllerGroup> {
public:
PyMotorControllerGroup(std::vector<std::shared_ptr<wpi::MotorController>> &&args) :
m_motorControllers(args) {}
explicit PyMotorControllerGroup(
std::vector<std::shared_ptr<wpi::MotorController>>&& args)
: m_motorControllers(args) {}
~PyMotorControllerGroup() override = default;
PyMotorControllerGroup(PyMotorControllerGroup&&) = default;
@@ -42,4 +43,4 @@ class PyMotorControllerGroup : public wpi::util::Sendable,
std::vector<std::shared_ptr<wpi::MotorController>> m_motorControllers;
};
} // namespace rpy
} // namespace wpi

View File

@@ -6,15 +6,15 @@
#include <utility>
#include <gilsafe_object.h>
#include <pybind11/functional.h>
#include "wpi/hal/Notifier.hpp"
#include "wpi/hal/Threads.h"
#include "wpi/system/Errors.hpp"
#include "wpi/system/Timer.hpp"
#include "wpi/util/Synchronization.h"
#include <pybind11/functional.h>
#include <gilsafe_object.h>
using namespace wpi;
using namespace pybind11::literals;
@@ -100,14 +100,14 @@ PyNotifier::~PyNotifier() {
}
}
PyNotifier::PyNotifier(PyNotifier &&rhs)
PyNotifier::PyNotifier(PyNotifier&& rhs)
: m_thread(std::move(rhs.m_thread)),
m_notifier(rhs.m_notifier.load()),
m_handler(std::move(rhs.m_handler)) {
rhs.m_notifier = HAL_INVALID_HANDLE;
}
PyNotifier &PyNotifier::operator=(PyNotifier &&rhs) {
PyNotifier& PyNotifier::operator=(PyNotifier&& rhs) {
m_thread = std::move(rhs.m_thread);
m_notifier = rhs.m_notifier.load();
rhs.m_notifier = HAL_INVALID_HANDLE;

View File

@@ -13,12 +13,12 @@
#include <type_traits>
#include <utility>
#include <semiwrap.h>
#include "wpi/hal/Types.h"
#include "wpi/units/time.hpp"
#include "wpi/util/mutex.hpp"
#include <semiwrap.h>
namespace wpi {
class PyNotifier {
@@ -42,8 +42,8 @@ class PyNotifier {
*/
virtual ~PyNotifier();
PyNotifier(PyNotifier &&rhs);
PyNotifier &operator=(PyNotifier &&rhs);
PyNotifier(PyNotifier&& rhs);
PyNotifier& operator=(PyNotifier&& rhs);
/**
* Sets the name of the notifier. Used for debugging purposes only.
@@ -101,7 +101,7 @@ class PyNotifier {
*/
int32_t GetOverrun() const;
private:
private:
// The thread waiting on the HAL alarm
py::object m_thread;
@@ -115,4 +115,4 @@ private:
std::function<void()> m_handler;
};
} // namespace wpi
} // namespace wpi

View File

@@ -1,6 +1,8 @@
#include "SmartDashboardData.h"
#include <memory>
namespace rpy {
//
@@ -10,25 +12,26 @@ namespace rpy {
// All functions here must be called with the GIL held
//
static py::dict &getSmartDashboardData() {
static py::dict& getSmartDashboardData() {
static py::dict data;
return data;
}
void addSmartDashboardData(py::str &key, std::shared_ptr<wpi::util::Sendable> data) {
auto &sdData = getSmartDashboardData();
void addSmartDashboardData(py::str& key,
std::shared_ptr<wpi::util::Sendable> data) {
auto& sdData = getSmartDashboardData();
sdData[key] = py::cast(data);
}
void clearSmartDashboardData() {
auto &sdData = getSmartDashboardData();
auto& sdData = getSmartDashboardData();
if (sdData) {
sdData.clear();
}
}
void destroySmartDashboardData() {
auto &sdData = getSmartDashboardData();
auto& sdData = getSmartDashboardData();
if (sdData) {
sdData.clear();
// force the dictionary to be deleted otherwise it'll crash when libc++
@@ -40,4 +43,4 @@ void destroySmartDashboardData() {
}
}
} // namespace rpy
} // namespace rpy

View File

@@ -1,17 +1,21 @@
#pragma once
#include "wpi/util/sendable/Sendable.hpp"
#include <memory>
#include <semiwrap.h>
#include "wpi/util/sendable/Sendable.hpp"
namespace rpy {
//
// These functions must be called with the GIL held
//
void addSmartDashboardData(py::str &key, std::shared_ptr<wpi::util::Sendable> data);
void addSmartDashboardData(py::str& key,
std::shared_ptr<wpi::util::Sendable> data);
void clearSmartDashboardData();
void destroySmartDashboardData();
} // namespace rpy
} // namespace rpy

View File

@@ -43,7 +43,7 @@ inline_code: |
self->ax = ax;
}
)
.def_property("ay_fpss",
.def_property("ay_fpss",
[](ChassisAccelerations * self) -> wpi::units::feet_per_second_squared_t {
return self->ay;
},
@@ -51,7 +51,7 @@ inline_code: |
self->ay = ay;
}
)
.def_property("alpha_dpss",
.def_property("alpha_dpss",
[](ChassisAccelerations * self) -> wpi::units::degrees_per_second_squared_t {
return self->alpha;
},

View File

@@ -45,7 +45,7 @@ inline_code: |
self->vx = vx;
}
)
.def_property("vy_fps",
.def_property("vy_fps",
[](ChassisVelocities * self) -> wpi::units::feet_per_second_t {
return self->vy;
},
@@ -53,7 +53,7 @@ inline_code: |
self->vy = vy;
}
)
.def_property("omega_dps",
.def_property("omega_dps",
[](ChassisVelocities * self) -> wpi::units::degrees_per_second_t {
return self->omega;
},

View File

@@ -36,7 +36,7 @@ inline_code: |
self->left = left;
}
)
.def_property("right_fpss",
.def_property("right_fpss",
[](DifferentialDriveWheelAccelerations * self) -> wpi::units::feet_per_second_squared_t {
return self->right;
},

View File

@@ -35,7 +35,7 @@ inline_code: |
self->left = left;
}
)
.def_property("right_fps",
.def_property("right_fps",
[](DifferentialDriveWheelVelocities * self) -> wpi::units::feet_per_second_t {
return self->right;
},
@@ -50,4 +50,3 @@ inline_code: |
;
SetupWPyStruct<wpi::math::DifferentialDriveWheelVelocities>(cls_DifferentialDriveWheelVelocities);

View File

@@ -29,9 +29,9 @@ inline_code: |
>(),
py::arg("frontLeft") = 0, py::arg("frontRight") = 0, py::arg("rearLeft") = 0, py::arg("rearRight") = 0
)
.def_static("fromFps", [](wpi::units::feet_per_second_squared_t frontLeft,
wpi::units::feet_per_second_squared_t frontRight,
wpi::units::feet_per_second_squared_t rearLeft,
.def_static("fromFps", [](wpi::units::feet_per_second_squared_t frontLeft,
wpi::units::feet_per_second_squared_t frontRight,
wpi::units::feet_per_second_squared_t rearLeft,
wpi::units::feet_per_second_squared_t rearRight){
return MecanumDriveWheelAccelerations{frontLeft, frontRight, rearLeft, rearRight};
}, py::arg("frontLeft") = 0, py::arg("frontRight") = 0, py::arg("rearLeft") = 0, py::arg("rearRight") = 0)
@@ -43,7 +43,7 @@ inline_code: |
self->frontLeft = frontLeft;
}
)
.def_property("front_right_fpss",
.def_property("front_right_fpss",
[](MecanumDriveWheelAccelerations * self) -> wpi::units::feet_per_second_squared_t {
return self->frontRight;
},
@@ -59,7 +59,7 @@ inline_code: |
self->rearLeft = rearLeft;
}
)
.def_property("rear_right_fpss",
.def_property("rear_right_fpss",
[](MecanumDriveWheelAccelerations * self) -> wpi::units::feet_per_second_squared_t {
return self->rearRight;
},

View File

@@ -46,7 +46,7 @@ inline_code: |
self->frontLeft = fps;
}
)
.def_property("frontRight_fps",
.def_property("frontRight_fps",
[](MecanumDriveWheelVelocities * self) -> wpi::units::feet_per_second_t {
return self->frontRight;
},
@@ -62,7 +62,7 @@ inline_code: |
self->rearLeft = fps;
}
)
.def_property("rearRight_fps",
.def_property("rearRight_fps",
[](MecanumDriveWheelVelocities * self) -> wpi::units::feet_per_second_t {
return self->rearRight;
},

View File

@@ -41,7 +41,7 @@ inline_code: |-
"\n"
":param kinematics: The swerve drive kinematics.")
)
.def("setKinematics", static_cast<void (wpi::math::TrajectoryConfig::*)(wpi::math::SwerveDriveKinematics<3>&)>(
&wpi::math::TrajectoryConfig::SetKinematics<3>),
py::arg("kinematics"), release_gil(), py::doc(
@@ -50,7 +50,7 @@ inline_code: |-
"\n"
":param kinematics: The swerve drive kinematics.")
)
.def("setKinematics", static_cast<void (wpi::math::TrajectoryConfig::*)(wpi::math::SwerveDriveKinematics<4>&)>(
&wpi::math::TrajectoryConfig::SetKinematics<4>),
py::arg("kinematics"), release_gil(), py::doc(
@@ -59,7 +59,7 @@ inline_code: |-
"\n"
":param kinematics: The swerve drive kinematics.")
)
.def("setKinematics", static_cast<void (wpi::math::TrajectoryConfig::*)(wpi::math::SwerveDriveKinematics<6>&)>(
&wpi::math::TrajectoryConfig::SetKinematics<6>),
py::arg("kinematics"), release_gil(), py::doc(

View File

@@ -19,4 +19,3 @@ classes:
- [CubicHermiteSpline]
- [QuinticHermiteSpline]
SetErrorHandler:

View File

@@ -22,7 +22,7 @@ inline_code: |
.def_static("fromFeet", [](wpi::units::foot_t dx, wpi::units::foot_t dy, wpi::units::radian_t dtheta){
return Twist2d{dx, dy, dtheta};
}, py::arg("dx") = 0, py::arg("dy") = 0, py::arg("dtheta") = 0)
.def_property("dx_feet",
.def_property("dx_feet",
[](Twist2d * self) -> wpi::units::foot_t {
return self->dx;
},
@@ -30,7 +30,7 @@ inline_code: |
self->dx = dx;
}
)
.def_property("dy_feet",
.def_property("dy_feet",
[](Twist2d * self) -> wpi::units::foot_t {
return self->dy;
},
@@ -38,7 +38,7 @@ inline_code: |
self->dy = dy;
}
)
.def_property("dtheta_degrees",
.def_property("dtheta_degrees",
[](Twist2d * self) -> wpi::units::degree_t {
return self->dtheta;
},

View File

@@ -30,7 +30,7 @@ inline_code: |-
},
py::arg("dx") = 0, py::arg("dy") = 0, py::arg("dz") = 0,
py::arg("rx") = 0, py::arg("ry") = 0, py::arg("rz") = 0)
.def_property("dx_feet",
.def_property("dx_feet",
[](Twist3d * self) -> wpi::units::foot_t {
return self->dx;
},
@@ -38,7 +38,7 @@ inline_code: |-
self->dx = dx;
}
)
.def_property("dy_feet",
.def_property("dy_feet",
[](Twist3d * self) -> wpi::units::foot_t {
return self->dy;
},
@@ -46,7 +46,7 @@ inline_code: |-
self->dy = dy;
}
)
.def_property("dz_feet",
.def_property("dz_feet",
[](Twist3d * self) -> wpi::units::foot_t {
return self->dz;
},
@@ -54,7 +54,7 @@ inline_code: |-
self->dz = dz;
}
)
.def_property("rx_degrees",
.def_property("rx_degrees",
[](Twist3d * self) -> wpi::units::degree_t {
return self->rx;
},
@@ -62,7 +62,7 @@ inline_code: |-
self->rx = rx;
}
)
.def_property("ry_degrees",
.def_property("ry_degrees",
[](Twist3d * self) -> wpi::units::degree_t {
return self->ry;
},
@@ -70,7 +70,7 @@ inline_code: |-
self->ry = ry;
}
)
.def_property("rz_degrees",
.def_property("rz_degrees",
[](Twist3d * self) -> wpi::units::degree_t {
return self->rz;
},

View File

@@ -1,37 +1,43 @@
#pragma once
#include "wpi/math/trajectory/constraint/TrajectoryConstraint.hpp"
#include <memory>
#include <utility>
#include <semiwrap.h>
#include "wpi/math/trajectory/constraint/TrajectoryConstraint.hpp"
namespace wpi::math {
struct PyTrajectoryConstraint : public TrajectoryConstraint {
PyTrajectoryConstraint() {}
wpi::units::meters_per_second_t
MaxVelocity(const Pose2d &pose, wpi::units::curvature_t curvature,
wpi::units::meters_per_second_t velocity) const override {
wpi::units::meters_per_second_t MaxVelocity(
const Pose2d& pose, wpi::units::curvature_t curvature,
wpi::units::meters_per_second_t velocity) const override {
return m_constraint->MaxVelocity(pose, curvature, velocity);
}
MinMax MinMaxAcceleration(const Pose2d &pose, wpi::units::curvature_t curvature,
wpi::units::meters_per_second_t velocity) const override {
MinMax MinMaxAcceleration(
const Pose2d& pose, wpi::units::curvature_t curvature,
wpi::units::meters_per_second_t velocity) const override {
return m_constraint->MinMaxAcceleration(pose, curvature, velocity);
}
std::shared_ptr<TrajectoryConstraint> m_constraint;
};
}; // namespace wpi::math
}; // namespace wpi::math
namespace pybind11 {
namespace detail {
namespace pybind11::detail {
template <> struct type_caster<wpi::math::PyTrajectoryConstraint> {
using value_conv = make_caster<std::shared_ptr<wpi::math::TrajectoryConstraint>>;
template <>
struct type_caster<wpi::math::PyTrajectoryConstraint> {
using value_conv =
make_caster<std::shared_ptr<wpi::math::TrajectoryConstraint>>;
PYBIND11_TYPE_CASTER(wpi::math::PyTrajectoryConstraint, _("wpimath._wpimath.TrajectoryConstraint"));
PYBIND11_TYPE_CASTER(wpi::math::PyTrajectoryConstraint,
_("wpimath._wpimath.TrajectoryConstraint"));
bool load(handle src, bool convert) {
value_conv conv;
@@ -40,15 +46,15 @@ template <> struct type_caster<wpi::math::PyTrajectoryConstraint> {
}
value.m_constraint =
cast_op<std::shared_ptr<wpi::math::TrajectoryConstraint>>(std::move(conv));
cast_op<std::shared_ptr<wpi::math::TrajectoryConstraint>>(
std::move(conv));
return true;
}
static handle cast(const wpi::math::PyTrajectoryConstraint &src,
static handle cast(const wpi::math::PyTrajectoryConstraint& src,
return_value_policy policy, handle parent) {
return value_conv::cast(src.m_constraint, policy, parent);
}
};
}; // namespace detail
}; // namespace pybind11
} // namespace pybind11::detail

View File

@@ -1,3 +1,5 @@
#pragma once
#include <string>
#include "wpi/math/geometry/Ellipse2d.hpp"
@@ -11,11 +13,11 @@
namespace rpy {
inline std::string toString(const wpi::math::Rotation2d &self) {
inline std::string toString(const wpi::math::Rotation2d& self) {
return "Rotation2d(" + std::to_string(self.Radians()()) + ")";
}
inline std::string toString(const wpi::math::Rotation3d &self) {
inline std::string toString(const wpi::math::Rotation3d& self) {
return "Rotation3d("
"x=" +
std::to_string(self.X()()) +
@@ -27,7 +29,7 @@ inline std::string toString(const wpi::math::Rotation3d &self) {
std::to_string(self.Z()()) + ")";
}
inline std::string toString(const wpi::math::Translation2d &self) {
inline std::string toString(const wpi::math::Translation2d& self) {
return "Translation2d("
"x=" +
std::to_string(self.X()()) +
@@ -36,7 +38,7 @@ inline std::string toString(const wpi::math::Translation2d &self) {
std::to_string(self.Y()()) + ")";
}
inline std::string toString(const wpi::math::Translation3d &self) {
inline std::string toString(const wpi::math::Translation3d& self) {
return "Translation3d("
"x=" +
std::to_string(self.X()()) +
@@ -48,7 +50,7 @@ inline std::string toString(const wpi::math::Translation3d &self) {
std::to_string(self.Z()()) + ")";
}
inline std::string toString(const wpi::math::Quaternion &self) {
inline std::string toString(const wpi::math::Quaternion& self) {
return "Quaternion("
"w=" +
std::to_string(self.W()) +
@@ -63,37 +65,36 @@ inline std::string toString(const wpi::math::Quaternion &self) {
std::to_string(self.Z()) + ")";
}
inline std::string toString(const wpi::math::Transform2d &self) {
inline std::string toString(const wpi::math::Transform2d& self) {
return "Transform2d(" + rpy::toString(self.Translation()) + ", " +
rpy::toString(self.Rotation()) + ")";
}
inline std::string toString(const wpi::math::Transform3d &self) {
inline std::string toString(const wpi::math::Transform3d& self) {
return "Transform3d(" + rpy::toString(self.Translation()) + ", " +
rpy::toString(self.Rotation()) + ")";
}
inline std::string toString(const wpi::math::Pose2d &self) {
inline std::string toString(const wpi::math::Pose2d& self) {
return "Pose2d(" + rpy::toString(self.Translation()) + ", " +
rpy::toString(self.Rotation()) + ")";
}
inline std::string toString(const wpi::math::Pose3d &self) {
inline std::string toString(const wpi::math::Pose3d& self) {
return "Pose3d(" + rpy::toString(self.Translation()) + ", " +
rpy::toString(self.Rotation()) + ")";
}
inline std::string toString(const wpi::math::Rectangle2d &self) {
inline std::string toString(const wpi::math::Rectangle2d& self) {
return "Rectangle2d(center=" + rpy::toString(self.Center()) +
", xWidth=" + std::to_string(self.XWidth()()) +
", yWidth=" + std::to_string(self.YWidth()()) + ")";
", xWidth=" + std::to_string(self.XWidth()()) +
", yWidth=" + std::to_string(self.YWidth()()) + ")";
}
inline std::string toString(const wpi::math::Ellipse2d &self) {
inline std::string toString(const wpi::math::Ellipse2d& self) {
return "Ellipse2d(center=" + rpy::toString(self.Center()) +
", xSemiAxis=" + std::to_string(self.XSemiAxis()()) +
", ySemiAxis=" + std::to_string(self.YSemiAxis()()) + ")";
", xSemiAxis=" + std::to_string(self.XSemiAxis()()) +
", ySemiAxis=" + std::to_string(self.YSemiAxis()()) + ")";
}
} // namespace rpy
} // namespace rpy

View File

@@ -1,4 +1,6 @@
#include "semiwrap_init.wpimath._wpimath.hpp"
SEMIWRAP_PYBIND11_MODULE(m) { initWrapper(m); }
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}

View File

@@ -1,24 +1,24 @@
#pragma once
#include "wpi/units/time.hpp"
#include "wpi/units/length.hpp"
#include "wpi/units/time.hpp"
struct SomeClass {
static constexpr auto s_constant = 2_s;
static constexpr auto ms_constant1 = 20_ms;
static constexpr wpi::units::second_t ms_constant2 = 50_ms;
static constexpr wpi::units::millisecond_t ms_constant3 = 0.20_s;
static constexpr auto s_constant = 2_s;
static constexpr auto ms_constant1 = 20_ms;
static constexpr wpi::units::second_t ms_constant2 = 50_ms;
static constexpr wpi::units::millisecond_t ms_constant3 = 0.20_s;
bool checkDefaultByName1(wpi::units::second_t period = ms_constant1);
bool checkDefaultByName2(wpi::units::second_t period = ms_constant2);
bool checkDefaultByNum1(wpi::units::second_t period = 50_ms);
bool checkDefaultByNum2(wpi::units::second_t period = 0.5_s);
bool checkDefaultByName1(wpi::units::second_t period = ms_constant1);
bool checkDefaultByName2(wpi::units::second_t period = ms_constant2);
bool checkDefaultByNum1(wpi::units::second_t period = 50_ms);
bool checkDefaultByNum2(wpi::units::second_t period = 0.5_s);
wpi::units::second_t ms2s(wpi::units::millisecond_t ms);
wpi::units::millisecond_t s2ms(wpi::units::second_t s);
wpi::units::second_t ms2s(wpi::units::millisecond_t ms);
wpi::units::millisecond_t s2ms(wpi::units::second_t s);
static constexpr wpi::units::foot_t five_ft = 5_ft;
static constexpr wpi::units::foot_t five_ft = 5_ft;
wpi::units::meter_t ft2m(wpi::units::foot_t f);
};
wpi::units::meter_t ft2m(wpi::units::foot_t f);
};

View File

@@ -1,53 +1,50 @@
#include "semiwrap_init.wpimath_test._wpimath_test.hpp"
#include <module.h>
#include <stdexcept>
SEMIWRAP_PYBIND11_MODULE(m)
{
initWrapper(m);
#include <module.h>
#include "semiwrap_init.wpimath_test._wpimath_test.hpp"
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}
bool SomeClass::checkDefaultByName1(wpi::units::second_t period)
{
if (period != SomeClass::ms_constant1) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
bool SomeClass::checkDefaultByName1(wpi::units::second_t period) {
if (period != SomeClass::ms_constant1) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
}
bool SomeClass::checkDefaultByName2(wpi::units::second_t period)
{
if (period != SomeClass::ms_constant2) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
bool SomeClass::checkDefaultByName2(wpi::units::second_t period) {
if (period != SomeClass::ms_constant2) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
}
bool SomeClass::checkDefaultByNum1(wpi::units::second_t period)
{
if (period != 50_ms) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
bool SomeClass::checkDefaultByNum1(wpi::units::second_t period) {
if (period != 50_ms) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
}
bool SomeClass::checkDefaultByNum2(wpi::units::second_t period)
{
if (period != 50_ms) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
bool SomeClass::checkDefaultByNum2(wpi::units::second_t period) {
if (period != 50_ms) {
throw std::runtime_error(wpi::units::to_string(period));
}
return true;
}
wpi::units::meter_t SomeClass::ft2m(wpi::units::foot_t f) {
return f;
return f;
}
wpi::units::second_t SomeClass::ms2s(wpi::units::millisecond_t ms) {
return ms;
return ms;
}
wpi::units::millisecond_t SomeClass::s2ms(wpi::units::second_t s) {
return s;
return s;
}

View File

@@ -1,4 +1,6 @@
#include <semiwrap_init.wpinet._wpinet.hpp>
#include "semiwrap_init.wpinet._wpinet.hpp"
SEMIWRAP_PYBIND11_MODULE(m) { initWrapper(m); }
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}

View File

@@ -1,3 +1,2 @@
defaults:
ignore: true

View File

@@ -1,5 +1,5 @@
#include <semiwrap_init.wpiutil._wpiutil.hpp>
#include "semiwrap_init.wpiutil._wpiutil.hpp"
void setup_stack_trace_hook(py::object fn);
void cleanup_stack_trace_hook();
@@ -14,7 +14,7 @@ void cleanup_now_impl();
namespace wpi::util::impl {
void ResetSendableRegistry();
} // namespace wpi::util::impl
} // namespace wpi::util::impl
void cleanup_sendable_registry() {
py::gil_scoped_release unlock;
@@ -31,7 +31,7 @@ SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
static int unused;
py::capsule cleanup(&unused, [](void *) {
py::capsule cleanup(&unused, [](void*) {
cleanup_sendable_registry();
cleanup_stack_trace_hook();
cleanup_safethread_gil();

View File

@@ -1,29 +1,30 @@
#include <atomic>
#include <gilsafe_object.h>
#include <semiwrap.h>
using OnThreadStartFn = void *(*)();
using OnThreadEndFn = void (*)(void *);
using OnThreadStartFn = void* (*)();
using OnThreadEndFn = void (*)(void*);
namespace wpi::util::impl {
void SetSafeThreadNotifiers(OnThreadStartFn OnStart, OnThreadEndFn OnEnd);
}
struct SafeThreadState {
py::gil_scoped_acquire *acquire = nullptr;
py::gil_scoped_release *release = nullptr;
py::gil_scoped_acquire* acquire = nullptr;
py::gil_scoped_release* release = nullptr;
};
std::atomic<bool> g_gilstate_managed = false;
void *on_safe_thread_start() {
if (Py_IsFinalizing() // python is shutting down
|| !g_gilstate_managed.load() // python has shutdown)
void* on_safe_thread_start() {
if (Py_IsFinalizing() // python is shutting down
|| !g_gilstate_managed.load() // python has shutdown)
) {
return nullptr;
}
auto *st = new SafeThreadState;
auto* st = new SafeThreadState;
// acquires the GIL and creates pybind11's thread state for this thread
st->acquire = new py::gil_scoped_acquire;
@@ -33,20 +34,20 @@ void *on_safe_thread_start() {
return st;
}
void on_safe_thread_end(void *opaque) {
void on_safe_thread_end(void* opaque) {
// on entry, GIL should not be acquired
// don't cleanup if it's unsafe to do so. Several possibilities here:
if (!opaque // internal error?
|| Py_IsFinalizing() // python is shutting down
|| !g_gilstate_managed.load() // python has shutdown
if (!opaque // internal error?
|| Py_IsFinalizing() // python is shutting down
|| !g_gilstate_managed.load() // python has shutdown
) {
return;
}
auto *st = (SafeThreadState *)opaque;
delete st->release; // causes GIL to be acquired
delete st->acquire; // causes GIL to be released and thread state deleted
auto* st = reinterpret_cast<SafeThreadState*>(opaque);
delete st->release; // causes GIL to be acquired
delete st->acquire; // causes GIL to be released and thread state deleted
delete st;
}
@@ -59,7 +60,10 @@ void setup_safethread_gil() {
atexit.attr("register")(
py::cpp_function([]() { g_gilstate_managed = false; }));
wpi::util::impl::SetSafeThreadNotifiers(on_safe_thread_start, on_safe_thread_end);
wpi::util::impl::SetSafeThreadNotifiers(on_safe_thread_start,
on_safe_thread_end);
}
void cleanup_safethread_gil() { g_gilstate_managed = false; }
void cleanup_safethread_gil() {
g_gilstate_managed = false;
}

View File

@@ -1,14 +1,18 @@
#include <string>
#include <semiwrap.h>
#include "wpi/util/StackTrace.hpp"
py::object &get_hook_ref() {
py::object& get_hook_ref() {
static py::object hook;
return hook;
}
std::string final_py_stack_trace_hook(int offset) {
std::string msg = "\tat <python stack trace not available due to interpreter shutdown>\n";
std::string msg =
"\tat <python stack trace not available due to interpreter shutdown>\n";
msg += wpi::util::GetStackTraceDefault(offset);
return msg;
}
@@ -17,11 +21,11 @@ std::string py_stack_trace_hook(int offset) {
py::gil_scoped_acquire gil;
try {
auto &hook = get_hook_ref();
auto& hook = get_hook_ref();
if (hook) {
return py::cast<std::string>(hook(offset));
}
} catch (py::error_already_set &e) {
} catch (py::error_already_set& e) {
e.discard_as_unraisable("wpiutil._stacktrace._stack_trace_hook");
}
@@ -37,9 +41,9 @@ void cleanup_stack_trace_hook() {
wpi::util::SetGetStackTraceImpl(final_py_stack_trace_hook);
// release the function during interpreter shutdown
auto &hook = get_hook_ref();
auto& hook = get_hook_ref();
if (hook) {
hook.dec_ref();
hook.release();
}
}
}

View File

@@ -1,11 +1,11 @@
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include "wpi/util/timestamp.hpp"
#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
namespace py = pybind11;
py::object &get_now_impl_ref() {
py::object& get_now_impl_ref() {
static py::object get_now_impl_ref;
return get_now_impl_ref;
}
@@ -14,11 +14,11 @@ py::object &get_now_impl_ref() {
uint64_t now_impl_trampoline() {
py::gil_scoped_acquire acquire;
try {
auto &hook = get_now_impl_ref();
auto& hook = get_now_impl_ref();
if (hook) {
return hook().cast<uint64_t>();
}
} catch (py::error_already_set &e) {
} catch (py::error_already_set& e) {
e.discard_as_unraisable("wpiutil.now_impl_trampoline");
}
@@ -26,21 +26,21 @@ uint64_t now_impl_trampoline() {
}
void set_now_impl(py::object func) {
get_now_impl_ref() = func;
if (func.is_none()) {
wpi::util::SetNowImpl(nullptr);
} else {
wpi::util::SetNowImpl(&now_impl_trampoline);
}
get_now_impl_ref() = func;
if (func.is_none()) {
wpi::util::SetNowImpl(nullptr);
} else {
wpi::util::SetNowImpl(&now_impl_trampoline);
}
}
void cleanup_now_impl() {
wpi::util::SetNowImpl(nullptr);
// release the function during interpreter shutdown
auto &hook = get_now_impl_ref();
auto& hook = get_now_impl_ref();
if (hook) {
hook.dec_ref();
hook.release();
}
}
}

View File

@@ -3,17 +3,18 @@
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <fmt/format.h>
#include "wpi/util/struct/Struct.hpp"
#include <pybind11/functional.h>
#include <pybind11/typing.h>
#include <semiwrap.h>
static inline std::string pytypename(const py::type &t) {
return ((PyTypeObject *)t.ptr())->tp_name;
#include "wpi/util/struct/Struct.hpp"
static inline std::string pytypename(const py::type& t) {
return (reinterpret_cast<PyTypeObject*>(t.ptr()))->tp_name;
}
//
@@ -23,15 +24,14 @@ static inline std::string pytypename(const py::type &t) {
// This merely holds the python object being operated on, the actual
// serialization work is done in WPyStructConverter
struct WPyStruct {
WPyStruct() = default;
WPyStruct(const WPyStruct &other) {
WPyStruct(const WPyStruct& other) {
py::gil_scoped_acquire gil;
py = other.py;
}
WPyStruct &operator=(const WPyStruct &other) {
WPyStruct& operator=(const WPyStruct& other) {
{
py::gil_scoped_acquire gil;
py = other.py;
@@ -39,9 +39,9 @@ struct WPyStruct {
return *this;
}
WPyStruct(WPyStruct &&) = default;
WPyStruct(WPyStruct&&) = default;
WPyStruct(const py::object &py) : py(py) {}
explicit WPyStruct(const py::object& py) : py(py) {}
~WPyStruct() {
py::gil_scoped_acquire gil;
@@ -51,10 +51,10 @@ struct WPyStruct {
py::object py;
};
namespace pybind11 {
namespace detail {
namespace pybind11::detail {
template <> struct type_caster<WPyStruct> {
template <>
struct type_caster<WPyStruct> {
// TODO: wpiutil.struct.T/TV?
PYBIND11_TYPE_CASTER(WPyStruct, const_name("object"));
@@ -64,7 +64,7 @@ template <> struct type_caster<WPyStruct> {
return true;
}
static handle cast(const WPyStruct &src, py::return_value_policy policy,
static handle cast(const WPyStruct& src, py::return_value_policy policy,
py::handle parent) {
py::handle v = src.py;
v.inc_ref();
@@ -72,8 +72,7 @@ template <> struct type_caster<WPyStruct> {
}
};
} // namespace detail
} // namespace pybind11
} // namespace pybind11::detail
//
// Struct info class implementation
@@ -88,7 +87,7 @@ struct WPyStructConverter {
virtual std::string_view GetSchema() const = 0;
virtual void Pack(std::span<uint8_t> data, const WPyStruct &value) const = 0;
virtual void Pack(std::span<uint8_t> data, const WPyStruct& value) const = 0;
virtual WPyStruct Unpack(std::span<const uint8_t> data) const = 0;
@@ -96,12 +95,13 @@ struct WPyStructConverter {
// std::span<const uint8_t> data) const = 0;
virtual void ForEachNested(
const std::function<void(std::string_view, std::string_view)> &fn)
const std::function<void(std::string_view, std::string_view)>& fn)
const = 0;
};
// static C++ converter
template <typename T> struct WPyStructCppConverter : WPyStructConverter {
template <typename T>
struct WPyStructCppConverter : WPyStructConverter {
std::string_view GetTypeName() const override {
return wpi::util::Struct<T>::GetTypeName();
}
@@ -112,9 +112,9 @@ template <typename T> struct WPyStructCppConverter : WPyStructConverter {
return wpi::util::Struct<T>::GetSchema();
}
void Pack(std::span<uint8_t> data, const WPyStruct &value) const override {
void Pack(std::span<uint8_t> data, const WPyStruct& value) const override {
py::gil_scoped_acquire gil;
const T &v = value.py.cast<const T &>();
const T& v = value.py.cast<const T&>();
wpi::util::Struct<T>::Pack(data, v);
}
@@ -131,7 +131,7 @@ template <typename T> struct WPyStructCppConverter : WPyStructConverter {
// }
void ForEachNested(
const std::function<void(std::string_view, std::string_view)> &fn)
const std::function<void(std::string_view, std::string_view)>& fn)
const override {
if constexpr (wpi::util::HasNestedStruct<T>) {
wpi::util::Struct<T>::ForEachNested(fn);
@@ -139,13 +139,13 @@ template <typename T> struct WPyStructCppConverter : WPyStructConverter {
}
};
template <typename T> void SetupWPyStruct(auto pycls) {
auto *sptr =
template <typename T>
void SetupWPyStruct(auto pycls) {
auto* sptr =
new std::shared_ptr<WPyStructConverter>(new WPyStructCppConverter<T>());
py::capsule c(sptr, "WPyStruct", [](void *ptr) {
delete (std::shared_ptr<WPyStructConverter> *)ptr;
py::capsule c(sptr, "WPyStruct", [](void* ptr) {
delete (std::shared_ptr<WPyStructConverter>*)ptr;
});
pycls.def_property_readonly_static("WPIStruct",
@@ -154,8 +154,7 @@ template <typename T> void SetupWPyStruct(auto pycls) {
// dynamic python converter
struct WPyStructPyConverter : WPyStructConverter {
WPyStructPyConverter(py::object o) {
explicit WPyStructPyConverter(py::object o) {
m_typename = o.attr("typename").cast<std::string>();
m_schema = o.attr("schema").cast<std::string>();
m_size = o.attr("size").cast<size_t>();
@@ -163,7 +162,8 @@ struct WPyStructPyConverter : WPyStructConverter {
m_pack = py::reinterpret_borrow<py::function>(o.attr("pack"));
m_packInto = py::reinterpret_borrow<py::function>(o.attr("packInto"));
m_unpack = py::reinterpret_borrow<py::function>(o.attr("unpack"));
// m_unpackInto = py::reinterpret_borrow<py::function>(o.attr("unpackInto"));
// m_unpackInto =
// py::reinterpret_borrow<py::function>(o.attr("unpackInto"));
m_forEachNested =
py::reinterpret_borrow<py::function>(o.attr("forEachNested"));
}
@@ -177,7 +177,7 @@ struct WPyStructPyConverter : WPyStructConverter {
py::function m_packInto;
py::function m_unpack;
// py::function m_unpackInto;
py::function m_forEachNested; // might be none
py::function m_forEachNested; // might be none
std::string_view GetTypeName() const override { return m_typename; }
@@ -185,7 +185,7 @@ struct WPyStructPyConverter : WPyStructConverter {
std::string_view GetSchema() const override { return m_schema; }
void Pack(std::span<uint8_t> data, const WPyStruct &value) const override {
void Pack(std::span<uint8_t> data, const WPyStruct& value) const override {
py::gil_scoped_acquire gil;
py::bytes result = m_pack(value.py);
std::string_view rview = result;
@@ -196,13 +196,13 @@ struct WPyStructPyConverter : WPyStructConverter {
throw py::value_error(msg);
}
rview.copy((char *)data.data(), rview.size());
rview.copy(reinterpret_cast<char*>(data.data()), rview.size());
}
WPyStruct Unpack(std::span<const uint8_t> data) const override {
py::gil_scoped_acquire gil;
auto view =
py::memoryview::from_memory((const void *)data.data(), data.size());
py::memoryview::from_memory((const void*)data.data(), data.size());
return WPyStruct(m_unpack(view));
}
@@ -215,7 +215,7 @@ struct WPyStructPyConverter : WPyStructConverter {
// }
void ForEachNested(
const std::function<void(std::string_view, std::string_view)> &fn)
const std::function<void(std::string_view, std::string_view)>& fn)
const override {
py::gil_scoped_acquire gil;
if (!m_forEachNested.is_none()) {
@@ -227,9 +227,8 @@ struct WPyStructPyConverter : WPyStructConverter {
// passed as I... to the wpi::util::Struct methods
struct WPyStructInfo {
WPyStructInfo() = default;
WPyStructInfo(const py::type &t) {
explicit WPyStructInfo(const py::type& t) {
if (!py::hasattr(t, "WPIStruct")) {
throw py::type_error(
fmt::format("{} is not struct serializable (does not have WPIStruct)",
pytypename(t)));
@@ -238,9 +237,9 @@ struct WPyStructInfo {
py::object s = t.attr("WPIStruct");
// C++ version
void *c = PyCapsule_GetPointer(s.ptr(), "WPyStruct");
void* c = PyCapsule_GetPointer(s.ptr(), "WPyStruct");
if (c != NULL) {
cvt = *(std::shared_ptr<WPyStructConverter> *)c;
cvt = *(std::shared_ptr<WPyStructConverter>*)c;
return;
}
@@ -249,7 +248,7 @@ struct WPyStructInfo {
// Python version
try {
cvt = std::make_shared<WPyStructPyConverter>(s);
} catch (py::error_already_set &e) {
} catch (py::error_already_set& e) {
std::string msg = fmt::format(
"{} is not struct serializable (invalid WPIStruct)", pytypename(t));
py::raise_from(e, PyExc_TypeError, msg.c_str());
@@ -257,10 +256,11 @@ struct WPyStructInfo {
}
}
WPyStructInfo(const WPyStruct &v) : WPyStructInfo(py::type::of(v.py)) {}
explicit WPyStructInfo(const WPyStruct& v)
: WPyStructInfo(py::type::of(v.py)) {}
const WPyStructConverter* operator->() const {
const auto *c = cvt.get();
const auto* c = cvt.get();
if (c == nullptr) {
// TODO: would be nice to have a better error here, but we don't have
// a good way to know our current context
@@ -269,27 +269,26 @@ struct WPyStructInfo {
return c;
}
private:
private:
// holds something used to do serialization
std::shared_ptr<WPyStructConverter> cvt;
};
// Leverages the converter stored in WPyStructInfo to do the actual work
template <> struct wpi::util::Struct<WPyStruct, WPyStructInfo> {
static std::string_view GetTypeName(const WPyStructInfo &info) {
template <>
struct wpi::util::Struct<WPyStruct, WPyStructInfo> {
static std::string_view GetTypeName(const WPyStructInfo& info) {
return info->GetTypeName();
}
static size_t GetSize(const WPyStructInfo &info) {
return info->GetSize();
}
static size_t GetSize(const WPyStructInfo& info) { return info->GetSize(); }
static std::string_view GetSchema(const WPyStructInfo &info) {
static std::string_view GetSchema(const WPyStructInfo& info) {
return info->GetSchema();
}
static WPyStruct Unpack(std::span<const uint8_t> data,
const WPyStructInfo &info) {
const WPyStructInfo& info) {
return info->Unpack(data);
}
@@ -298,14 +297,14 @@ template <> struct wpi::util::Struct<WPyStruct, WPyStructInfo> {
// info->UnpackInto(v, data);
// }
static void Pack(std::span<uint8_t> data, const WPyStruct &value,
const WPyStructInfo &info) {
static void Pack(std::span<uint8_t> data, const WPyStruct& value,
const WPyStructInfo& info) {
info->Pack(data, value);
}
static void
ForEachNested(std::invocable<std::string_view, std::string_view> auto fn,
const WPyStructInfo &info) {
static void ForEachNested(
std::invocable<std::string_view, std::string_view> auto fn,
const WPyStructInfo& info) {
info->ForEachNested(fn);
}
};
@@ -314,4 +313,5 @@ static_assert(wpi::util::StructSerializable<WPyStruct, WPyStructInfo>);
static_assert(wpi::util::HasNestedStruct<WPyStruct, WPyStructInfo>);
// This breaks on readonly structs, so we disable for now
// static_assert(wpi::util::MutableStructSerializable<WPyStruct, WPyStructInfo>);
// static_assert(wpi::util::MutableStructSerializable<WPyStruct,
// WPyStructInfo>);

View File

@@ -1,51 +1,53 @@
#include "wpystruct_fns.h"
#include "wpystruct.h"
void forEachNested(
const py::type &t,
const std::function<void(std::string_view, std::string_view)> &fn) {
const py::type& t,
const std::function<void(std::string_view, std::string_view)>& fn) {
WPyStructInfo info(t);
wpi::util::ForEachStructSchema<WPyStruct, WPyStructInfo>(fn, info);
}
py::str getTypeName(const py::type &t) {
py::str getTypeName(const py::type& t) {
WPyStructInfo info(t);
return wpi::util::GetStructTypeName<WPyStruct, WPyStructInfo>(info);
}
py::str getSchema(const py::type &t) {
py::str getSchema(const py::type& t) {
WPyStructInfo info(t);
return wpi::util::GetStructSchema<WPyStruct, WPyStructInfo>(info);
}
size_t getSize(const py::type &t) {
size_t getSize(const py::type& t) {
WPyStructInfo info(t);
return wpi::util::GetStructSize<WPyStruct>(info);
}
py::bytes pack(const WPyStruct &v) {
py::bytes pack(const WPyStruct& v) {
WPyStructInfo info(v);
auto sz = wpi::util::GetStructSize<WPyStruct>(info);
PyObject *b = PyBytes_FromStringAndSize(NULL, sz);
PyObject* b = PyBytes_FromStringAndSize(NULL, sz);
if (b == NULL) {
throw py::error_already_set();
}
char *pybuf;
char* pybuf;
py::ssize_t pysz;
if (PyBytes_AsStringAndSize(b, &pybuf, &pysz) != 0) {
Py_DECREF(b);
throw py::error_already_set();
}
auto s = std::span((uint8_t *)pybuf, pysz);
auto s = std::span(reinterpret_cast<uint8_t*>(pybuf), pysz);
wpi::util::PackStruct(s, v, info);
return py::reinterpret_steal<py::bytes>(b);
}
py::bytes packArray(const py::sequence &seq) {
py::bytes packArray(const py::sequence& seq) {
auto len = seq.size();
if (len == 0) {
return {};
@@ -53,14 +55,14 @@ py::bytes packArray(const py::sequence &seq) {
WPyStructInfo info(py::type::of(seq[0]));
auto sz = wpi::util::GetStructSize<WPyStruct>(info);
auto total = sz*len;
auto total = sz * len;
PyObject *b = PyBytes_FromStringAndSize(NULL, total);
PyObject* b = PyBytes_FromStringAndSize(NULL, total);
if (b == NULL) {
throw py::error_already_set();
}
char *pybuf;
char* pybuf;
py::ssize_t pysz;
if (PyBytes_AsStringAndSize(b, &pybuf, &pysz) != 0) {
Py_DECREF(b);
@@ -69,9 +71,9 @@ py::bytes packArray(const py::sequence &seq) {
auto bytes_obj = py::reinterpret_steal<py::bytes>(b);
for (const auto &v: seq) {
for (const auto& v : seq) {
WPyStruct wv(v);
auto s = std::span((uint8_t *)pybuf, sz);
auto s = std::span(reinterpret_cast<uint8_t*>(pybuf), sz);
wpi::util::PackStruct(s, wv, info);
pybuf += sz;
}
@@ -79,7 +81,7 @@ py::bytes packArray(const py::sequence &seq) {
return bytes_obj;
}
void packInto(const WPyStruct &v, py::buffer &b) {
void packInto(const WPyStruct& v, py::buffer& b) {
WPyStructInfo info(v);
py::ssize_t sz = wpi::util::GetStructSize<WPyStruct>(info);
@@ -94,11 +96,11 @@ void packInto(const WPyStruct &v, py::buffer &b) {
throw py::value_error("buffer must be " + std::to_string(sz) + " bytes");
}
auto s = std::span((uint8_t *)req.ptr, req.size);
auto s = std::span(reinterpret_cast<uint8_t*>(req.ptr), req.size);
wpi::util::PackStruct(s, v, info);
}
WPyStruct unpack(const py::type &t, const py::buffer &b) {
WPyStruct unpack(const py::type& t, const py::buffer& b) {
WPyStructInfo info(t);
py::ssize_t sz = wpi::util::GetStructSize<WPyStruct>(info);
@@ -113,11 +115,12 @@ WPyStruct unpack(const py::type &t, const py::buffer &b) {
throw py::value_error("buffer must be " + std::to_string(sz) + " bytes");
}
auto s = std::span((const uint8_t *)req.ptr, req.size);
auto s = std::span(reinterpret_cast<const uint8_t*>(req.ptr), req.size);
return wpi::util::UnpackStruct<WPyStruct, WPyStructInfo>(s, info);
}
py::typing::List<WPyStruct> unpackArray(const py::type &t, const py::buffer &b) {
py::typing::List<WPyStruct> unpackArray(const py::type& t,
const py::buffer& b) {
WPyStructInfo info(t);
py::ssize_t sz = wpi::util::GetStructSize<WPyStruct>(info);
@@ -129,12 +132,13 @@ py::typing::List<WPyStruct> unpackArray(const py::type &t, const py::buffer &b)
}
if (req.size % sz != 0) {
throw py::value_error("buffer must be multiple of " + std::to_string(sz) + " bytes");
throw py::value_error("buffer must be multiple of " + std::to_string(sz) +
" bytes");
}
auto items = req.size / sz;
py::list a(items);
const uint8_t *ptr = (const uint8_t *)req.ptr;
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(req.ptr);
for (py::ssize_t i = 0; i < items; i++) {
auto s = std::span(ptr, sz);
auto v = wpi::util::UnpackStruct<WPyStruct, WPyStructInfo>(s, info);

View File

@@ -7,50 +7,50 @@
Call a function to retrieve the (type string, schema) for each nested struct
*/
void forEachNested(
const py::type &t,
const std::function<void(std::string_view, std::string_view)> &fn);
const py::type& t,
const std::function<void(std::string_view, std::string_view)>& fn);
/**
Retrieve the type name for the specified type
*/
py::str getTypeName(const py::type &t);
py::str getTypeName(const py::type& t);
/**
Retrieve schema for the specified type
*/
py::str getSchema(const py::type &t);
py::str getSchema(const py::type& t);
/**
Returns the serialized size in bytes
*/
size_t getSize(const py::type &t);
size_t getSize(const py::type& t);
/**
Serialize object into byte buffer
*/
py::bytes pack(const WPyStruct &v);
py::bytes pack(const WPyStruct& v);
/**
Serialize objects into byte buffer
*/
py::bytes packArray(const py::sequence &seq);
py::bytes packArray(const py::sequence& seq);
/**
Serialize object into byte buffer. Buffer must be exact size.
*/
void packInto(const WPyStruct &v, py::buffer &b);
void packInto(const WPyStruct& v, py::buffer& b);
/**
Convert byte buffer into object of specified type. Buffer must be exact
size.
*/
WPyStruct unpack(const py::type &t, const py::buffer &b);
WPyStruct unpack(const py::type& t, const py::buffer& b);
/**
Convert byte buffer into list of objects of specified type. Buffer must be
exact size.
*/
py::typing::List<WPyStruct> unpackArray(const py::type &t, const py::buffer &b);
py::typing::List<WPyStruct> unpackArray(const py::type& t, const py::buffer& b);
// /**
// Convert byte buffer into passed in object. Buffer must be exact

View File

@@ -13,6 +13,8 @@
#include <limits>
#include <functional>
#include <string>
#include <vector>
#include <pybind11/functional.h>
@@ -178,7 +180,6 @@ StructWithWPI_String cast_struct_with_wpi_string() {
}
PYBIND11_MODULE(module, m) {
sendable_test(m);
struct_test(m);
@@ -209,7 +210,7 @@ PYBIND11_MODULE(module, m) {
m.def("load_stringmap_int", &load_stringmap_int);
m.def("cast_stringmap", &cast_stringmap);
// JSON
m.def("cast_json_arg", &cast_json_arg);
m.def("cast_json_arg", &cast_json_arg);
m.def("cast_json_val", &cast_json_val);
m.attr("max_uint64") = std::numeric_limits<uint64_t>::max();
m.attr("max_int64") = std::numeric_limits<int64_t>::max();
@@ -220,7 +221,7 @@ PYBIND11_MODULE(module, m) {
// WPI_String
m.def("load_wpi_string", &load_wpi_string);
m.def("cast_wpi_string", &cast_wpi_string);
py::class_<StructWithWPI_String> structWithWpiStringCls(m, "StructWithWPI_String");
structWithWpiStringCls.def_readwrite("x", &StructWithWPI_String::x);
structWithWpiStringCls.def_readonly("str", &StructWithWPI_String::str);

View File

@@ -1,15 +1,20 @@
#include <memory>
#include <string>
#include <utility>
#include <pybind11/functional.h>
#include <pybind11/stl.h>
#include <semiwrap.h>
#include "wpi/util/sendable/SendableBuilder.hpp"
#include "wpi/util/sendable/SendableRegistry.hpp"
class MySendableBuilder : public wpi::util::SendableBuilder {
public:
MySendableBuilder(py::dict keys) : keys(keys) {}
public:
explicit MySendableBuilder(py::dict keys) : keys(keys) {}
~MySendableBuilder() {
~MySendableBuilder() override {
// leak this so the python interpreter doesn't crash on shutdown
keys.release();
}
@@ -42,9 +47,9 @@ public:
void PublishConstDouble(std::string_view key, double value) override {}
void
AddStringProperty(std::string_view key, std::function<std::string()> getter,
std::function<void(std::string_view)> setter) override {}
void AddStringProperty(
std::string_view key, std::function<std::string()> getter,
std::function<void(std::string_view)> setter) override {}
void PublishConstString(std::string_view key,
std::string_view value) override {}
@@ -94,44 +99,48 @@ public:
void AddSmallStringProperty(
std::string_view key,
std::function<std::string_view(wpi::util::SmallVectorImpl<char> &buf)> getter,
std::function<std::string_view(wpi::util::SmallVectorImpl<char>& buf)>
getter,
std::function<void(std::string_view)> setter) override {}
void AddSmallBooleanArrayProperty(
std::string_view key,
std::function<std::span<const int>(wpi::util::SmallVectorImpl<int> &buf)>
std::function<std::span<const int>(wpi::util::SmallVectorImpl<int>& buf)>
getter,
std::function<void(std::span<const int>)> setter) override {}
void AddSmallIntegerArrayProperty(
std::string_view key,
std::function<
std::span<const int64_t>(wpi::util::SmallVectorImpl<int64_t> &buf)>
std::span<const int64_t>(wpi::util::SmallVectorImpl<int64_t>& buf)>
getter,
std::function<void(std::span<const int64_t>)> setter) override {}
void AddSmallFloatArrayProperty(
std::string_view key,
std::function<std::span<const float>(wpi::util::SmallVectorImpl<float> &buf)>
std::function<
std::span<const float>(wpi::util::SmallVectorImpl<float>& buf)>
getter,
std::function<void(std::span<const float>)> setter) override {}
void AddSmallDoubleArrayProperty(
std::string_view key,
std::function<std::span<const double>(wpi::util::SmallVectorImpl<double> &buf)>
std::function<
std::span<const double>(wpi::util::SmallVectorImpl<double>& buf)>
getter,
std::function<void(std::span<const double>)> setter) override {}
void AddSmallStringArrayProperty(
std::string_view key,
std::function<
std::span<const std::string>(wpi::util::SmallVectorImpl<std::string> &buf)>
std::function<std::span<const std::string>(
wpi::util::SmallVectorImpl<std::string>& buf)>
getter,
std::function<void(std::span<const std::string>)> setter) override {}
void AddSmallRawProperty(
std::string_view key, std::string_view typeString,
std::function<std::span<uint8_t>(wpi::util::SmallVectorImpl<uint8_t> &buf)>
std::function<
std::span<uint8_t>(wpi::util::SmallVectorImpl<uint8_t>& buf)>
getter,
std::function<void(std::span<const uint8_t>)> setter) override {}
@@ -151,4 +160,6 @@ void Publish(wpi::util::SendableRegistry::UID sendableUid, py::dict keys) {
wpi::util::SendableRegistry::Publish(sendableUid, std::move(builder));
}
void sendable_test(py::module &m) { m.def("publish", Publish); }
void sendable_test(py::module& m) {
m.def("publish", Publish);
}

View File

@@ -8,33 +8,34 @@
struct ThingA {
ThingA() = default;
ThingA(int x) : x(x) {}
explicit ThingA(int x) : x(x) {}
const int x = 0;
bool operator==(const ThingA &other) const { return x == other.x; }
bool operator==(const ThingA& other) const { return x == other.x; }
};
template <> struct wpi::util::Struct<ThingA> {
template <>
struct wpi::util::Struct<ThingA> {
static constexpr std::string_view GetTypeName() { return "ThingA"; }
static constexpr size_t GetSize() { return 1; }
static constexpr std::string_view GetSchema() { return "uint8 value"; }
static ThingA Unpack(std::span<const uint8_t> data) {
return ThingA{data[0]};
}
static void Pack(std::span<uint8_t> data, const ThingA &value) {
static void Pack(std::span<uint8_t> data, const ThingA& value) {
data[0] = value.x;
}
};
struct Outer {
Outer() = default;
Outer(const ThingA &t, int c) : inner(t), c(c) {}
Outer(const ThingA& t, int c) : inner(t), c(c) {}
ThingA inner;
int c = 0;
bool operator==(const Outer &other) const {
bool operator==(const Outer& other) const {
return inner == other.inner && c == other.c;
}
};
@@ -42,7 +43,9 @@ struct Outer {
template <>
struct wpi::util::Struct<Outer> {
static constexpr std::string_view GetTypeName() { return "Outer"; }
static constexpr size_t GetSize() { return wpi::util::GetStructSize<ThingA>() + 4; }
static constexpr size_t GetSize() {
return wpi::util::GetStructSize<ThingA>() + 4;
}
static constexpr std::string_view GetSchema() {
return "ThingA inner; int32 c";
}
@@ -63,8 +66,7 @@ struct wpi::util::Struct<Outer> {
}
};
void struct_test(py::module &m) {
void struct_test(py::module& m) {
py::class_<ThingA> thingCls(m, "ThingA");
thingCls.def(py::init<>());
thingCls.def(py::init<int>());
@@ -81,4 +83,4 @@ void struct_test(py::module &m) {
outerCls.def(py::self == py::self);
SetupWPyStruct<Outer>(outerCls);
}
}

View File

@@ -1,6 +1,6 @@
#include <semiwrap_init.xrp._xrp.hpp>
#include "semiwrap_init.xrp._xrp.hpp"
SEMIWRAP_PYBIND11_MODULE(m) {
initWrapper(m);
}
initWrapper(m);
}

View File

@@ -4,6 +4,6 @@ pkgconf_pypi_initpy=xrp._init__xrp
Name: xrp
Description: semiwrap pybind11 module
Version:
Version:
Cflags: -I${prefix}
Requires: robotpy-native-xrp wpilib wpimath