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 "object_registry.h"
17 
18 #include <chrono>
19 
20 #include <base/containers/fixed_string.h>
21 #include <base/util/compile_time_hashes.h>
22 #include <base/util/uid_util.h>
23 
24 #include <meta/interface/animation/builtin_animations.h>
25 #include <meta/interface/intf_derived.h>
26 
27 #include "any.h"
28 #include "call_context.h"
29 #include "metadata.h"
30 #include "property/bind.h"
31 #include "property/stack_property.h"
32 #include "random.h"
33 
34 #define OBJ_REG_LOG(...)
35 
36 /*
37     Notes:
38       * Currently Unregistering object and creating it at the same time can cause the pointer ObjectTypeInfo still
39             be used after the Unregister function returns.
40       * Same issue applies to creating and unregistering property.
41 */
42 
43 META_BEGIN_NAMESPACE()
44 
45 const size_t DISPOSAL_THRESHOLD = 100;
46 
GenerateInstanceId(uint64_t random)47 static BASE_NS::Uid GenerateInstanceId(uint64_t random)
48 {
49     // NOTE: instance uid:s are generated from 64 bit random number and 64 bit timestamp
50     auto elapsed = std::chrono::high_resolution_clock::now();
51     auto high = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed.time_since_epoch()).count();
52 
53     BASE_NS::Uid uid;
54     uid.data[0] = high;
55     uid.data[1] = random;
56     return uid;
57 }
58 
ObjectRegistry()59 ObjectRegistry::ObjectRegistry() : random_(CreateXoroshiro128(BASE_NS::FNV1aHash("ToolKitObjectRegistry"))) {}
60 
~ObjectRegistry()61 ObjectRegistry::~ObjectRegistry()
62 {
63     queues_.clear();
64     defaultContext_.reset();
65     classRegistry_.Clear();
66     // Just for sanity.
67     GC();
68     //  And to make sure all "objects" are unregistered. (we have some that never un-register)
69     //  doing it one at a time, because unregister will modify the list..
70     bool first = true;
71     auto& pluginRegistry = CORE_NS::GetPluginRegister();
72     for (;;) {
73         const auto& types = pluginRegistry.GetTypeInfos(ObjectTypeInfo::UID);
74         if (types.empty()) {
75             break;
76         }
77         auto object = static_cast<const ObjectTypeInfo* const>(types[0]);
78         if (first) {
79             CORE_LOG_F("Object classes not unregistered before object registry death. (force unregister)");
80             first = false;
81         }
82         auto& classInfo = object->GetFactory()->GetClassInfo();
83         CORE_LOG_F(
84             "Name: [%s] ClassId [%s]", BASE_NS::string(classInfo.Name()).c_str(), classInfo.Id().ToString().c_str());
85         pluginRegistry.UnregisterTypeInfo(*types[0]);
86     }
87 }
88 
GetClassRegistry()89 IClassRegistry& ObjectRegistry::GetClassRegistry()
90 {
91     return classRegistry_;
92 }
93 
RegisterToPluginRegistry(const ObjectTypeInfo & info)94 static void RegisterToPluginRegistry(const ObjectTypeInfo& info)
95 {
96     auto& pluginRegistry = CORE_NS::GetPluginRegister();
97     const auto& types = pluginRegistry.GetTypeInfos(ObjectTypeInfo::UID);
98     for (auto it = types.begin(); it != types.end(); it++) {
99         auto object = static_cast<const ObjectTypeInfo* const>(*it);
100         if (*object == info) {
101             return;
102         }
103     }
104     pluginRegistry.RegisterTypeInfo(info);
105 }
106 
UnregisterFromPluginRegistry(const BASE_NS::Uid & uid)107 static void UnregisterFromPluginRegistry(const BASE_NS::Uid& uid)
108 {
109     auto& pluginRegistry = CORE_NS::GetPluginRegister();
110     const auto& types = pluginRegistry.GetTypeInfos(ObjectTypeInfo::UID);
111     for (auto it = types.begin(); it != types.end(); it++) {
112         auto object = static_cast<const ObjectTypeInfo* const>(*it);
113         if (object->GetFactory()->GetClassInfo().Id() == ObjectId(uid)) {
114             pluginRegistry.UnregisterTypeInfo(**it);
115             break;
116         }
117     }
118 }
119 
RegisterObjectType(const IClassInfo::Ptr & classInfo)120 bool ObjectRegistry::RegisterObjectType(const IClassInfo::Ptr& classInfo)
121 {
122     if (!classInfo) {
123         return false;
124     }
125     const auto factory = interface_pointer_cast<IObjectFactory>(classInfo);
126     if (!factory) {
127         CORE_LOG_E("ObjectRegistry: The class (%s) being registered does not provide object factory",
128             classInfo->GetClassInfo().Name().data());
129     }
130     if (!classRegistry_.Register(factory)) {
131         return false;
132     }
133 
134     // Construct dummy object of that type to get the static metadata initialised
135     BASE_NS::vector<IObject::Ptr> classes;
136     auto res = CreateInternal(factory->GetClassInfo().Id().ToUid(), classes);
137     if (res.successful && !classes.empty()) {
138         // for now we need to set the super classes to safely destroy some objects, using dummy instance id
139         SetObjectInstanceIds(classes, BASE_NS::Uid {});
140     } else {
141         CORE_LOG_W("Failed to create object when generating static metadata [uid=%s]",
142             BASE_NS::to_string(factory->GetClassInfo().Id().ToUid()).c_str());
143     }
144     return true;
145 }
146 
UnregisterObjectType(const IClassInfo::Ptr & classInfo)147 bool ObjectRegistry::UnregisterObjectType(const IClassInfo::Ptr& classInfo)
148 {
149     if (const auto factory = interface_pointer_cast<IObjectFactory>(classInfo)) {
150         return classRegistry_.Unregister(factory);
151     }
152     return false;
153 }
154 
GetClassName(BASE_NS::Uid uid) const155 BASE_NS::string ObjectRegistry::GetClassName(BASE_NS::Uid uid) const
156 {
157     return classRegistry_.GetClassName(uid);
158 }
159 
CreateInternal(BASE_NS::Uid uid,BASE_NS::vector<IObject::Ptr> & classes) const160 ObjectRegistry::CreateResult ObjectRegistry::CreateInternal(
161     BASE_NS::Uid uid, BASE_NS::vector<IObject::Ptr>& classes) const
162 {
163     IObject::Ptr obj;
164     ClassInfo info;
165     if (auto fac = classRegistry_.GetObjectFactory(uid)) {
166         obj = fac->CreateInstance();
167         if (obj) {
168             info = fac->GetClassInfo();
169             return CreateResult { ConstructObjectInternal(obj, classes), info.category, info.IsSingleton() };
170         }
171     }
172     return { false, 0, false };
173 }
174 
ConstructObjectInternal(const IObject::Ptr & obj,BASE_NS::vector<IObject::Ptr> & classes) const175 bool ObjectRegistry::ConstructObjectInternal(const IObject::Ptr& obj, BASE_NS::vector<IObject::Ptr>& classes) const
176 {
177     classes.push_back(obj);
178     if (auto agr = obj->GetInterface<IDerived>()) {
179         auto superUid = agr->GetSuperClassUid();
180         if (superUid != BASE_NS::Uid {}) {
181             OBJ_REG_LOG("\tCreate super of %s", GetClassName(superUid).c_str());
182             auto super = CreateInternal(superUid, classes);
183             if (!super.successful) {
184                 // failed to create super class.
185                 CORE_LOG_F("Could not create the super class [uid=%s]", BASE_NS::to_string(superUid).c_str());
186                 return false;
187             }
188         }
189     }
190     return true;
191 }
192 
SetObjectInstanceIds(const BASE_NS::vector<IObject::Ptr> & classes,InstanceId instid) const193 void ObjectRegistry::SetObjectInstanceIds(const BASE_NS::vector<IObject::Ptr>& classes, InstanceId instid) const
194 {
195     IObject::Ptr obj = classes.front();
196     IObject::Ptr base;
197 
198     // Prepare object hierarchy for building by setting instance ids and super objects
199     for (auto it = classes.rbegin(); it != classes.rend(); ++it) {
200         if (auto o = (*it)->GetInterface<ILifecycle>()) {
201             o->SetInstanceId(instid);
202         }
203         if (auto der = (*it)->GetInterface<IDerived>()) {
204             if (base) {
205                 OBJ_REG_LOG("\tAssigning instance of %s as super to %s", BASE_NS::string(base->GetClassName()).c_str(),
206                     BASE_NS::string((*it)->GetClassName()).c_str());
207             }
208             der->SetSuperInstance(obj, base);
209         }
210         base = *it;
211     }
212 }
213 
BuildObject(const BASE_NS::vector<IObject::Ptr> & classes,const IMetadata::Ptr & data) const214 bool ObjectRegistry::BuildObject(const BASE_NS::vector<IObject::Ptr>& classes, const IMetadata::Ptr& data) const
215 {
216     if (classes.empty()) {
217         return false;
218     }
219     IObject::Ptr obj = classes.front();
220     IMetadata::Ptr meta = ConstructMetadata();
221 
222     // Set metadata first so that one can use IMetadata via GetSelf in the non-top classes' Build
223     for (auto it = classes.rbegin(); it != classes.rend(); ++it) {
224         if (auto i = (*it)->GetInterface<IMetadataInternal>()) {
225             i->SetMetadata(meta);
226         }
227     }
228     // call build for the object hierarchy
229     for (auto it = classes.rbegin(); it != classes.rend(); ++it) {
230         if (auto ctor = (*it)->GetInterface<ILifecycle>()) {
231             OBJ_REG_LOG("\tBuilding %s", BASE_NS::string((*it)->GetClassName()).c_str());
232             if (!ctor->Build(data)) {
233                 return false;
234             }
235         }
236     }
237     return true;
238 }
239 
Create(ObjectId uid,const CreateInfo & createInfo,const IMetadata::Ptr & data) const240 IObject::Ptr ObjectRegistry::Create(ObjectId uid, const CreateInfo& createInfo, const IMetadata::Ptr& data) const
241 {
242     CheckGC();
243 
244     auto instid = createInfo.instanceId;
245 
246     if (instid == BASE_NS::Uid {}) {
247         std::unique_lock lock { mutex_ };
248         if (auto so = FindSingleton(uid.ToUid())) {
249             return so;
250         }
251         instid = GenerateInstanceId(random_->GetRandom());
252     } else {
253         std::shared_lock lock { mutex_ };
254         if (auto so = FindSingleton(uid.ToUid())) {
255             return so;
256         }
257         // make sure that an object with specified instanceid does not exist already.
258         auto it = instancesByUid_.find(instid);
259         if (it != instancesByUid_.end() && !it->second.ptr.expired()) {
260             CORE_LOG_F("Object with instance id %s already exists.", instid.ToString().c_str());
261             return {};
262         }
263     }
264     OBJ_REG_LOG("Create instance of %s {instance id %s}", GetClassName(uid).c_str(), instid.ToString().c_str());
265     BASE_NS::vector<IObject::Ptr> classes;
266     auto t = CreateInternal(uid.ToUid(), classes);
267     if (t.successful && !classes.empty()) {
268         if (PostCreate(uid.ToUid(), instid.ToUid(), t, createInfo, classes, data)) {
269             return classes.front();
270         }
271     }
272 
273     CORE_LOG_F("Could not create instance of %s", GetClassName(uid.ToUid()).c_str());
274     return nullptr;
275 }
276 
PostCreate(const BASE_NS::Uid & uid,InstanceId instid,const CreateResult & t,const CreateInfo & createInfo,const BASE_NS::vector<IObject::Ptr> & classes,const IMetadata::Ptr & data) const277 bool ObjectRegistry::PostCreate(const BASE_NS::Uid& uid, InstanceId instid, const CreateResult& t,
278     const CreateInfo& createInfo, const BASE_NS::vector<IObject::Ptr>& classes, const IMetadata::Ptr& data) const
279 {
280     SetObjectInstanceIds(classes, instid);
281 
282     if (!BuildObject(classes, data)) {
283         CORE_LOG_F("Failed to build object (%s).", GetClassName(uid).c_str());
284         return false;
285     }
286 
287     std::unique_lock lock { mutex_ };
288     auto& i = instancesByUid_[instid];
289     if (!i.ptr.expired()) {
290         // seems someone beat us to it
291         CORE_LOG_F("Object with instance id %s already exists.", instid.ToString().c_str());
292         return false;
293     }
294     i = ObjectInstance { classes.front(), t.category };
295 
296     if (t.singleton) {
297         singletons_[uid] = classes.front(); // Store singleton weakref
298     }
299     if (createInfo.isGloballyAvailable) {
300         CORE_LOG_D("Registering global object: %s [%s]", GetClassName(uid).c_str(), instid.ToString().c_str());
301         globalObjects_[instid] = classes.front();
302     }
303     return true;
304 }
305 
Create(ObjectId uid,const CreateInfo & createInfo) const306 IObject::Ptr ObjectRegistry::Create(ObjectId uid, const CreateInfo& createInfo) const
307 {
308     return Create(uid, createInfo, nullptr);
309 }
310 
Create(const META_NS::ClassInfo & info,const CreateInfo & createInfo) const311 IObject::Ptr ObjectRegistry::Create(const META_NS::ClassInfo& info, const CreateInfo& createInfo) const
312 {
313     return Create(info.Id(), createInfo);
314 }
315 
GetAllCategories() const316 BASE_NS::vector<ObjectCategoryItem> ObjectRegistry::GetAllCategories() const
317 {
318     static const BASE_NS::vector<ObjectCategoryItem> items = { { ObjectCategoryBits::WIDGET, "Widgets" },
319         { ObjectCategoryBits::ANIMATION, "Animations" }, { ObjectCategoryBits::LAYOUT, "Layouts" },
320         { ObjectCategoryBits::CURVE, "Curves" }, { ObjectCategoryBits::SHAPE, "Shapes" },
321         { ObjectCategoryBits::CONTAINER, "Containers" }, { ObjectCategoryBits::INTERNAL, "Internals" },
322         { ObjectCategoryBits::APPLICATION, "Application specifics" },
323         { ObjectCategoryBits::ANIMATION_MODIFIER, "Animation modifier" },
324         { ObjectCategoryBits::NO_CATEGORY, "Not categorized" } };
325     return items;
326 }
327 
GetObjectFactory(const ObjectId & uid) const328 IObjectFactory::ConstPtr ObjectRegistry::GetObjectFactory(const ObjectId& uid) const
329 {
330     std::shared_lock lock { mutex_ };
331     return classRegistry_.GetObjectFactory(uid.ToUid());
332 }
333 
GetAllTypes(ObjectCategoryBits category,bool strict,bool excludeDeprecated) const334 BASE_NS::vector<IClassInfo::ConstPtr> ObjectRegistry::GetAllTypes(
335     ObjectCategoryBits category, bool strict, bool excludeDeprecated) const
336 {
337     std::shared_lock lock { mutex_ };
338     return classRegistry_.GetAllTypes(category, strict, excludeDeprecated);
339 }
340 
CheckGC() const341 void ObjectRegistry::CheckGC() const
342 {
343     if (purgeCounter_ > DISPOSAL_THRESHOLD && disposalInProgress_.test_and_set()) {
344         {
345             std::unique_lock lock { disposalMutex_ };
346             disposalsStorage_.swap(disposals_);
347             purgeCounter_ = 0;
348         }
349         DoDisposal(disposalsStorage_);
350         disposalsStorage_.clear();
351         disposalInProgress_.clear();
352     }
353 }
354 
GC() const355 void ObjectRegistry::GC() const
356 {
357     for (auto it = instancesByUid_.begin(); it != instancesByUid_.end();) {
358         if (it->second.ptr.expired()) {
359             it = instancesByUid_.erase(it);
360         } else {
361             ++it;
362         }
363     }
364     for (auto it = singletons_.begin(); it != singletons_.end();) {
365         if (it->second.expired()) {
366             it = singletons_.erase(it);
367         } else {
368             ++it;
369         }
370     }
371     for (auto it = globalObjects_.begin(); it != globalObjects_.end();) {
372         if (it->second.expired()) {
373             it = globalObjects_.erase(it);
374         } else {
375             ++it;
376         }
377     }
378 }
379 
Purge()380 void ObjectRegistry::Purge()
381 {
382     std::unique_lock lock { mutex_ };
383     GC();
384 }
385 
DoDisposal(const BASE_NS::vector<InstanceId> & uids) const386 void ObjectRegistry::DoDisposal(const BASE_NS::vector<InstanceId>& uids) const
387 {
388     std::unique_lock lock { mutex_ };
389     for (auto&& v : uids) {
390         auto it = instancesByUid_.find(v);
391         if (it != instancesByUid_.end()) {
392             instancesByUid_.erase(it);
393             auto it = singletons_.find(v);
394             if (it != singletons_.end()) {
395                 singletons_.erase(it);
396             }
397         }
398     }
399 }
400 
DisposeObject(const InstanceId & uid) const401 void ObjectRegistry::DisposeObject(const InstanceId& uid) const
402 {
403     std::unique_lock lock { disposalMutex_ };
404     disposals_.push_back(uid);
405     ++purgeCounter_;
406 }
407 
ConstructMetadata() const408 IMetadata::Ptr ObjectRegistry::ConstructMetadata() const
409 {
410     return IMetadata::Ptr { new Internal::Metadata };
411 }
412 
ConstructDefaultCallContext() const413 ICallContext::Ptr ObjectRegistry::ConstructDefaultCallContext() const
414 {
415     return ICallContext::Ptr { new DefaultCallContext };
416 }
417 
GetAllObjectInstances() const418 BASE_NS::vector<IObject::Ptr> ObjectRegistry::GetAllObjectInstances() const
419 {
420     CheckGC();
421     BASE_NS::vector<IObject::Ptr> result;
422     std::shared_lock lock { mutex_ };
423     result.reserve(instancesByUid_.size());
424     for (const auto& v : instancesByUid_) {
425         if (auto strong = v.second.ptr.lock()) {
426             result.emplace_back(strong);
427         }
428     }
429     return result;
430 }
431 
GetAllSingletonObjectInstances() const432 BASE_NS::vector<IObject::Ptr> ObjectRegistry::GetAllSingletonObjectInstances() const
433 {
434     CheckGC();
435     BASE_NS::vector<IObject::Ptr> result;
436     std::shared_lock lock { mutex_ };
437     if (!singletons_.empty()) {
438         result.reserve(singletons_.size());
439         for (const auto& s : singletons_) {
440             if (auto strong = s.second.lock()) {
441                 result.push_back(strong);
442             }
443         }
444     }
445     return result;
446 }
447 
GetObjectInstancesByCategory(ObjectCategoryBits category,bool strict) const448 BASE_NS::vector<IObject::Ptr> ObjectRegistry::GetObjectInstancesByCategory(
449     ObjectCategoryBits category, bool strict) const
450 {
451     CheckGC();
452     BASE_NS::vector<IObject::Ptr> result;
453     std::shared_lock lock { mutex_ };
454     for (const auto& i : instancesByUid_) {
455         if (CheckCategoryBits(static_cast<ObjectCategoryBits>(i.second.category), category, strict)) {
456             if (auto strong = i.second.ptr.lock()) {
457                 result.emplace_back(strong);
458             }
459         }
460     }
461     return result;
462 }
463 
FindSingleton(const BASE_NS::Uid uid) const464 IObject::Ptr ObjectRegistry::FindSingleton(const BASE_NS::Uid uid) const
465 {
466     auto it = singletons_.find(uid);
467     return it != singletons_.end() ? it->second.lock() : nullptr;
468 }
469 
GetObjectInstanceByInstanceId(InstanceId uid) const470 IObject::Ptr ObjectRegistry::GetObjectInstanceByInstanceId(InstanceId uid) const
471 {
472     if (uid == BASE_NS::Uid()) {
473         // invalid/zero/empty UID.
474         return nullptr;
475     }
476 
477     CheckGC();
478 
479     std::shared_lock lock { mutex_ };
480 
481     // See if it's an singleton.
482     auto sing = FindSingleton(uid.ToUid());
483     if (sing) {
484         return sing;
485     }
486 
487     // Non singletons then
488     auto it2 = instancesByUid_.find(uid);
489     if (it2 != instancesByUid_.end()) {
490         if (auto strong = it2->second.ptr.lock()) {
491             return strong;
492         }
493     }
494 
495     // No such instance then
496     return nullptr;
497 }
498 
ExportToString(const IObjectRegistryExporter::Ptr & exporter) const499 BASE_NS::string ObjectRegistry::ExportToString(const IObjectRegistryExporter::Ptr& exporter) const
500 {
501     return exporter ? exporter->ExportRegistry(this) : "";
502 }
503 
GetDefaultObjectContext() const504 IObjectContext::Ptr ObjectRegistry::GetDefaultObjectContext() const
505 {
506     {
507         std::shared_lock lock { mutex_ };
508         if (defaultContext_) {
509             return defaultContext_;
510         }
511     }
512 
513     IObjectContext::Ptr context = interface_pointer_cast<IObjectContext>(
514         Create(ClassId::ObjectContext, { GlobalObjectInstance::DEFAULT_OBJECT_CONTEXT, true }));
515 
516     std::unique_lock lock { mutex_ };
517     // still not set?
518     if (!defaultContext_) {
519         defaultContext_ = context;
520     }
521     CORE_ASSERT(defaultContext_);
522     return defaultContext_;
523 }
524 
GetTaskQueue(const BASE_NS::Uid & queueId) const525 ITaskQueue::Ptr ObjectRegistry::GetTaskQueue(const BASE_NS::Uid& queueId) const
526 {
527     std::shared_lock lock { mutex_ };
528     if (auto queue = queues_.find(queueId); queue != queues_.end()) {
529         return queue->second;
530     }
531     CORE_LOG_W("Cannot get task queue, task queue not registered: %s", BASE_NS::to_string(queueId).data());
532     return {};
533 }
534 
RegisterTaskQueue(const ITaskQueue::Ptr & queue,const BASE_NS::Uid & queueId)535 bool ObjectRegistry::RegisterTaskQueue(const ITaskQueue::Ptr& queue, const BASE_NS::Uid& queueId)
536 {
537     std::unique_lock lock { mutex_ };
538     if (!queue) {
539         if (auto existing = queues_.find(queueId); existing != queues_.end()) {
540             queues_.erase(existing);
541             return true;
542         }
543         // Null queue but no existing queue found
544         return false;
545     }
546     queues_[queueId] = queue;
547     return true;
548 }
549 
UnregisterTaskQueue(const BASE_NS::Uid & queueId)550 bool ObjectRegistry::UnregisterTaskQueue(const BASE_NS::Uid& queueId)
551 {
552     std::unique_lock lock { mutex_ };
553     if (auto existing = queues_.find(queueId); existing != queues_.end()) {
554         queues_.erase(existing);
555         return true;
556     }
557     return false;
558 }
559 
HasTaskQueue(const BASE_NS::Uid & queueId) const560 bool ObjectRegistry::HasTaskQueue(const BASE_NS::Uid& queueId) const
561 {
562     std::shared_lock lock { mutex_ };
563     return queues_.find(queueId) != queues_.end();
564 }
565 
UnregisterAllTaskQueues()566 bool ObjectRegistry::UnregisterAllTaskQueues()
567 {
568     std::unique_lock lock { mutex_ };
569     queues_.clear();
570     return true;
571 }
572 
GetCurrentTaskQueueImpl()573 static ITaskQueue::WeakPtr& GetCurrentTaskQueueImpl()
574 {
575     static thread_local ITaskQueue::WeakPtr q;
576     return q;
577 }
578 
GetCurrentTaskQueue() const579 ITaskQueue::Ptr ObjectRegistry::GetCurrentTaskQueue() const
580 {
581     return GetCurrentTaskQueueImpl().lock();
582 }
SetCurrentTaskQueue(ITaskQueue::WeakPtr q)583 ITaskQueue::WeakPtr ObjectRegistry::SetCurrentTaskQueue(ITaskQueue::WeakPtr q)
584 {
585     auto& impl = GetCurrentTaskQueueImpl();
586     auto res = impl;
587     impl = q;
588     return res;
589 }
590 
RegisterInterpolator(TypeId propertyTypeUid,BASE_NS::Uid interpolatorClassUid)591 void ObjectRegistry::RegisterInterpolator(TypeId propertyTypeUid, BASE_NS::Uid interpolatorClassUid)
592 {
593     std::unique_lock lock { mutex_ };
594     interpolatorConstructors_[propertyTypeUid] = interpolatorClassUid;
595 }
596 
UnregisterInterpolator(TypeId propertyTypeUid)597 void ObjectRegistry::UnregisterInterpolator(TypeId propertyTypeUid)
598 {
599     std::unique_lock lock { mutex_ };
600     interpolatorConstructors_.erase(propertyTypeUid);
601 }
602 
HasInterpolator(TypeId propertyTypeUid) const603 bool ObjectRegistry::HasInterpolator(TypeId propertyTypeUid) const
604 {
605     std::shared_lock lock { mutex_ };
606     return interpolatorConstructors_.contains(propertyTypeUid);
607 }
608 
CreateInterpolator(TypeId propertyTypeUid)609 IInterpolator::Ptr ObjectRegistry::CreateInterpolator(TypeId propertyTypeUid)
610 {
611     TypeId uid;
612     {
613         std::shared_lock lock { mutex_ };
614         if (auto it = interpolatorConstructors_.find(propertyTypeUid); it != interpolatorConstructors_.end()) {
615             uid = it->second;
616         }
617     }
618     if (uid != TypeId {}) {
619         return interface_pointer_cast<IInterpolator>(Create(uid.ToUid(), CreateInfo {}));
620     }
621     // We don't have an interpolator for the given property type, return the default interpolator (which just steps the
622     // value)
623     CORE_LOG_D("No interpolator for property type %s, falling back to default interpolator",
624         propertyTypeUid.ToString().c_str());
625     return interface_pointer_cast<IInterpolator>(IObjectRegistry::Create(ClassId::DefaultInterpolator));
626 }
627 
GetInterface(const BASE_NS::Uid & uid) const628 const CORE_NS::IInterface* ObjectRegistry::GetInterface(const BASE_NS::Uid& uid) const
629 {
630     const CORE_NS::IInterface* result = nullptr;
631     if (uid == CORE_NS::IInterface::UID) {
632         const IObjectRegistry* obj = static_cast<const IObjectRegistry*>(this);
633         result = static_cast<const IInterface*>(obj);
634     }
635     if (uid == IObjectRegistry::UID) {
636         result = static_cast<const IObjectRegistry*>(this);
637     }
638     if (uid == ITaskQueueRegistry::UID) {
639         result = static_cast<const ITaskQueueRegistry*>(this);
640     }
641     return result;
642 }
GetInterface(const BASE_NS::Uid & uid)643 CORE_NS::IInterface* ObjectRegistry::GetInterface(const BASE_NS::Uid& uid)
644 {
645     CORE_NS::IInterface* result = nullptr;
646     if (uid == CORE_NS::IInterface::UID) {
647         IObjectRegistry* obj = static_cast<IObjectRegistry*>(this);
648         result = static_cast<IInterface*>(obj);
649     }
650     if (uid == IObjectRegistry::UID) {
651         result = static_cast<IObjectRegistry*>(this);
652     }
653     if (uid == ITaskQueueRegistry::UID) {
654         result = static_cast<ITaskQueueRegistry*>(this);
655     }
656     return result;
657 }
Ref()658 void ObjectRegistry::Ref() {}
Unref()659 void ObjectRegistry::Unref() {}
660 
GetPropertyRegister()661 META_NS::IPropertyRegister& ObjectRegistry::GetPropertyRegister()
662 {
663     return *this;
664 }
665 
Create(const ObjectId & object,BASE_NS::string_view name) const666 META_NS::IProperty::Ptr ObjectRegistry::Create(const ObjectId& object, BASE_NS::string_view name) const
667 {
668     if (object == ClassId::StackProperty) {
669         auto p = META_NS::IProperty::Ptr(new META_NS::Internal::StackProperty(BASE_NS::string(name)));
670         if (auto i = interface_cast<IPropertyInternal>(p)) {
671             i->SetSelf(p);
672         }
673         return p;
674     }
675     return nullptr;
676 }
CreateBind() const677 IBind::Ptr ObjectRegistry::CreateBind() const
678 {
679     return interface_pointer_cast<IBind>(Create(ClassId::Bind, CreateInfo {}));
680 }
InvalidAny() const681 IAny& ObjectRegistry::InvalidAny() const
682 {
683     static DummyAny any;
684     return any;
685 }
ConstructAny(const ObjectId & id) const686 IAny::Ptr ObjectRegistry::ConstructAny(const ObjectId& id) const
687 {
688     std::shared_lock lock { mutex_ };
689     auto it = anyBuilders_.find(id);
690     return it != anyBuilders_.end() ? it->second->Construct() : nullptr;
691 }
IsAnyRegistered(const ObjectId & id) const692 bool ObjectRegistry::IsAnyRegistered(const ObjectId& id) const
693 {
694     std::shared_lock lock { mutex_ };
695     return anyBuilders_.find(id) != anyBuilders_.end();
696 }
RegisterAny(BASE_NS::shared_ptr<AnyBuilder> builder)697 void ObjectRegistry::RegisterAny(BASE_NS::shared_ptr<AnyBuilder> builder)
698 {
699     std::unique_lock lock { mutex_ };
700     if (anyBuilders_.find(builder->GetObjectId()) != anyBuilders_.end()) {
701         CORE_LOG_W("Any already registered [id=%s]", builder->GetObjectId().ToString().c_str());
702     }
703     anyBuilders_[builder->GetObjectId()] = builder;
704 }
UnregisterAny(const ObjectId & id)705 void ObjectRegistry::UnregisterAny(const ObjectId& id)
706 {
707     std::unique_lock lock { mutex_ };
708     anyBuilders_.erase(id);
709 }
GetGlobalSerializationData()710 IGlobalSerializationData& ObjectRegistry::GetGlobalSerializationData()
711 {
712     return *this;
713 }
GetDefaultSettings() const714 SerializationSettings ObjectRegistry::GetDefaultSettings() const
715 {
716     std::shared_lock lock { mutex_ };
717     return defaultSettings_;
718 }
SetDefaultSettings(const SerializationSettings & settings)719 void ObjectRegistry::SetDefaultSettings(const SerializationSettings& settings)
720 {
721     std::unique_lock lock { mutex_ };
722     defaultSettings_ = settings;
723 }
RegisterGlobalObject(const IObject::Ptr & object)724 void ObjectRegistry::RegisterGlobalObject(const IObject::Ptr& object)
725 {
726     std::unique_lock lock { mutex_ };
727     if (auto p = interface_cast<IObjectInstance>(object)) {
728         globalObjects_[p->GetInstanceId()] = object;
729     }
730 }
UnregisterGlobalObject(const IObject::Ptr & object)731 void ObjectRegistry::UnregisterGlobalObject(const IObject::Ptr& object)
732 {
733     std::unique_lock lock { mutex_ };
734     if (auto p = interface_cast<IObjectInstance>(object)) {
735         globalObjects_.erase(p->GetInstanceId());
736     }
737 }
GetGlobalObject(const InstanceId & id) const738 IObject::Ptr ObjectRegistry::GetGlobalObject(const InstanceId& id) const
739 {
740     std::shared_lock lock { mutex_ };
741     auto it = globalObjects_.find(id);
742     return it != globalObjects_.end() ? it->second.lock() : nullptr;
743 }
RegisterValueSerializer(const IValueSerializer::Ptr & s)744 void ObjectRegistry::RegisterValueSerializer(const IValueSerializer::Ptr& s)
745 {
746     std::unique_lock lock { mutex_ };
747     valueSerializers_[s->GetTypeId()] = s;
748 }
UnregisterValueSerializer(const TypeId & id)749 void ObjectRegistry::UnregisterValueSerializer(const TypeId& id)
750 {
751     std::unique_lock lock { mutex_ };
752     valueSerializers_.erase(id);
753 }
GetValueSerializer(const TypeId & id) const754 IValueSerializer::Ptr ObjectRegistry::GetValueSerializer(const TypeId& id) const
755 {
756     std::shared_lock lock { mutex_ };
757     auto it = valueSerializers_.find(id);
758     return it != valueSerializers_.end() ? it->second : nullptr;
759 }
760 
GetInternalValueAccess(const CORE_NS::PropertyTypeDecl & type) const761 IEngineInternalValueAccess::Ptr ObjectRegistry::GetInternalValueAccess(const CORE_NS::PropertyTypeDecl& type) const
762 {
763     std::shared_lock lock { mutex_ };
764     auto it = engineInternalAccess_.find(type);
765     return it != engineInternalAccess_.end() ? it->second : nullptr;
766 }
RegisterInternalValueAccess(const CORE_NS::PropertyTypeDecl & type,IEngineInternalValueAccess::Ptr ptr)767 void ObjectRegistry::RegisterInternalValueAccess(
768     const CORE_NS::PropertyTypeDecl& type, IEngineInternalValueAccess::Ptr ptr)
769 {
770     std::unique_lock lock { mutex_ };
771     engineInternalAccess_[type] = BASE_NS::move(ptr);
772 }
UnregisterInternalValueAccess(const CORE_NS::PropertyTypeDecl & type)773 void ObjectRegistry::UnregisterInternalValueAccess(const CORE_NS::PropertyTypeDecl& type)
774 {
775     std::unique_lock lock { mutex_ };
776     engineInternalAccess_.erase(type);
777 }
GetEngineData()778 IEngineData& ObjectRegistry::GetEngineData()
779 {
780     return *this;
781 }
782 META_END_NAMESPACE()
783