Replies: 2 comments 4 replies
-
|
You have four options:
The last two options assume that it's mainly the stubs that you want to change. In that case, the |
Beta Was this translation helpful? Give feedback.
4 replies
-
|
So for reference I managed to write a type-caster that interpret any enum into a #include <nanobind/nanobind.h>
#include <nanobind/stl/string.h>
#include <magic_enum/magic_enum.hpp>
#include <array>
#include <iostream>
#include <string>
namespace nb = nanobind;
using namespace nb::literals;
////////////////////////////////////////////////////////////////////////////////
template<class InputIt, class Size, class OutputIt>
constexpr //< since C++20
OutputIt copy_n(InputIt first, Size count, OutputIt result)
{
if (count > 0)
{
*result = *first;
++result;
for (Size i = 1; i != count; ++i, (void)++result)
*result = *++first;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
template <typename Enum>
struct Literal : public std::string
{
using std::string::string;
operator Enum() const
{
auto s = magic_enum::enum_cast<Enum>(*this);
if (!s.has_value()) {
throw std::runtime_error("Invalid literal value: '" + *this + "'");
}
return s.value();
}
static constexpr size_t calculate_string_size()
{
std::string_view base = "typing.Literal[]";
size_t total_size = base.size();
bool first = true;
for (const auto& name : magic_enum::enum_names<Enum>()) {
total_size += name.size() + (first ? 2 : 4); // account for quotes and comma+space
first = false;
}
total_size += 1; // null terminator
return total_size;
}
static constexpr auto type_names()
{
constexpr size_t N = calculate_string_size();
char buffer[N];
std::string_view first = "typing.Literal[";
std::string_view last = "]";
copy_n(first.data(), first.size(), buffer);
size_t offset = first.size();
for (const auto& name : magic_enum::enum_names<Enum>()) {
if (offset > first.size()) {
buffer[offset++] = ',';
buffer[offset++] = ' ';
}
buffer[offset++] = '\'';
copy_n(name.data(), name.size(), buffer + offset);
offset += name.size();
buffer[offset++] = '\'';
}
copy_n(last.data(), last.size(), buffer + offset);
return nb::detail::const_name(buffer);
}
};
////////////////////////////////////////////////////////////////////////////////
NAMESPACE_BEGIN(NB_NAMESPACE)
NAMESPACE_BEGIN(detail)
template <typename Enum>
struct type_caster<Literal<Enum>>
{
NB_TYPE_CASTER(Literal<Enum>, Literal<Enum>::type_names())
bool from_python(handle src, uint8_t, cleanup_list*) noexcept
{
Py_ssize_t size;
const char* str = PyUnicode_AsUTF8AndSize(src.ptr(), &size);
if (!str) {
PyErr_Clear();
return false;
}
value = Literal<Enum>(str, (size_t)size);
return true;
}
static handle from_cpp(const Literal<Enum>& value, rv_policy, cleanup_list*) noexcept
{
return PyUnicode_FromStringAndSize(value.c_str(), value.size());
}
};
NAMESPACE_END(detail)
NAMESPACE_END(NB_NAMESPACE)
////////////////////////////////////////////////////////////////////////////////
enum class Method { BFS, DFS };
void print(const std::string& s)
{
std::cout << "this: " << s << std::endl;
}
void check_enum(const Method& method)
{
switch (method) {
case Method::BFS: std::cout << "Method is BFS" << std::endl; break;
case Method::DFS: std::cout << "Method is DFS" << std::endl; break;
default: std::cout << "Unknown method" << std::endl; break;
}
}
NB_MODULE(nanobind_example, m)
{
m.doc() = "This is a \"hello world\" example with nanobind";
m.def(
"traverse_graph",
[](Literal<Method> method) {
std::cout << "Traversing graph using method: " << std::endl;
print(method);
check_enum(method);
},
"method"_a);
}And the working autocompletion in vscode:
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment

Uh oh!
There was an error while loading. Please reload this page.
-
Consider a simple example like this:
m.def( "traverse_graph", [](const std::vector<std::vector<int>> &graph, std::string method) { // ... }, "graph"_a, "method"_a.sig("typing.Literal['bfs', 'dfs']") );Where I would like to override the stub for the
"method"argument to usetyping.Literal. I would like to avoid overrind the whoe function signature. From what I understand of the current stubgen code,nb::sig()can only be used to customize how the default value is rendered. Could we have a similar annotation to customize how the type itself is rendered? Even without default values.Beta Was this translation helpful? Give feedback.
All reactions