* 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 "engine_value.h"
#include <algorithm>
#include <core/property/intf_property_api.h>
#include <meta/interface/engine/intf_engine_value_manager.h>
#include "../any.h"
#include "engine_dirty_list.h"
META_BEGIN_NAMESPACE()
namespace Internal {
EngineValue::EngineValue(
BASE_NS::string name, IEngineInternalValueAccess::ConstPtr access, const EnginePropertyParams& p)
: Super(ObjectFlagBits::INTERNAL | ObjectFlagBits::SERIALIZE),
params_(p),
access_(BASE_NS::move(access)),
name_(BASE_NS::move(name)),
value_(access_->CreateAny(p.property))
{}
EngineValue::~EngineValue() = default;
bool EngineValue::HasChangeCallbacks() const
{
return changeCallbacks_.HasCallbacks();
}
bool EngineValue::CanSkipFromEngineSync() const
{
return flags_.IsSet(ValueFlags::INITIALIZED) && !changeCallbacks_.HasCallbacks();
}
AnyReturnValue EngineValue::Sync(EngineSyncDirection dir)
{
if (!params_.handle) {
return AnyReturn::INVALID_ARGUMENT;
}
if (dir == EngineSyncDirection::TO_ENGINE ||
(dir == EngineSyncDirection::AUTO && flags_.IsSet(ValueFlags::VALUE_CHANGED))) {
if (flags_.IsSet(ValueFlags::VALUE_CHANGED)) {
auto res = access_->SyncToEngine(*value_, params_);
if (res) {
flags_.Clear(ValueFlags::VALUE_CHANGED);
}
return res ? AnyReturn::NOTHING_TO_DO : AnyReturn::FAIL;
}
return params_.handle.Handle() ? AnyReturn::NOTHING_TO_DO : AnyReturn::FAIL;
}
auto res = access_->SyncFromEngine(params_, *value_);
bool firstSync = !flags_.IsSet(ValueFlags::INITIALIZED);
flags_.Set(ValueFlags::INITIALIZED);
if (!res && params_.containerMethods) {
return AnyReturn::NOTHING_TO_DO;
}
if (!firstSync && res && res != AnyReturn::NOTHING_TO_DO) {
flags_.Set(ValueFlags::PENDING_NOTIFY);
}
return res;
}
AnyReturnValue EngineValue::SetValue(const IAny& value)
{
AnyReturnValue res = value_->CopyFrom(value);
bool wasDirty = flags_.IsSet(ValueFlags::VALUE_CHANGED);
if (res) {
flags_.Set(ValueFlags::VALUE_CHANGED);
}
if (!wasDirty && flags_.IsSet(ValueFlags::VALUE_CHANGED)) {
MarkDirty();
}
if (params_.pushValueToEngineDirectly) {
if (flags_.IsSet(ValueFlags::VALUE_CHANGED)) {
if (!params_.handle) {
return AnyReturn::INVALID_ARGUMENT;
}
flags_.Clear(ValueFlags::VALUE_CHANGED);
res = access_->SyncToEngine(*value_, params_) ? AnyReturn::NOTHING_TO_DO : AnyReturn::FAIL;
}
}
return res;
}
void EngineValue::SetDirtyList(EngineDirtyList* list)
{
dirtyList_ = list;
}
void EngineValue::ClearDirtyList()
{
dirtyList_ = nullptr;
}
CORE_NS::IComponentManager* EngineValue::GetComponentManager() const
{
return params_.handle.manager;
}
void EngineValue::MarkDirty()
{
if (auto* list = dirtyList_) {
{
std::lock_guard lock{list->mutex};
list->values.push_back(static_cast<IEngineValue*>(this));
}
if (list->owner) {
list->owner->NotifyDirty();
}
}
}
const IAny& EngineValue::GetValue() const
{
if (params_.pushValueToEngineDirectly) {
if (!params_.handle || !access_->SyncFromEngine(params_, *value_)) {
return INVALID_ANY;
}
}
return *value_;
}
bool EngineValue::IsCompatible(const TypeId& id) const
{
return META_NS::IsCompatible(*value_, id);
}
BASE_NS::string EngineValue::GetName() const
{
return name_;
}
void EngineValue::Lock() const
{
mutex_.lock();
}
void EngineValue::Unlock() const
{
mutex_.unlock();
}
void EngineValue::LockShared() const
{
mutex_.lock_shared();
}
void EngineValue::UnlockShared() const
{
mutex_.unlock_shared();
}
ResetResult EngineValue::ProcessOnReset(const IAny& value)
{
SetValue(value);
return RESET_CONTINUE;
}
void EngineValue::AddChangeCallback(const INotifyOnChangeCallback::Ptr& callback)
{
changeCallbacks_.Add(callback, mutex_);
}
void EngineValue::RemoveChangeCallback(const INotifyOnChangeCallback::Ptr& callback)
{
changeCallbacks_.Remove(callback, mutex_);
}
void EngineValue::InvokeChangeCallbacks()
{
for (auto& cb : changeCallbacks_.GetCallbacks(mutex_)) {
cb->NotifyChanged(*this);
}
}
void ChangeCallbackList::Add(const INotifyOnChangeCallback::Ptr& cb, std::shared_mutex& mutex)
{
std::unique_lock lock{mutex};
callbacks_.push_back(cb);
count_.store(static_cast<uint8_t>(callbacks_.size()), std::memory_order_relaxed);
}
void ChangeCallbackList::Remove(const INotifyOnChangeCallback::Ptr& cb, std::shared_mutex& mutex)
{
std::unique_lock lock{mutex};
auto it = std::find_if(callbacks_.begin(), callbacks_.end(), [&cb](const INotifyOnChangeCallback::WeakPtr& w) {
return w.lock() == cb;
});
if (it != callbacks_.end()) {
callbacks_.erase(it);
}
count_.store(static_cast<uint8_t>(callbacks_.size()), std::memory_order_relaxed);
}
BASE_NS::vector<INotifyOnChangeCallback::Ptr> ChangeCallbackList::GetCallbacks(std::shared_mutex& mutex) const
{
BASE_NS::vector<INotifyOnChangeCallback::Ptr> locked;
{
std::unique_lock lock{mutex};
for (auto& w : callbacks_) {
if (auto cb = w.lock()) {
locked.push_back(BASE_NS::move(cb));
}
}
}
return locked;
}
EnginePropertyParams EngineValue::GetPropertyParams() const
{
return params_;
}
bool EngineValue::SetPropertyParams(const EnginePropertyParams& p)
{
params_ = p;
return true;
}
IAny::Ptr EngineValue::CreateAny() const
{
return access_ ? access_->CreateSerializableAny() : nullptr;
}
bool EngineValue::ResetPendingNotify()
{
auto res = flags_.IsSet(ValueFlags::PENDING_NOTIFY);
flags_.Clear(ValueFlags::PENDING_NOTIFY);
return res;
}
ReturnError EngineValue::Export(IExportContext& c) const
{
META_NS::IAny::Ptr any = access_->CreateSerializableAny();
if (any->CopyFrom(*value_)) {
if (auto node = c.ExportValueToNode(any)) {
return c.SubstituteThis(node);
}
}
return GenericError::FAIL;
}
ReturnError EngineValue::Import(IImportContext&)
{
return GenericError::FAIL;
}
}
META_END_NAMESPACE()