/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "exporter.h" #include #include #include #include #include "ser_nodes.h" META_BEGIN_NAMESPACE() namespace Serialization { bool Exporter::ShouldSerialize(const IObject::ConstPtr& object) const { return IsFlagSet(object, ObjectFlagBits::SERIALIZE); } bool Exporter::ShouldSerialize(const IAny& any) const { SharedPtrConstIInterface p; if (any.GetValue(p)) { if (auto flags = interface_cast(p)) { return flags->GetObjectFlags().IsSet(ObjectFlagBits::SERIALIZE); } } return true; } InstanceId Exporter::ConvertInstanceId(const InstanceId& id) const { auto it = mapInstanceIds_.find(id); return it != mapInstanceIds_.end() ? it->second : id; } bool Exporter::MarkExported(const IObject::ConstPtr& object) { bool res = false; if (auto i = interface_cast(object)) { auto id = i->GetInstanceId(); auto it = exported_.find(id); res = it != exported_.end(); if (!res) { exported_[id] = object; } } return res; } bool Exporter::HasBeenExported(const InstanceId& id) const { return exported_.find(id) != exported_.end(); } ISerNode::Ptr Exporter::Export(const IObject::ConstPtr& object) { BASE_NS::shared_ptr res; if (object) { ISerNode::Ptr node; auto r = ExportObject(object, node); if (r) { res.reset(new RootNode { EXPORTER_VERSION, BASE_NS::move(node) }); } } return res; } ISerNode::Ptr Exporter::CreateObjectNode(const IObject::ConstPtr& object, BASE_NS::shared_ptr node) { ISerNode::Ptr res; InstanceId iid; if (auto i = interface_cast(object)) { iid = ConvertInstanceId(i->GetInstanceId()); } return ISerNode::Ptr(new ObjectNode(BASE_NS::string(object->GetClassName()), BASE_NS::string(object->GetName()), object->GetClassId(), iid, BASE_NS::move(node))); } ISerNode::Ptr Exporter::CreateObjectRefNode(const RefUri& ref) { RefUri uri(ref); uri.SetBaseObjectUid(ConvertInstanceId(uri.BaseObjectUid()).ToUid()); return ISerNode::Ptr(new RefNode { uri }); } ISerNode::Ptr Exporter::CreateObjectRefNode(const IObject::ConstPtr& object) { ISerNode::Ptr res; if (auto i = interface_cast(object)) { RefUri ref(i->GetInstanceId().ToUid()); res = CreateObjectRefNode(ref); } return res; } ReturnError Exporter::ExportObject(const IObject::ConstPtr& object, ISerNode::Ptr& res) { ReturnError err = GenericError::SUCCESS; if (ShouldSerialize(object)) { if (MarkExported(object)) { res = CreateObjectRefNode(object); } else if (auto ser = interface_cast(object)) { ExportContext context(*this, object); err = ser->Export(context); if (err) { res = CreateObjectNode(object, context.ExtractNode()); } } else { res = AutoExportObject(object); } } return err; } ISerNode::Ptr Exporter::AutoExportObject(const IObject::ConstPtr& object) { BASE_NS::vector members; AutoExportObjectMembers(object, members); return CreateObjectNode(object, BASE_NS::shared_ptr(new MapNode(members))); } ReturnError Exporter::AutoExportObjectMembers(const IObject::ConstPtr& object, BASE_NS::vector& members) { if (auto flags = interface_cast(object)) { if (flags->GetObjectDefaultFlags() != flags->GetObjectFlags()) { ISerNode::Ptr node; auto res = ExportValue(Any(flags->GetObjectFlags().GetValue()), node); if (res && node) { members.push_back(NamedNode { "__flags", node }); } } } if (auto meta = interface_cast(object)) { auto res = ExportIMetadata(*meta); members.insert(members.end(), res.begin(), res.end()); } if (auto attach = interface_cast(object)) { if (IsFlagSet(object, ObjectFlagBits::SERIALIZE_ATTACHMENTS)) { if (auto cont = attach->GetAttachmentContainer()) { if (auto node = ExportIContainer(*cont)) { members.push_back(NamedNode { "__attachments", node }); } } } } if (auto cont = interface_cast(object)) { if (IsFlagSet(object, ObjectFlagBits::SERIALIZE_HIERARCHY)) { if (auto node = ExportIContainer(*cont)) { members.push_back(NamedNode { "__children", node }); } } } return GenericError::SUCCESS; } BASE_NS::vector Exporter::ExportIMetadata(const IMetadata& data) { // for now only properties BASE_NS::vector res; if (auto cont = data.GetPropertyContainer()) { if (cont->GetSize() > 0) { if (auto node = ExportIContainer(*cont)) { res.push_back(NamedNode { "__properties", BASE_NS::move(node) }); } } } return res; } ISerNode::Ptr Exporter::ExportIContainer(const IContainer& cont) { BASE_NS::vector elements; for (size_t i = 0; i != cont.GetSize(); ++i) { ISerNode::Ptr node; if (ExportObject(cont.GetAt(i), node) && node) { elements.push_back(BASE_NS::move(node)); } } return ISerNode::Ptr(new ArrayNode(BASE_NS::move(elements))); } template static ISerNode::Ptr ExportSingleBuiltinValue(TypeList, const IAny& value) { ISerNode::Ptr res; [[maybe_unused]] bool r = ((Builtins::ID == value.GetTypeId() ? (res = Builtins::CreateNode(value), true) : false) || ...); return res; } ISerNode::Ptr Exporter::ExportArray(const IArrayAny& array) { ISerNode::Ptr res; auto any = array.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM }); if (any) { BASE_NS::vector elements; for (size_t i = 0; i != array.GetSize(); ++i) { if (!array.GetAnyAt(i, *any)) { return nullptr; } ISerNode::Ptr node; if (ExportValue(*any, node) && node) { elements.push_back(BASE_NS::move(node)); } } res.reset(new ArrayNode(BASE_NS::move(elements))); } return res; } ISerNode::Ptr Exporter::ExportBuiltinValue(const IAny& value) { ISerNode::Ptr res; if (auto arr = interface_cast(&value)) { res = ExportArray(*arr); } else { if (value.GetTypeId() == UidFromType()) { // handle as double res = ExportSingleBuiltinValue(SupportedBuiltins {}, Any(GetValue(value))); } else { res = ExportSingleBuiltinValue(SupportedBuiltins {}, value); } } return res; } ReturnError Exporter::ExportPointer(const IAny& entity, ISerNode::Ptr& res) { // first see if it is a weak pointer BASE_NS::weak_ptr weak; bool isWeak = entity.GetValue(weak); if (isWeak) { if (auto obj = interface_pointer_cast(weak)) { return ExportWeakPtr(obj, res); } } BASE_NS::shared_ptr intf; if (entity.GetValue(intf)) { // see if it is null pointer if (!intf) { res = ISerNode::Ptr(new NilNode); return GenericError::SUCCESS; } // finally handle normal pointer case if (!isWeak) { if (auto obj = interface_pointer_cast(intf)) { return ExportObject(obj, res); } if (auto any = interface_pointer_cast(intf)) { return ExportAny(any, res); } } } return GenericError::FAIL; } ReturnError Exporter::ExportValue(const IAny& entity, ISerNode::Ptr& res) { if (!ShouldSerialize(entity)) { return GenericError::SUCCESS; } if (auto exp = globalData_.GetValueSerializer(entity.GetTypeId())) { res = exp->Export(*this, entity); if (res) { return GenericError::SUCCESS; } CORE_LOG_W("Value export registered for type [%s, %s] but it failed", entity.GetTypeIdString().c_str(), entity.GetTypeId().ToString().c_str()); } res = ExportBuiltinValue(entity); if (!res) { ExportPointer(entity, res); } if (!res) { CORE_LOG_F( "Failed to export type [%s, %s]", entity.GetTypeIdString().c_str(), entity.GetTypeId().ToString().c_str()); return GenericError::FAIL; } return GenericError::SUCCESS; } ReturnError Exporter::ExportAny(const IAny::ConstPtr& any, ISerNode::Ptr& res) { ReturnError err = GenericError::SUCCESS; if (!registry_.GetPropertyRegister().IsAnyRegistered(any->GetClassId())) { CORE_LOG_W("Exporting any that is not registered [class id=%s, type=%s, type id=%s]", any->GetClassId().ToString().c_str(), any->GetTypeIdString().c_str(), any->GetTypeId().ToString().c_str()); } if (!any) { res = ISerNode::Ptr(new NilNode); } else if (auto ser = interface_cast(any)) { ExportContext context(*this, interface_pointer_cast(any)); err = ser->Export(context); if (err) { res = ISerNode::Ptr(new ObjectNode(BASE_NS::string("Any"), {}, any->GetClassId(), {}, context.ExtractNode())); } } else { ISerNode::Ptr node; err = ExportValue(*any, node); if (err && node) { auto members = CreateShared(BASE_NS::vector { NamedNode { "value", node } }); res = ISerNode::Ptr( new ObjectNode(BASE_NS::string("Any"), {}, any->GetClassId(), {}, BASE_NS::move(members))); } } return err; } IObject::Ptr Exporter::ResolveUriSegment(const IObject::ConstPtr& ptr, RefUri& uri) const { if (auto instance = interface_cast(ptr)) { if (auto context = interface_cast(ptr)) { uri.PushObjectContextSegment(); } else { uri.PushObjectSegment(instance->GetName()); } return ptr->Resolve(RefUri::ParentUri()); } if (auto property = interface_cast(ptr)) { uri.PushPropertySegment(property->GetName()); auto owner = property->GetOwner().lock(); if (!owner) { CORE_LOG_E("No Owner for property '%s' when exporting weak ptr", property->GetName().c_str()); } return owner; } return nullptr; } ReturnError Exporter::ExportWeakPtr(const IObject::ConstWeakPtr& ptr, ISerNode::Ptr& res) { if (auto p = ptr.lock()) { auto original = p; RefUri uri; while (p) { if (auto obj = interface_cast(p)) { auto iid = ConvertInstanceId(obj->GetInstanceId()); if (HasBeenExported(iid) || globalData_.GetGlobalObject(obj->GetInstanceId())) { uri.SetBaseObjectUid(iid.ToUid()); res = ISerNode::Ptr(new RefNode(uri)); return GenericError::SUCCESS; } } p = ResolveUriSegment(p, uri); } CORE_LOG_E("Could not find suitable anchor object when exporting weak ptr [%s, %s, %s]", BASE_NS::string(original->GetClassName()).c_str(), original->GetName().c_str(), original->GetClassId().ToString().c_str()); return GenericError::FAIL; } res = ISerNode::Ptr(new NilNode); return GenericError::SUCCESS; } ReturnError Exporter::ExportToNode(const IAny& entity, ISerNode::Ptr& res) { return ExportValue(entity, res); } ReturnError ExportContext::Export(BASE_NS::string_view name, const IAny& entity) { ISerNode::Ptr node; auto res = exporter_.ExportValue(entity, node); if (res && node) { elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) }); } if (!res) { CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str()); } return res; } ReturnError ExportContext::ExportAny(BASE_NS::string_view name, const IAny::Ptr& any) { ISerNode::Ptr node; auto res = exporter_.ExportAny(any, node); if (res && node) { elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) }); } if (!res) { CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str()); } return res; } ReturnError ExportContext::ExportWeakPtr(BASE_NS::string_view name, const IObject::ConstWeakPtr& ptr) { ISerNode::Ptr node; auto res = exporter_.ExportWeakPtr(ptr, node); if (res && node) { elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) }); } if (!res) { CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str()); } return res; } ReturnError ExportContext::AutoExport() { if (object_) { BASE_NS::vector vec; auto res = exporter_.AutoExportObjectMembers(object_, vec); if (res) { elements_.insert(elements_.end(), vec.begin(), vec.end()); } return res; } CORE_LOG_W("Failed to auto export, exported type is not IObject"); return GenericError::FAIL; } BASE_NS::shared_ptr ExportContext::ExtractNode() { return BASE_NS::shared_ptr(new MapNode { BASE_NS::move(elements_) }); } ReturnError ExportContext::ExportToNode(const IAny& entity, ISerNode::Ptr& res) { return exporter_.ExportToNode(entity, res); } } // namespace Serialization META_END_NAMESPACE()