• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "exporter.h"
17 
18 #include <meta/api/util.h>
19 #include <meta/interface/intf_attach.h>
20 #include <meta/interface/intf_object_context.h>
21 #include <meta/interface/serialization/intf_serializable.h>
22 
23 #include "ser_nodes.h"
24 
25 META_BEGIN_NAMESPACE()
26 namespace Serialization {
27 
ShouldSerialize(const IObject::ConstPtr & object) const28 bool Exporter::ShouldSerialize(const IObject::ConstPtr& object) const
29 {
30     return IsFlagSet(object, ObjectFlagBits::SERIALIZE);
31 }
ShouldSerialize(const IAny & any) const32 bool Exporter::ShouldSerialize(const IAny& any) const
33 {
34     SharedPtrConstIInterface p;
35     if (any.GetValue(p)) {
36         if (auto flags = interface_cast<IObjectFlags>(p)) {
37             return flags->GetObjectFlags().IsSet(ObjectFlagBits::SERIALIZE);
38         }
39     }
40     return true;
41 }
42 
ConvertInstanceId(const InstanceId & id) const43 InstanceId Exporter::ConvertInstanceId(const InstanceId& id) const
44 {
45     auto it = mapInstanceIds_.find(id);
46     return it != mapInstanceIds_.end() ? it->second : id;
47 }
48 
MarkExported(const IObject::ConstPtr & object)49 bool Exporter::MarkExported(const IObject::ConstPtr& object)
50 {
51     bool res = false;
52     if (auto i = interface_cast<IObjectInstance>(object)) {
53         auto id = i->GetInstanceId();
54         auto it = exported_.find(id);
55         res = it != exported_.end();
56         if (!res) {
57             exported_[id] = object;
58         }
59     }
60     return res;
61 }
62 
HasBeenExported(const InstanceId & id) const63 bool Exporter::HasBeenExported(const InstanceId& id) const
64 {
65     return exported_.find(id) != exported_.end();
66 }
67 
Export(const IObject::ConstPtr & object)68 ISerNode::Ptr Exporter::Export(const IObject::ConstPtr& object)
69 {
70     BASE_NS::shared_ptr<RootNode> res;
71     if (object) {
72         ISerNode::Ptr node;
73         auto r = ExportObject(object, node);
74         if (r) {
75             // resolve deferred weak ptr exports
76             for (auto&& d : deferred_) {
77                 if (!ResolveDeferredWeakPtr(d)) {
78                     CORE_LOG_E("Failed to resolve deferred weak ptr export");
79                 }
80             }
81             res.reset(new RootNode { BASE_NS::move(node), VERSION, EXPORTER_VERSION });
82         }
83     }
84     return res;
85 }
86 
CreateObjectNode(const IObject::ConstPtr & object,BASE_NS::shared_ptr<MapNode> node)87 ISerNode::Ptr Exporter::CreateObjectNode(const IObject::ConstPtr& object, BASE_NS::shared_ptr<MapNode> node)
88 {
89     ISerNode::Ptr res;
90     InstanceId iid;
91     if (auto i = interface_cast<IObjectInstance>(object)) {
92         iid = ConvertInstanceId(i->GetInstanceId());
93     }
94     return ISerNode::Ptr(new ObjectNode(BASE_NS::string(object->GetClassName()), BASE_NS::string(object->GetName()),
95         object->GetClassId(), iid, BASE_NS::move(node)));
96 }
97 
CreateObjectRefNode(const RefUri & ref)98 ISerNode::Ptr Exporter::CreateObjectRefNode(const RefUri& ref)
99 {
100     RefUri uri(ref);
101     uri.SetBaseObjectUid(ConvertInstanceId(uri.BaseObjectUid()).ToUid());
102     return ISerNode::Ptr(new RefNode { uri });
103 }
104 
CreateObjectRefNode(const IObject::ConstPtr & object)105 ISerNode::Ptr Exporter::CreateObjectRefNode(const IObject::ConstPtr& object)
106 {
107     ISerNode::Ptr res;
108     if (auto i = interface_cast<IObjectInstance>(object)) {
109         RefUri ref(i->GetInstanceId().ToUid());
110         res = CreateObjectRefNode(ref);
111     }
112     return res;
113 }
114 
ExportObject(const IObject::ConstPtr & object,ISerNode::Ptr & res)115 ReturnError Exporter::ExportObject(const IObject::ConstPtr& object, ISerNode::Ptr& res)
116 {
117     ReturnError err = GenericError::SUCCESS;
118     if (ShouldSerialize(object)) {
119         if (MarkExported(object)) {
120             res = CreateObjectRefNode(object);
121         } else if (auto ser = interface_cast<ISerializable>(object)) {
122             ExportContext context(*this, object);
123             err = ser->Export(context);
124             if (err) {
125                 res = CreateObjectNode(object, context.ExtractNode());
126             }
127         } else {
128             res = AutoExportObject(object);
129         }
130     }
131     return err;
132 }
133 
AutoExportObject(const IObject::ConstPtr & object)134 ISerNode::Ptr Exporter::AutoExportObject(const IObject::ConstPtr& object)
135 {
136     BASE_NS::vector<NamedNode> members;
137     AutoExportObjectMembers(object, members);
138     return CreateObjectNode(object, BASE_NS::shared_ptr<MapNode>(new MapNode(members)));
139 }
140 
AutoExportObjectMembers(const IObject::ConstPtr & object,BASE_NS::vector<NamedNode> & members)141 ReturnError Exporter::AutoExportObjectMembers(const IObject::ConstPtr& object, BASE_NS::vector<NamedNode>& members)
142 {
143     if (auto flags = interface_cast<IObjectFlags>(object)) {
144         if (flags->GetObjectDefaultFlags() != flags->GetObjectFlags()) {
145             ISerNode::Ptr node;
146             auto res = ExportValue(Any<uint64_t>(flags->GetObjectFlags().GetValue()), node);
147             if (res && node) {
148                 members.push_back(NamedNode { "__flags", node });
149             }
150         }
151     }
152     if (auto attach = interface_cast<IAttach>(object)) {
153         if (IsFlagSet(object, ObjectFlagBits::SERIALIZE_ATTACHMENTS)) {
154             if (auto cont = attach->GetAttachmentContainer()) {
155                 if (auto node = ExportIContainer(*cont)) {
156                     members.push_back(NamedNode { "__attachments", node });
157                 }
158             }
159         }
160     }
161     if (auto cont = interface_cast<IContainer>(object)) {
162         if (IsFlagSet(object, ObjectFlagBits::SERIALIZE_HIERARCHY)) {
163             if (auto node = ExportIContainer(*cont)) {
164                 members.push_back(NamedNode { "__children", node });
165             }
166         }
167     }
168     return GenericError::SUCCESS;
169 }
170 
ExportIContainer(const IContainer & cont)171 ISerNode::Ptr Exporter::ExportIContainer(const IContainer& cont)
172 {
173     BASE_NS::vector<ISerNode::Ptr> elements;
174     for (size_t i = 0; i != cont.GetSize(); ++i) {
175         ISerNode::Ptr node;
176         if (ExportObject(cont.GetAt(i), node) && node) {
177             elements.push_back(BASE_NS::move(node));
178         }
179     }
180     return ISerNode::Ptr(new ArrayNode(BASE_NS::move(elements)));
181 }
182 
183 template<typename... Builtins>
ExportSingleBuiltinValue(TypeList<Builtins...>,const IAny & value)184 static ISerNode::Ptr ExportSingleBuiltinValue(TypeList<Builtins...>, const IAny& value)
185 {
186     ISerNode::Ptr res;
187     [[maybe_unused]] bool r =
188         ((META_NS::IsCompatible(value, Builtins::ID) ? (res = Builtins::CreateNode(value), true) : false) || ...);
189     return res;
190 }
191 
ExportArray(const IArrayAny & array)192 ISerNode::Ptr Exporter::ExportArray(const IArrayAny& array)
193 {
194     ISerNode::Ptr res;
195     auto any = array.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM });
196     if (any) {
197         BASE_NS::vector<ISerNode::Ptr> elements;
198         for (size_t i = 0; i != array.GetSize(); ++i) {
199             if (!array.GetAnyAt(i, *any)) {
200                 return nullptr;
201             }
202             ISerNode::Ptr node;
203             if (ExportValue(*any, node) && node) {
204                 elements.push_back(BASE_NS::move(node));
205             }
206         }
207         res.reset(new ArrayNode(BASE_NS::move(elements)));
208     }
209     return res;
210 }
211 
ExportBuiltinValue(const IAny & value)212 ISerNode::Ptr Exporter::ExportBuiltinValue(const IAny& value)
213 {
214     ISerNode::Ptr res;
215     if (auto arr = interface_cast<IArrayAny>(&value)) {
216         res = ExportArray(*arr);
217     } else {
218         if (value.GetTypeId() == UidFromType<float>()) {
219             // handle as double
220             res = ExportSingleBuiltinValue(SupportedBuiltins {}, Any<double>(GetValue<float>(value)));
221         } else {
222             res = ExportSingleBuiltinValue(SupportedBuiltins {}, value);
223         }
224     }
225     return res;
226 }
227 
ExportPointer(const IAny & entity,ISerNode::Ptr & res)228 ReturnError Exporter::ExportPointer(const IAny& entity, ISerNode::Ptr& res)
229 {
230     // first see if it is a weak pointer
231     BASE_NS::weak_ptr<const CORE_NS::IInterface> weak;
232     bool isWeak = entity.GetValue(weak);
233     if (isWeak) {
234         if (auto obj = interface_pointer_cast<IObject>(weak)) {
235             return ExportWeakPtr(obj, res);
236         }
237     }
238 
239     BASE_NS::shared_ptr<const CORE_NS::IInterface> intf;
240     if (entity.GetValue(intf)) {
241         // see if it is null pointer
242         if (!intf) {
243             res = ISerNode::Ptr(new NilNode);
244             return GenericError::SUCCESS;
245         }
246         // finally handle normal pointer case
247         if (!isWeak) {
248             if (auto obj = interface_pointer_cast<IObject>(intf)) {
249                 return ExportObject(obj, res);
250             }
251             if (auto any = interface_pointer_cast<IAny>(intf)) {
252                 return ExportAny(any, res);
253             }
254         }
255     }
256     return GenericError::FAIL;
257 }
258 
ExportValue(const IAny & entity,ISerNode::Ptr & res)259 ReturnError Exporter::ExportValue(const IAny& entity, ISerNode::Ptr& res)
260 {
261     if (!ShouldSerialize(entity)) {
262         return GenericError::SUCCESS;
263     }
264     if (auto exp = globalData_.GetValueSerializer(entity.GetTypeId())) {
265         res = exp->Export(*this, entity);
266         if (res) {
267             return GenericError::SUCCESS;
268         }
269         CORE_LOG_W("Value export registered for type [%s, %s] but it failed", entity.GetTypeIdString().c_str(),
270             entity.GetTypeId().ToString().c_str());
271     }
272     res = ExportBuiltinValue(entity);
273     if (!res) {
274         ExportPointer(entity, res);
275     }
276     if (!res) {
277         CORE_LOG_F(
278             "Failed to export type [%s, %s]", entity.GetTypeIdString().c_str(), entity.GetTypeId().ToString().c_str());
279         return GenericError::FAIL;
280     }
281     return GenericError::SUCCESS;
282 }
283 
ExportAny(const IAny::ConstPtr & any,ISerNode::Ptr & res)284 ReturnError Exporter::ExportAny(const IAny::ConstPtr& any, ISerNode::Ptr& res)
285 {
286     ReturnError err = GenericError::SUCCESS;
287     if (!registry_.GetPropertyRegister().IsAnyRegistered(any->GetClassId())) {
288         CORE_LOG_W("Exporting any that is not registered [class id=%s, type=%s, type id=%s]",
289             any->GetClassId().ToString().c_str(), any->GetTypeIdString().c_str(), any->GetTypeId().ToString().c_str());
290     }
291     if (!any) {
292         res = ISerNode::Ptr(new NilNode);
293     } else if (auto ser = interface_cast<ISerializable>(any)) {
294         ExportContext context(*this, interface_pointer_cast<IObject>(any));
295         err = ser->Export(context);
296         if (err) {
297             res =
298                 ISerNode::Ptr(new ObjectNode(BASE_NS::string("Any"), {}, any->GetClassId(), {}, context.ExtractNode()));
299         }
300     } else {
301         ISerNode::Ptr node;
302         err = ExportValue(*any, node);
303         if (err && node) {
304             auto members = CreateShared<MapNode>(BASE_NS::vector<NamedNode> { NamedNode { "value", node } });
305             res = ISerNode::Ptr(
306                 new ObjectNode(BASE_NS::string("Any"), {}, any->GetClassId(), {}, BASE_NS::move(members)));
307         }
308     }
309     return err;
310 }
311 
ResolveUriSegment(const IObject::ConstPtr & ptr,RefUri & uri) const312 IObject::Ptr Exporter::ResolveUriSegment(const IObject::ConstPtr& ptr, RefUri& uri) const
313 {
314     if (auto instance = interface_cast<IObjectInstance>(ptr)) {
315         if (auto context = interface_cast<IObjectContext>(ptr)) {
316             uri.PushObjectContextSegment();
317         } else {
318             uri.PushObjectSegment(instance->GetName());
319         }
320         return ptr->Resolve(RefUri::ParentUri());
321     }
322     if (auto property = interface_cast<IProperty>(ptr)) {
323         uri.PushPropertySegment(property->GetName());
324         auto owner = property->GetOwner().lock();
325         if (!owner) {
326             CORE_LOG_E("No Owner for property '%s' when exporting weak ptr", property->GetName().c_str());
327         }
328         return owner;
329     }
330     return nullptr;
331 }
332 
ResolveDeferredWeakPtr(const DeferredWeakPtrResolve & d)333 ReturnError Exporter::ResolveDeferredWeakPtr(const DeferredWeakPtrResolve& d)
334 {
335     if (auto p = d.ptr.lock()) {
336         auto original = p;
337         RefUri uri;
338         while (p) {
339             if (auto obj = interface_cast<IObjectInstance>(p)) {
340                 auto iid = ConvertInstanceId(obj->GetInstanceId());
341                 if (HasBeenExported(iid) || globalData_.GetGlobalObject(obj->GetInstanceId())) {
342                     uri.SetBaseObjectUid(iid.ToUid());
343                     d.node->SetValue(uri);
344                     return GenericError::SUCCESS;
345                 }
346             }
347             p = ResolveUriSegment(p, uri);
348         }
349         CORE_LOG_E("Could not find suitable anchor object when exporting weak ptr [%s, %s, %s]",
350             BASE_NS::string(original->GetClassName()).c_str(), original->GetName().c_str(),
351             original->GetClassId().ToString().c_str());
352     } else {
353         CORE_LOG_E("Weak ptr is null when doing deferred resolve");
354     }
355     return GenericError::FAIL;
356 }
357 
ExportWeakPtr(const IObject::ConstWeakPtr & ptr,ISerNode::Ptr & res)358 ReturnError Exporter::ExportWeakPtr(const IObject::ConstWeakPtr& ptr, ISerNode::Ptr& res)
359 {
360     if (auto p = ptr.lock()) {
361         auto node = CreateShared<RefNode>(RefUri {});
362         res = ISerNode::Ptr(node);
363         deferred_.push_back(DeferredWeakPtrResolve { node, ptr });
364     } else {
365         res = ISerNode::Ptr(new NilNode);
366     }
367     return GenericError::SUCCESS;
368 }
369 
ExportToNode(const IAny & entity,ISerNode::Ptr & res)370 ReturnError Exporter::ExportToNode(const IAny& entity, ISerNode::Ptr& res)
371 {
372     return ExportValue(entity, res);
373 }
374 
Export(BASE_NS::string_view name,const IAny & entity)375 ReturnError ExportContext::Export(BASE_NS::string_view name, const IAny& entity)
376 {
377     ISerNode::Ptr node;
378     auto res = exporter_.ExportValue(entity, node);
379     if (res && node) {
380         elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) });
381     }
382     if (!res) {
383         CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str());
384     }
385     return res;
386 }
387 
ExportAny(BASE_NS::string_view name,const IAny::Ptr & any)388 ReturnError ExportContext::ExportAny(BASE_NS::string_view name, const IAny::Ptr& any)
389 {
390     ISerNode::Ptr node;
391     auto res = exporter_.ExportAny(any, node);
392     if (res && node) {
393         elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) });
394     }
395     if (!res) {
396         CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str());
397     }
398     return res;
399 }
400 
ExportWeakPtr(BASE_NS::string_view name,const IObject::ConstWeakPtr & ptr)401 ReturnError ExportContext::ExportWeakPtr(BASE_NS::string_view name, const IObject::ConstWeakPtr& ptr)
402 {
403     ISerNode::Ptr node;
404     auto res = exporter_.ExportWeakPtr(ptr, node);
405     if (res && node) {
406         elements_.push_back(NamedNode { BASE_NS::string(name), BASE_NS::move(node) });
407     }
408     if (!res) {
409         CORE_LOG_W("Failed to export member with name '%s'", BASE_NS::string(name).c_str());
410     }
411     return res;
412 }
413 
AutoExport()414 ReturnError ExportContext::AutoExport()
415 {
416     if (object_) {
417         BASE_NS::vector<NamedNode> vec;
418         auto res = exporter_.AutoExportObjectMembers(object_, vec);
419         if (res) {
420             elements_.insert(elements_.end(), vec.begin(), vec.end());
421         }
422         return res;
423     }
424     CORE_LOG_W("Failed to auto export, exported type is not IObject");
425     return GenericError::FAIL;
426 }
427 
ExtractNode()428 BASE_NS::shared_ptr<MapNode> ExportContext::ExtractNode()
429 {
430     return BASE_NS::shared_ptr<MapNode>(new MapNode { BASE_NS::move(elements_) });
431 }
432 
ExportToNode(const IAny & entity,ISerNode::Ptr & res)433 ReturnError ExportContext::ExportToNode(const IAny& entity, ISerNode::Ptr& res)
434 {
435     return exporter_.ExportToNode(entity, res);
436 }
437 
438 } // namespace Serialization
439 META_END_NAMESPACE()
440