Skip to content

Commit 3e28837

Browse files
committed
serdes: allow calling methods by strings
- this commit introduces a new feature on the object manager, allowing one call a member function by name. - the arguments must be json and all VTK objects must be passed as identifier integers that correspond to the identifier tracked by the vtkObjectManager.
1 parent 6ad1085 commit 3e28837

File tree

49 files changed

+2362
-141
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2362
-141
lines changed

CMake/vtkModuleSerialization.cmake

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ function (vtk_module_generate_library_serdes_registrar)
8282
set(_vtk_serdes_register_classes_decls "")
8383
foreach (_vtk_serdes_class IN LISTS _vtk_serdes_CLASSES)
8484
string(APPEND _vtk_serdes_register_classes_decls
85-
" int RegisterHandlers_${_vtk_serdes_class}SerDes(void* serializer, void* deserializer);\n")
85+
" int RegisterHandlers_${_vtk_serdes_class}SerDes(void* serializer, void* deserializer, void* invoker);\n")
8686
string(APPEND _vtk_serdes_register_classes "
87-
if(!RegisterHandlers_${_vtk_serdes_class}SerDes(serializer, deserializer))
87+
if(!RegisterHandlers_${_vtk_serdes_class}SerDes(serializer, deserializer, invoker))
8888
{
8989
*error = \"Failed to register handlers for ${_vtk_serdes_class}\";
9090
return FAIL;
@@ -157,7 +157,7 @@ function (vtk_module_generate_libraries_serdes_registrar)
157157
string(APPEND _vtk_serdes_include_mandatory_libraries_registrar_headers
158158
"#include \"${_vtk_serdes_library_name}SerDes.h\"")
159159
string(APPEND _vtk_serdes_register_mandatory_libraries "
160-
if(!${_vtk_serdes_library_name}SerDesRegistrar::RegisterClasses(serializer, deserializer, error))
160+
if(!${_vtk_serdes_library_name}SerDesRegistrar::RegisterClasses(serializer, deserializer, invoker, error))
161161
{
162162
return FAIL;
163163
}\n")
@@ -181,7 +181,7 @@ function (vtk_module_generate_libraries_serdes_registrar)
181181
#endif\n")
182182
string(APPEND _vtk_serdes_register_optional_libraries "
183183
#if ${_vtk_serdes_module_enabled_condition}
184-
if(!${_vtk_serdes_library_name}SerDesRegistrar::RegisterClasses(serializer, deserializer, error))
184+
if(!${_vtk_serdes_library_name}SerDesRegistrar::RegisterClasses(serializer, deserializer, invoker, error))
185185
{
186186
return FAIL;
187187
}

CMake/vtkSerializationLibrariesRegistrar.cxx.in

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ extern "C"
1515
* Register the (de)serialization handlers of classes in all serialized libraries.
1616
* @param serializer a vtkSerializer instance
1717
* @param deserializer a vtkDeserializer instance
18+
* @param invoker a vtkInvoker instance
1819
* @param error when registration fails, the error message is pointed to by `error`. Use it for logging purpose.
1920
* @warning The memory pointed to by `error` is not dynamically allocated. Do not free it.
2021
*/
21-
int RegisterLibraries_@_vtk_serdes_registrar_name@(void* serializer, void* deserializer, const char** error);
22+
int RegisterLibraries_@_vtk_serdes_registrar_name@(void* serializer, void* deserializer, void* invoker, const char** error);
2223
}
2324

24-
int RegisterLibraries_@_vtk_serdes_registrar_name@(void* serializer, void* deserializer, const char** error)
25+
int RegisterLibraries_@_vtk_serdes_registrar_name@(void* serializer, void* deserializer, void* invoker, const char** error)
2526
{
2627
const int SUCCESS = 1;
2728
const int FAIL = 0;

CMake/vtkSerializationLibraryRegistrar.cxx.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extern "C"
1212
}
1313

1414
VTK_ABI_NAMESPACE_BEGIN
15-
int @_vtk_serdes_library@SerDesRegistrar::RegisterClasses(void* serializer, void* deserializer, const char** error)
15+
int @_vtk_serdes_library@SerDesRegistrar::RegisterClasses(void* serializer, void* deserializer, void* invoker, const char** error)
1616
{
1717
const int SUCCESS = 1;
1818
const int FAIL = 0;

CMake/vtkSerializationLibraryRegistrar.h.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ public:
1414
* Register the (de)serialization handlers of classes in a serialized library.
1515
* @param serializer a vtkSerializer instance
1616
* @param deserializer a vtkDeserializer instance
17+
* @param invoker a vtkInvoker instance
1718
* @param error when registration fails, the error message is pointed to by `error`. Use it
1819
* for logging purpose.
1920
* @warning The memory pointed to by `error` is not dynamically allocated. Do not free it.
2021
*/
21-
static int RegisterClasses(void* serializer, void* deserializer, const char** error);
22+
static int RegisterClasses(void* serializer, void* deserializer, void* invoker, const char** error);
2223
};
2324
VTK_ABI_NAMESPACE_END
2425
#endif

CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,12 @@ set("_vtk_module_reason_VTK::Java"
300300
if (VTK_WRAP_SERIALIZATION)
301301
list(APPEND vtk_requested_modules
302302
VTK::SerializationManager)
303+
if (VTK_BUILD_TESTING)
304+
list(APPEND vtk_requested_modules
305+
VTK::TestingSerialization)
306+
endif ()
307+
set("_vtk_module_reason_VTK::TestingSerialization"
308+
"via `VTK_WRAP_SERIALIZATION` AND `VTK_BUILD_TESTING`")
303309
if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
304310
list(APPEND vtk_requested_modules
305311
VTK::WebAssembly)
@@ -311,7 +317,8 @@ if (VTK_WRAP_SERIALIZATION)
311317
"via `VTK_WRAP_SERIALIZATION` AND `CMAKE_SYSTEM_NAME` STREQUAL Emscripten")
312318
else ()
313319
list(APPEND vtk_rejected_modules
314-
VTK::SerializationManager)
320+
VTK::SerializationManager
321+
VTK::TestingSerialization)
315322
endif ()
316323
set("_vtk_module_reason_VTK::SerializationManager"
317324
"via `VTK_WRAP_SERIALIZATION`")

Common/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ set(classes
290290
vtkInformationVariantVectorKey
291291
vtkInformationVector
292292
vtkIntArray
293+
vtkInvoker
293294
vtkLargeInteger
294295
vtkLogger
295296
vtkLongArray

Common/Core/vtkDataArraySerDesHelper.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ extern "C"
3939
* @param ser a vtkSerializer instance
4040
* @param deser a vtkDeserializer instance
4141
*/
42-
int RegisterHandlers_vtkDataArraySerDesHelper(void* ser, void* deser);
42+
int RegisterHandlers_vtkDataArraySerDesHelper(void* ser, void* deser, void* invoker);
4343
}
4444

4545
namespace
@@ -203,7 +203,7 @@ static void Deserialize_vtkDataArray(
203203
}
204204
}
205205

206-
int RegisterHandlers_vtkDataArraySerDesHelper(void* ser, void* deser)
206+
int RegisterHandlers_vtkDataArraySerDesHelper(void* ser, void* deser, void* vtkNotUsed(invoker))
207207
{
208208
int success = 0;
209209
if (auto* asObjectBase = static_cast<vtkObjectBase*>(ser))

Common/Core/vtkInvoker.cxx

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
#include "vtkInvoker.h"
4+
#include "vtkLogger.h"
5+
#include "vtkObjectFactory.h"
6+
7+
#include "vtksys/SystemTools.hxx"
8+
9+
// clang-format off
10+
#include "vtk_nlohmannjson.h" // for json
11+
#include VTK_NLOHMANN_JSON(json.hpp) // for json
12+
// clang-format on
13+
14+
#include <unordered_map>
15+
16+
VTK_ABI_NAMESPACE_BEGIN
17+
18+
class vtkInvoker::vtkInternals
19+
{
20+
public:
21+
std::unordered_map<std::size_t, vtkInvoker::HandlerType> Handlers;
22+
};
23+
24+
//------------------------------------------------------------------------------
25+
vtkStandardNewMacro(vtkInvoker);
26+
27+
//------------------------------------------------------------------------------
28+
vtkInvoker::vtkInvoker()
29+
: Internals(new vtkInternals())
30+
{
31+
}
32+
33+
//------------------------------------------------------------------------------
34+
vtkInvoker::~vtkInvoker() = default;
35+
36+
//------------------------------------------------------------------------------
37+
void vtkInvoker::PrintSelf(ostream& os, vtkIndent indent)
38+
{
39+
this->Superclass::PrintSelf(os, indent);
40+
const auto& internals = (*this->Internals);
41+
os << "No. of handlers: " << internals.Handlers.size() << '\n';
42+
for (const auto& item : internals.Handlers)
43+
{
44+
os << item.first << ": function pointer (" << item.second.target_type().name() << ")\n";
45+
}
46+
}
47+
48+
//------------------------------------------------------------------------------
49+
nlohmann::json vtkInvoker::Invoke(
50+
const vtkTypeUInt32& identifier, const std::string& methodName, const nlohmann::json& args)
51+
{
52+
if (auto objectBase = this->Context->GetObjectAtId(identifier))
53+
{
54+
auto* objectPtr = objectBase.GetPointer();
55+
const auto& typeId = typeid(*objectPtr);
56+
if (const auto& f = this->GetHandler(typeId))
57+
{
58+
vtkVLog(this->GetInvokerLogVerbosity(), << "Invoke method=\'" << methodName.c_str()
59+
<< "\', args=\'" << args.dump().c_str() << "\'");
60+
return f(this, objectPtr, methodName.c_str(), args);
61+
}
62+
else
63+
{
64+
vtkErrorMacro(
65+
<< "Cannot invoke method on object with type "
66+
"{ .name="
67+
<< typeId.name() << " .hashCode=" << typeId.hash_code()
68+
<< " }"
69+
" because a handler was not found. Check stack trace to see how we got here.");
70+
}
71+
}
72+
else
73+
{
74+
vtkWarningMacro(<< "Cannot invoke method \'" << methodName.c_str()
75+
<< "\' on an object (id=" << identifier << ") that does not exist");
76+
}
77+
return { { "success", false } };
78+
}
79+
80+
//------------------------------------------------------------------------------
81+
void vtkInvoker::RegisterHandler(const std::type_info& type, HandlerType invoker)
82+
{
83+
auto& internals = (*this->Internals);
84+
vtkVLog(this->GetInvokerLogVerbosity(),
85+
<< "Register invoker at { .name=" << type.name() << " .hashCode=" << type.hash_code() << " }");
86+
internals.Handlers[type.hash_code()] = invoker;
87+
}
88+
89+
//------------------------------------------------------------------------------
90+
vtkInvoker::HandlerType vtkInvoker::GetHandler(const std::type_info& type) const
91+
{
92+
const auto& internals = (*this->Internals);
93+
auto iter = internals.Handlers.find(type.hash_code());
94+
if (iter != internals.Handlers.end())
95+
{
96+
return iter->second;
97+
}
98+
return nullptr;
99+
}
100+
101+
//------------------------------------------------------------------------------
102+
bool vtkInvoker::UnRegisterHandler(const std::type_info& type)
103+
{
104+
return this->Internals->Handlers.erase(type.hash_code()) != 0;
105+
}
106+
107+
//------------------------------------------------------------------------------
108+
void vtkInvoker::SetInvokerLogVerbosity(vtkLogger::Verbosity verbosity)
109+
{
110+
this->InvokerLogVerbosity = verbosity;
111+
}
112+
113+
//------------------------------------------------------------------------------
114+
vtkLogger::Verbosity vtkInvoker::GetInvokerLogVerbosity()
115+
{
116+
// initialize the log verbosity if it is invalid.
117+
if (this->InvokerLogVerbosity == vtkLogger::VERBOSITY_INVALID)
118+
{
119+
this->InvokerLogVerbosity = vtkLogger::VERBOSITY_TRACE;
120+
// Find an environment variable that specifies logger verbosity
121+
const char* verbosityKey = "VTK_INVOKER_LOG_VERBOSITY";
122+
if (vtksys::SystemTools::HasEnv(verbosityKey))
123+
{
124+
const char* verbosityCStr = vtksys::SystemTools::GetEnv(verbosityKey);
125+
const auto verbosity = vtkLogger::ConvertToVerbosity(verbosityCStr);
126+
if (verbosity > vtkLogger::VERBOSITY_INVALID)
127+
{
128+
this->InvokerLogVerbosity = verbosity;
129+
}
130+
}
131+
}
132+
return this->InvokerLogVerbosity;
133+
}
134+
VTK_ABI_NAMESPACE_END

Common/Core/vtkInvoker.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
/**
4+
* @class vtkInvoker
5+
* @brief Deserialize VTK objects from JSON.
6+
*/
7+
#ifndef vtkInvoker_h
8+
#define vtkInvoker_h
9+
10+
#include "vtkObject.h"
11+
12+
#include "vtkCommonCoreModule.h" // for export macro
13+
#include "vtkLogger.h" // for vtkLogger::Verbosity enum
14+
#include "vtkMarshalContext.h" // for vtkMarshalContext
15+
#include "vtkSmartPointer.h" // for vktSmartPointer
16+
17+
// clang-format off
18+
#include "vtk_nlohmannjson.h" // for json
19+
#include VTK_NLOHMANN_JSON(json_fwd.hpp) // for json
20+
// clang-format on
21+
22+
#include <memory> // for unique_ptr
23+
#include <typeinfo> // for type_info
24+
25+
VTK_ABI_NAMESPACE_BEGIN
26+
27+
class VTKCOMMONCORE_EXPORT vtkInvoker : public vtkObject
28+
{
29+
public:
30+
static vtkInvoker* New();
31+
vtkTypeMacro(vtkInvoker, vtkObject);
32+
void PrintSelf(ostream& os, vtkIndent indent) override;
33+
34+
using HandlerType =
35+
std::function<nlohmann::json(vtkInvoker*, vtkObjectBase*, const char*, const nlohmann::json&)>;
36+
37+
nlohmann::json Invoke(
38+
const vtkTypeUInt32& identifier, const std::string& methodName, const nlohmann::json& args);
39+
40+
///@{
41+
/**
42+
* The handlers are used to call a named method.
43+
*
44+
* @note
45+
* If a class does not have a handler, this class will
46+
* print a stack trace to help you understand the reason for failure.
47+
*/
48+
void RegisterHandler(const std::type_info& type, HandlerType Invoker);
49+
HandlerType GetHandler(const std::type_info& type) const;
50+
bool UnRegisterHandler(const std::type_info& type);
51+
///@}
52+
53+
///@{
54+
/**
55+
* Get/Set the marshalling context.
56+
* The vtkInvoker does not track state of any object.
57+
* However, it leverages the context to discover objects and invoke methods.
58+
*/
59+
vtkSetSmartPointerMacro(Context, vtkMarshalContext);
60+
vtkGetSmartPointerMacro(Context, vtkMarshalContext);
61+
///@}
62+
63+
///@{
64+
/**
65+
* Set/Get the log verbosity of messages that are emitted when data is uploaded to GPU memory.
66+
* The GetInvokerLogVerbosity looks up system environment for
67+
* `VTK_Invoker_LOG_VERBOSITY` that shall be used to set initial logger verbosity. The
68+
* default value is TRACE.
69+
*
70+
* Accepted string values are OFF, ERROR, WARNING, INFO, TRACE, MAX, INVALID or ASCII
71+
* representation for an integer in the range [-9,9].
72+
*
73+
* @note This method internally uses vtkLogger::ConvertToVerbosity(const char*) to parse the
74+
* value from environment variable.
75+
*/
76+
void SetInvokerLogVerbosity(vtkLogger::Verbosity verbosity);
77+
vtkLogger::Verbosity GetInvokerLogVerbosity();
78+
///@}
79+
80+
protected:
81+
vtkInvoker();
82+
~vtkInvoker() override;
83+
84+
vtkSmartPointer<vtkMarshalContext> Context;
85+
vtkLogger::Verbosity InvokerLogVerbosity = vtkLogger::VERBOSITY_INVALID;
86+
87+
private:
88+
vtkInvoker(const vtkInvoker&) = delete;
89+
void operator=(const vtkInvoker&) = delete;
90+
class vtkInternals;
91+
std::unique_ptr<vtkInternals> Internals;
92+
};
93+
94+
VTK_ABI_NAMESPACE_END
95+
#endif

Common/Core/vtkStringArraySerDesHelper.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extern "C"
1616
* @param ser a vtkSerializer instance
1717
* @param deser a vtkDeserializer instance
1818
*/
19-
int RegisterHandlers_vtkStringArraySerDesHelper(void* ser, void* deser);
19+
int RegisterHandlers_vtkStringArraySerDesHelper(void* ser, void* deser, void* invoker);
2020
}
2121

2222
static nlohmann::json Serialize_vtkStringArray(vtkObjectBase* objectBase, vtkSerializer* serializer)
@@ -61,7 +61,7 @@ static void Deserialize_vtkStringArray(
6161
}
6262
}
6363

64-
int RegisterHandlers_vtkStringArraySerDesHelper(void* ser, void* deser)
64+
int RegisterHandlers_vtkStringArraySerDesHelper(void* ser, void* deser, void* vtkNotUsed(invoker))
6565
{
6666
int success = 0;
6767
if (auto* asObjectBase = static_cast<vtkObjectBase*>(ser))

0 commit comments

Comments
 (0)