Lagrange
bind_value.h
1/*
2 * Copyright 2024 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/Logger.h>
15#include <lagrange/scene/SceneExtension.h>
16
17// clang-format off
18#include <lagrange/utils/warnoff.h>
19#include <nanobind/nanobind.h>
20#include <nanobind/stl/string.h>
21#include <nanobind/stl/variant.h>
22#include <lagrange/utils/warnon.h>
23// clang-format on
24
25NAMESPACE_BEGIN(NB_NAMESPACE)
26NAMESPACE_BEGIN(detail)
27
28template <>
29struct type_caster<lagrange::scene::Value>
30{
31 NB_TYPE_CASTER(lagrange::scene::Value, const_name("Value"))
32
33 template <typename T>
34 bool try_cast(const handle& src, uint8_t flags, cleanup_list* cleanup)
35 {
36 using CasterT = make_caster<T>;
37
38 CasterT caster;
39 if (!caster.from_python(src, flags, cleanup)) return false;
40 value.set(caster.operator cast_t<T>());
41 return true;
42 }
43
44 bool from_python(handle src, uint8_t flags, cleanup_list* cleanup) noexcept
45 {
46 if (PyNumber_Check(src.ptr())) {
47 lagrange::logger().debug("Number!");
48 return try_cast<int>(src, flags, cleanup) || try_cast<double>(src, flags, cleanup);
49 } else if (try_cast<std::string>(src, flags, cleanup)) {
50 lagrange::logger().debug("String!");
51 return true;
52 } else if (PySequence_Check(src.ptr())) {
53 lagrange::logger().debug("Array of size {}!", PySequence_Size(src.ptr()));
54
55 size_t n;
56 PyObject* temp;
57 /* Will initialize 'temp' (NULL in the case of a failure.) */
58 PyObject** o = seq_get(src.ptr(), &n, &temp);
59
60 bool success = o != nullptr;
61
62 if (success) {
63 lagrange::scene::Value::Array arr;
64 arr.reserve(n);
65 make_caster<lagrange::scene::Value> caster;
66
67 for (size_t i = 0; i < n; ++i) {
68 if (!caster.from_python(o[i], flags, cleanup)) {
69 success = false;
70 break;
71 }
72
73 arr.push_back(caster.operator cast_t<lagrange::scene::Value>());
74 }
75 value.set(arr);
76 }
77
78 Py_XDECREF(temp);
79 return success;
80 } else if (PyMapping_Check(src.ptr())) {
81 lagrange::logger().debug("Dict!");
82
83 PyObject* items = PyMapping_Items(src.ptr());
84 if (items == nullptr) {
85 PyErr_Clear();
86 return false;
87 }
88
89 Py_ssize_t size = NB_LIST_GET_SIZE(items);
90 bool success = size >= 0;
91
92 make_caster<std::string> key_caster;
93 make_caster<lagrange::scene::Value> val_caster;
94 lagrange::scene::Value::Object obj;
95
96 for (Py_ssize_t i = 0; i < size; ++i) {
97 PyObject* item = NB_LIST_GET_ITEM(items, i);
98 PyObject* key = NB_TUPLE_GET_ITEM(item, 0);
99 PyObject* val = NB_TUPLE_GET_ITEM(item, 1);
100
101 if (!key_caster.from_python(key, flags, cleanup)) {
102 success = false;
103 break;
104 }
105
106 if (!val_caster.from_python(val, flags, cleanup)) {
107 success = false;
108 break;
109 }
110
111 obj.emplace(
112 key_caster.operator cast_t<std::string>(),
113 val_caster.operator cast_t<lagrange::scene::Value>());
114 }
115 value.set(obj);
116
117 Py_DECREF(items);
118
119 return success;
120 }
121
122 return false;
123 }
124
125 static handle
126 from_cpp(const lagrange::scene::Value& value, rv_policy policy, cleanup_list* cleanup) noexcept
127 {
128 if (value.is_bool()) {
129 return make_caster<bool>::from_cpp(value.get_bool(), policy, cleanup);
130 } else if (value.is_int()) {
131 return make_caster<int>::from_cpp(value.get_int(), policy, cleanup);
132 } else if (value.is_real()) {
133 return make_caster<double>::from_cpp(value.get_real(), policy, cleanup);
134 } else if (value.is_string()) {
135 return make_caster<std::string>::from_cpp(value.get_string(), policy, cleanup);
136 } else if (value.is_buffer()) {
137 return make_caster<lagrange::scene::Value::Buffer>::from_cpp(
138 value.get_buffer(),
139 policy,
140 cleanup);
141 } else if (value.is_array()) {
142 return make_caster<lagrange::scene::Value::Array>::from_cpp(
143 value.get_array(),
144 policy,
145 cleanup);
146 } else if (value.is_object()) {
147 return make_caster<lagrange::scene::Value::Object>::from_cpp(
148 value.get_object(),
149 policy,
150 cleanup);
151 }
152 return none().release();
153 }
154};
155
156NAMESPACE_END(detail)
157NAMESPACE_END(NB_NAMESPACE)
158
Definition: SceneExtension.h:33
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
@ Value
Values that are not attached to a specific element.
Definition: AttributeFwd.h:42
Main namespace for Lagrange.
Definition: AABBIGL.h:30