• 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 #ifndef SCENE_SRC_CONVERTING_VALUE_H
17 #define SCENE_SRC_CONVERTING_VALUE_H
18 
19 #include <atomic>
20 #include <scene/ext/intf_converting_value.h>
21 
22 #include <meta/api/event_handler.h>
23 #include <meta/api/make_callback.h>
24 #include <meta/ext/minimal_object.h>
25 #include <meta/interface/property/intf_stack_property.h>
26 #include <meta/interface/property/intf_stack_resetable.h>
27 #include <meta/interface/resource/intf_dynamic_resource.h>
28 #include <meta/interface/serialization/intf_serializable.h>
29 
30 SCENE_BEGIN_NAMESPACE()
31 
32 META_REGISTER_CLASS(
33     ConvertingValueBase, "41474a42-d7d1-4d4a-a6cd-5a53973e8f9e", META_NS::ObjectCategoryBits::NO_CATEGORY)
34 
35 template<typename PropertyType>
36 class ConvertingValueBase : public META_NS::IntroduceInterfaces<META_NS::MinimalObject, META_NS::INotifyOnChange,
37                                 META_NS::IStackResetable, META_NS::IValue, IConvertingValue, META_NS::ISerializable> {
META_IMPLEMENT_OBJECT_TYPE_INTERFACE(ClassId::ConvertingValueBase)38     META_IMPLEMENT_OBJECT_TYPE_INTERFACE(ClassId::ConvertingValueBase)
39 public:
40     ConvertingValueBase(META_NS::IAny::Ptr any, PropertyType p) : any_(BASE_NS::move(any)), p_(p) {}
41 
ProcessOnReset(const META_NS::IAny & value)42     META_NS::ResetResult ProcessOnReset(const META_NS::IAny& value) override
43     {
44         SetValue(value);
45         return META_NS::RESET_CONTINUE;
46     }
47 
EventOnChanged(META_NS::MetadataQuery)48     BASE_NS::shared_ptr<META_NS::IEvent> EventOnChanged(META_NS::MetadataQuery) const override
49     {
50         return p_->OnChanged();
51     }
52 
GetTargetProperty()53     META_NS::IProperty::Ptr GetTargetProperty() override
54     {
55         return p_;
56     }
57 
Export(META_NS::IExportContext & c)58     META_NS::ReturnError Export(META_NS::IExportContext& c) const override
59     {
60         if (auto node = c.ExportValueToNode(any_)) {
61             return c.SubstituteThis(node);
62         }
63         return META_NS::GenericError::FAIL;
64     }
Import(META_NS::IImportContext &)65     META_NS::ReturnError Import(META_NS::IImportContext&) override
66     {
67         return META_NS::GenericError::FAIL;
68     }
69 
70 protected:
71     META_NS::IAny::Ptr any_;
72     PropertyType p_;
73 };
74 
75 template<typename Converter>
76 class ConvertingValue : public ConvertingValueBase<META_NS::Property<typename Converter::TargetType>> {
77 public:
78     using Super = ConvertingValueBase<META_NS::Property<typename Converter::TargetType>>;
79 
80     using TargetType = typename Converter::TargetType;
81     using SourceType = typename Converter::SourceType;
82     using TargetProperty = META_NS::Property<TargetType>;
83 
84     ConvertingValue(TargetProperty p, Converter convert = {})
Super(META_NS::ConstructAny<SourceType> (),p)85         : Super(META_NS::ConstructAny<SourceType>(), p), convert_(BASE_NS::move(convert))
86     {}
87 
SetValue(const META_NS::IAny & any)88     META_NS::AnyReturnValue SetValue(const META_NS::IAny& any) override
89     {
90         SourceType value {};
91         auto res = any.GetValue<SourceType>(value);
92         if (res) {
93             res = this->p_->SetValue(convert_.ConvertToTarget(value));
94             if (res) {
95                 InternalSetValue(value);
96             }
97         }
98         return res;
99     }
GetValue()100     const META_NS::IAny& GetValue() const override
101     {
102         auto pvalue = this->p_->GetValue();
103         auto value = convert_.ConvertToSource(*this->any_, pvalue);
104         InternalSetValue(value);
105         return *this->any_;
106     }
IsCompatible(const META_NS::TypeId & id)107     bool IsCompatible(const META_NS::TypeId& id) const override
108     {
109         return id == META_NS::UidFromType<SourceType>() || id == META_NS::UidFromType<TargetType>();
110     }
111 
112 private:
113     void OnResourceChanged(bool forceNotification = false) const
114     {
115         SourceType value {};
116         auto res = this->any_->template GetValue<SourceType>(value);
117         if (res) {
118             auto locked = this->p_.GetLockedAccess();
119             res = locked->SetValue(convert_.ConvertToTarget(value));
120             // force notification
121             if (forceNotification && res == META_NS::AnyReturn::NOTHING_TO_DO) {
122                 locked->NotifyChange();
123             }
124         }
125     }
InternalSetValue(const SourceType & value)126     void InternalSetValue(const SourceType& value) const
127     {
128         if (this->any_->SetValue(value) == META_NS::AnyReturn::SUCCESS) {
129             if constexpr (META_NS::IsInterfacePtr_v<SourceType>) {
130                 if (auto i = interface_cast<META_NS::IDynamicResource>(value)) {
131                     changed_.Subscribe<META_NS::IOnChanged>(i->OnResourceChanged(), [this] {
132                         // if the object itself says it changed, for the notification
133                         OnResourceChanged(true);
134                     });
135                     OnResourceChanged();
136                 } else {
137                     changed_.Unsubscribe();
138                 }
139             }
140         }
141     }
142 
143 private:
144     Converter convert_;
145     mutable META_NS::EventHandler changed_;
146 };
147 
148 template<typename Converter>
149 class ConvertingArrayValue : public ConvertingValueBase<META_NS::ArrayProperty<typename Converter::TargetType>> {
150 public:
151     using Super = ConvertingValueBase<META_NS::ArrayProperty<typename Converter::TargetType>>;
152 
153     using TargetType = typename Converter::TargetType;
154     using SourceType = typename Converter::SourceType;
155     using TargetProperty = META_NS::ArrayProperty<TargetType>;
156 
157     ConvertingArrayValue(TargetProperty p, Converter convert = {})
Super(META_NS::ConstructArrayAny<SourceType> (),p)158         : Super(META_NS::ConstructArrayAny<SourceType>(), p), convert_(BASE_NS::move(convert))
159     {}
160 
SetValue(const META_NS::IAny & any)161     META_NS::AnyReturnValue SetValue(const META_NS::IAny& any) override
162     {
163         BASE_NS::vector<SourceType> value {};
164         auto res = any.GetValue<BASE_NS::vector<SourceType>>(value);
165         if (res) {
166             BASE_NS::vector<TargetType> converted;
167             for (auto&& v : value) {
168                 converted.push_back(convert_.ConvertToTarget(v));
169             }
170             res = this->p_->SetValue(converted);
171             if (res) {
172                 this->any_->SetValue(converted);
173             }
174         }
175         return res;
176     }
GetValue()177     const META_NS::IAny& GetValue() const override
178     {
179         BASE_NS::vector<SourceType> result;
180         for (auto&& v : this->p_->GetValue()) {
181             result.push_back(convert_.ConvertToSource(*this->any_, v));
182         }
183         this->any_->SetValue(result);
184         return *this->any_;
185     }
IsCompatible(const META_NS::TypeId & id)186     bool IsCompatible(const META_NS::TypeId& id) const override
187     {
188         return id == META_NS::ArrayUidFromType<SourceType>() || id == META_NS::ArrayUidFromType<TargetType>();
189     }
190 
191 private:
192     Converter convert_;
193 };
194 
195 SCENE_END_NAMESPACE()
196 
197 #endif
198