// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkSerializer.h" #include "vtkLogger.h" #include "vtkObjectFactory.h" #include "vtksys/SystemInformation.hxx" // clang-format off #include "vtk_nlohmannjson.h" #include VTK_NLOHMANN_JSON(json.hpp) // clang-format on #include VTK_ABI_NAMESPACE_BEGIN class vtkSerializer::vtkInternals { public: std::unordered_map Handlers; }; //------------------------------------------------------------------------------ vtkStandardNewMacro(vtkSerializer); //------------------------------------------------------------------------------ vtkSerializer::vtkSerializer() : Internals(new vtkInternals()) { } //------------------------------------------------------------------------------ vtkSerializer::~vtkSerializer() = default; //------------------------------------------------------------------------------ void vtkSerializer::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); const auto& internals = (*this->Internals); os << "No. of handlers: " << internals.Handlers.size() << '\n'; for (const auto& item : internals.Handlers) { os << item.first << ": function pointer (" << item.second.target_type().name() << ")\n"; } } //------------------------------------------------------------------------------ nlohmann::json vtkSerializer::SerializeJSON(vtkObjectBase* objectBase) { if ((this->Context == nullptr) || (objectBase == nullptr)) { return nlohmann::json::object(); } vtkTypeUInt32 identifier = 0; if (this->Context->HasId(objectBase, identifier)) { if (this->Context->IsProcessing(identifier) || this->Context->IsProcessed(identifier)) { vtkVLogF(this->GetSerializerLogVerbosity(), "Avoided serialization of %s", objectBase->GetObjectDescription().c_str()); this->Context->AddChild(identifier); return { { "Id", identifier } }; } } else if (!this->Context->RegisterObject(objectBase, identifier)) { vtkErrorMacro(<< "Failed to add object " << objectBase->GetObjectDescription()); return nlohmann::json::object(); } nlohmann::json state = nlohmann::json::object(); if (const auto& f = this->GetHandler(typeid(*objectBase))) { try { vtkMarshalContext::ScopedParentTracker parentTracker(this->Context, identifier); vtkVLogScopeF(this->GetSerializerLogVerbosity(), "Serialize objectBase=%s at id=%u", objectBase->GetObjectDescription().c_str(), identifier); state = f(objectBase, this); state["Id"] = identifier; this->Context->UnRegisterState(identifier); } catch (std::exception& e) { vtkErrorMacro(<< "Failed to serialize objectBase=" << objectBase->GetObjectDescription() << ". message=" << e.what()); return nlohmann::json::object(); } } if (this->Context->RegisterState(std::move(state))) { this->Context->AddChild(identifier); return { { "Id", identifier } }; } vtkErrorMacro(<< "Failed to add state for object=" << objectBase->GetObjectDescription() << " with id=" << identifier); return nlohmann::json::object(); } //------------------------------------------------------------------------------ void vtkSerializer::RegisterHandler(const std::type_info& type, HandlerType handler) { auto& internals = (*this->Internals); vtkVLog(this->GetSerializerLogVerbosity(), << "Register handler at { .name=" << type.name() << " .hashCode=" << type.hash_code() << " }"); internals.Handlers[type.hash_code()] = handler; } //------------------------------------------------------------------------------ vtkSerializer::HandlerType vtkSerializer::GetHandler(const std::type_info& type) const { const auto& internals = (*this->Internals); auto handlerIter = internals.Handlers.find(type.hash_code()); if (handlerIter != internals.Handlers.end()) { return handlerIter->second; } vtkErrorMacro( << "Cannot serialize object with type " "{ .name=" << type.name() << " .hashCode=" << type.hash_code() << " }" " because a serializer was not found. Check stack trace to see how we got here."); vtkWarningMacro(<< vtksys::SystemInformation::GetProgramStack(2, 1)); return nullptr; } //------------------------------------------------------------------------------ bool vtkSerializer::UnRegisterHandler(const std::type_info& type) { return this->Internals->Handlers.erase(type.hash_code()) != 0; } //------------------------------------------------------------------------------ void vtkSerializer::SetSerializerLogVerbosity(vtkLogger::Verbosity verbosity) { this->SerializerLogVerbosity = verbosity; } //------------------------------------------------------------------------------ vtkLogger::Verbosity vtkSerializer::GetSerializerLogVerbosity() { // initialize the log verbosity if it is invalid. if (this->SerializerLogVerbosity == vtkLogger::VERBOSITY_INVALID) { this->SerializerLogVerbosity = vtkLogger::VERBOSITY_TRACE; // Find an environment variable that specifies logger verbosity const char* verbosityKey = "VTK_SERIALIZER_LOG_VERBOSITY"; if (vtksys::SystemTools::HasEnv(verbosityKey)) { const char* verbosityCStr = vtksys::SystemTools::GetEnv(verbosityKey); const auto verbosity = vtkLogger::ConvertToVerbosity(verbosityCStr); if (verbosity > vtkLogger::VERBOSITY_INVALID) { this->SerializerLogVerbosity = verbosity; } } } return this->SerializerLogVerbosity; } VTK_ABI_NAMESPACE_END