Nebula
Loading...
Searching...
No Matches
conversion.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
9//------------------------------------------------------------------------------
10#include "util/variant.h"
11#include "nanobind/nanobind.h"
12#include "nanobind/stl/detail/nb_dict.h"
13#include "nanobind/stl/detail/nb_array.h"
14#include "nanobind/stl/detail/nb_list.h"
15
16#pragma warning(push)
17#if defined(_MSC_VER)
18#pragma warning(disable: 4267)
19#endif
20
21namespace Python
22{
23//------------------------------------------------------------------------------
27//------------------------------------------------------------------------------
30nanobind::handle VariantToPyType(Util::Variant src, nanobind::rv_policy policy = nanobind::rv_policy::automatic, nanobind::detail::cleanup_list* cleanup = nullptr);
31
32} // namespace Python
33
34namespace nanobind
35{
36 namespace detail
37 {
38 template <> struct type_caster<Util::String>
39 {
40 public:
41 bool from_python(handle src, uint8_t flags, cleanup_list* ) noexcept
42 {
43 handle load_src = src;
44 if (!src)
45 {
46 return false;
47 }
48 else if (!PyUnicode_Check(load_src.ptr()))
49 {
50 return load_bytes(load_src);
51 }
52 object utfNbytes = steal<object>(PyUnicode_AsEncodedString(load_src.ptr(), "utf-8", nullptr));
53 if (!utfNbytes)
54 {
55 PyErr_Clear();
56 return false;
57 }
58
59 const char *buffer = reinterpret_cast<const char *>(PyBytes_AsString(utfNbytes.ptr()));
60 size_t length = (size_t)PyBytes_Size(utfNbytes.ptr());
61 value.Set(buffer, length);
62
63 return true;
64 }
65 static handle from_cpp(const Util::String& src, rv_policy /* policy */, cleanup_list*) noexcept {
66 const char *buffer = src.AsCharPtr();
67 size_t nbytes = size_t(src.Length());
68 handle s = PyUnicode_DecodeUTF8(buffer, nbytes, nullptr);
69 return s;
70 }
71 NB_TYPE_CASTER(Util::String, const_name("str"));
72
73 private:
74 bool load_bytes(handle src)
75 {
76 if (PyBytes_Check(src.ptr()))
77 {
78 // We were passed a Python 3 raw bytes; accept it into a std::string or char*
79 // without any encoding attempt.
80 const char *bytes = PyBytes_AsString(src.ptr());
81 if (bytes)
82 {
83 value.Set(bytes, (size_t)PyBytes_Size(src.ptr()));
84 return true;
85 }
86 }
87 return false;
88 }
89 };
90
91#if 0
92 // this needs a different approach, ownership between c++ and python is not clear atm
93 template <> class type_caster<Util::Variant>
94 {
95 template <typename T> using Caster = make_caster<detail::intrinsic_t<T>>;
96 public:
97 template<class T>
98 bool try_load(handle src, uint8_t flags, cleanup_list* cleanup)
99 {
100 Caster<T> caster;
101 if (!caster.from_python(src, flags, cleanup))
102 {
103 return false;
104 }
105
106 if constexpr (is_pointer_v<T>)
107 {
108 static_assert(Caster<T>::IsClass,
109 "Binding 'Variant<T*,...>' requires that 'T' can also be bound by nanobind.");
110 value = caster.operator cast_t<T>();
111 }
112 else if constexpr (Caster<T>::IsClass)
113 {
114 // Non-pointer classes do not accept a null pointer
115 if (src.is_none())
116 return false;
117 value = caster.operator cast_t<T&>();
118 }
119 else
120 {
121 value = std::move(caster).operator cast_t<T&&>();
122 }
123 return true;
124 }
125
126 bool from_python(handle src, uint8_t flags, cleanup_list* cleanup) noexcept {
127 auto loaded = {
128 false,
129 try_load<int>(src, flags, cleanup),
130 try_load<uint>(src, flags, cleanup),
131 try_load<float>(src, flags, cleanup),
132 try_load<Math::vec4>(src, flags, cleanup),
133 try_load<Math::mat4>(src, flags, cleanup),
134 try_load<Util::String>(src, flags, cleanup),
135 try_load<Util::Guid>(src, flags, cleanup),
136 try_load<Util::Array<int>>(src, flags, cleanup),
137 try_load<Util::Array<float>>(src, flags, cleanup),
138 try_load<Util::Array<Math::vec4>>(src, flags, cleanup),
139 try_load<Util::Array<Math::mat4>>(src, flags, cleanup),
140 try_load<Util::Array<Util::String>>(src, flags, cleanup),
141 try_load<Util::Array<Util::Guid>>(src, flags, cleanup)
142 };
143 return std::any_of(loaded.begin(), loaded.end(), [](bool b) { return b; });
144 }
145
146 static handle from_cpp(const Util::Variant& src, rv_policy policy, cleanup_list* cleanup) noexcept {
147 return Python::VariantToPyType(src, policy, cleanup);
148 }
149 NB_TYPE_CASTER(Util::Variant, const_name("Variant"));
150 };
151#endif
152 template <typename Key, typename Value> struct type_caster<Util::Dictionary<Key, Value>>
153 : nanobind::detail::dict_caster<Util::Dictionary<Key, Value>, Key, Value> { };
154 template <typename Type> struct type_caster<Util::Array<Type>>
155 : list_caster<Util::Array<Type>, Type> { };
156 }
157}
158#pragma warning(pop)
Nebula's dynamic array class.
Definition array.h:60
An "any type" variable.
Definition variant.h:31
Python conversion functions.
Definition conversion.cc:20
void RegisterNebulaModules()
Definition conversion.cc:517
nanobind::handle VariantToPyType(Util::Variant src, py::rv_policy policy, nanobind::detail::cleanup_list *cleanup)
Definition conversion.cc:402
A pinned array is an array which manages its own virtual memory.
Definition String.cs:6
Definition conversion.h:35
Nebula's universal string class.
Definition string.h:50
NB_TYPE_CASTER(Util::String, const_name("str"))
bool from_python(handle src, uint8_t flags, cleanup_list *) noexcept
Definition conversion.h:41
static handle from_cpp(const Util::String &src, rv_policy, cleanup_list *) noexcept
Definition conversion.h:65
bool load_bytes(handle src)
Definition conversion.h:74