18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#ifndef META_API_FUNCTION_H
178bf80f4bSopenharmony_ci#define META_API_FUNCTION_H
188bf80f4bSopenharmony_ci
198bf80f4bSopenharmony_ci#include <meta/api/call_context.h>
208bf80f4bSopenharmony_ci#include <meta/interface/builtin_objects.h>
218bf80f4bSopenharmony_ci#include <meta/interface/interface_helpers.h>
228bf80f4bSopenharmony_ci#include <meta/interface/intf_cloneable.h>
238bf80f4bSopenharmony_ci#include <meta/interface/intf_function.h>
248bf80f4bSopenharmony_ci#include <meta/interface/object_macros.h>
258bf80f4bSopenharmony_ci
268bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE()
278bf80f4bSopenharmony_ci
288bf80f4bSopenharmony_ci/**
298bf80f4bSopenharmony_ci * @brief Function implementation that is used for the meta function system.
308bf80f4bSopenharmony_ci */
318bf80f4bSopenharmony_citemplate<typename Obj, typename Func>
328bf80f4bSopenharmony_ciclass DefaultFunction : public IntroduceInterfaces<IFunction, ICloneable> {
338bf80f4bSopenharmony_cipublic:
348bf80f4bSopenharmony_ci    ~DefaultFunction() override = default;
358bf80f4bSopenharmony_ci    DefaultFunction& operator=(const DefaultFunction&) noexcept = delete;
368bf80f4bSopenharmony_ci    META_NO_MOVE(DefaultFunction)
378bf80f4bSopenharmony_ci
388bf80f4bSopenharmony_ci    BASE_NS::string GetName() const override
398bf80f4bSopenharmony_ci    {
408bf80f4bSopenharmony_ci        return name_;
418bf80f4bSopenharmony_ci    }
428bf80f4bSopenharmony_ci
438bf80f4bSopenharmony_ci    IObject::ConstPtr GetDestination() const override
448bf80f4bSopenharmony_ci    {
458bf80f4bSopenharmony_ci        return interface_pointer_cast<IObject>(obj_);
468bf80f4bSopenharmony_ci    }
478bf80f4bSopenharmony_ci
488bf80f4bSopenharmony_ci    void Invoke(const ICallContext::Ptr& context) const override
498bf80f4bSopenharmony_ci    {
508bf80f4bSopenharmony_ci        func_(obj_, context);
518bf80f4bSopenharmony_ci    }
528bf80f4bSopenharmony_ci
538bf80f4bSopenharmony_ci    ICallContext::Ptr CreateCallContext() const override
548bf80f4bSopenharmony_ci    {
558bf80f4bSopenharmony_ci        if (context_) {
568bf80f4bSopenharmony_ci            return context_();
578bf80f4bSopenharmony_ci        }
588bf80f4bSopenharmony_ci        return nullptr;
598bf80f4bSopenharmony_ci    }
608bf80f4bSopenharmony_ci
618bf80f4bSopenharmony_ci    BASE_NS::shared_ptr<CORE_NS::IInterface> GetClone() const override
628bf80f4bSopenharmony_ci    {
638bf80f4bSopenharmony_ci        BASE_NS::shared_ptr<DefaultFunction> p(new DefaultFunction(*this));
648bf80f4bSopenharmony_ci        return interface_pointer_cast<CORE_NS::IInterface>(p);
658bf80f4bSopenharmony_ci    }
668bf80f4bSopenharmony_ci
678bf80f4bSopenharmony_ci    DefaultFunction(
688bf80f4bSopenharmony_ci        BASE_NS::string n, BASE_NS::weak_ptr<BASE_NS::remove_const_t<Obj>> obj, Func f, Internal::FContext* context)
698bf80f4bSopenharmony_ci        : name_(BASE_NS::move(n)), obj_(obj), func_(BASE_NS::move(f)), context_(context)
708bf80f4bSopenharmony_ci    {}
718bf80f4bSopenharmony_ci
728bf80f4bSopenharmony_ciprotected:
738bf80f4bSopenharmony_ci    DefaultFunction(const DefaultFunction& s) : name_(s.name_), obj_(s.obj_), func_(s.func_), context_(s.context_) {}
748bf80f4bSopenharmony_ci
758bf80f4bSopenharmony_ciprotected:
768bf80f4bSopenharmony_ci    BASE_NS::string name_;
778bf80f4bSopenharmony_ci    BASE_NS::weak_ptr<BASE_NS::remove_const_t<Obj>> obj_ {};
788bf80f4bSopenharmony_ci    Func func_;
798bf80f4bSopenharmony_ci    Internal::FContext* const context_;
808bf80f4bSopenharmony_ci};
818bf80f4bSopenharmony_ci
828bf80f4bSopenharmony_ci/**
838bf80f4bSopenharmony_ci * @brief Create DefaultFunction object for obj+memfun (used in metadata initialisation)
848bf80f4bSopenharmony_ci */
858bf80f4bSopenharmony_citemplate<typename Obj, typename MemFun>
868bf80f4bSopenharmony_ciIFunction::Ptr CreateFunction(BASE_NS::string_view name, Obj* obj, MemFun func, Internal::FContext* context)
878bf80f4bSopenharmony_ci{
888bf80f4bSopenharmony_ci    using ObjType = BASE_NS::shared_ptr<BASE_NS::remove_const_t<Obj>>;
898bf80f4bSopenharmony_ci    ObjType objPtr { obj->GetSelf(), obj };
908bf80f4bSopenharmony_ci    auto l = [func](auto obj, const ICallContext::Ptr& context) {
918bf80f4bSopenharmony_ci        if (auto o = obj.lock()) {
928bf80f4bSopenharmony_ci            (o.get()->*func)(context);
938bf80f4bSopenharmony_ci        }
948bf80f4bSopenharmony_ci    };
958bf80f4bSopenharmony_ci    return IFunction::Ptr(
968bf80f4bSopenharmony_ci        new DefaultFunction<Obj, decltype(l)>(BASE_NS::string(name), objPtr, BASE_NS::move(l), context));
978bf80f4bSopenharmony_ci}
988bf80f4bSopenharmony_ci
998bf80f4bSopenharmony_ci/**
1008bf80f4bSopenharmony_ci * @brief Create DefaultFunction object from lambda
1018bf80f4bSopenharmony_ci */
1028bf80f4bSopenharmony_citemplate<typename Func, typename = EnableIfBindFunction<Func>>
1038bf80f4bSopenharmony_ciIFunction::Ptr CreateBindFunction(Func func)
1048bf80f4bSopenharmony_ci{
1058bf80f4bSopenharmony_ci    auto ccontext = []() {
1068bf80f4bSopenharmony_ci        ::BASE_NS::string_view arr[] = { "" };
1078bf80f4bSopenharmony_ci        return CreateCallContextImpl<decltype(func())>(ParamNameToView(arr));
1088bf80f4bSopenharmony_ci    };
1098bf80f4bSopenharmony_ci    // wrap to make CallFunction to work with operator()(auto...)
1108bf80f4bSopenharmony_ci    auto wrapper = [func]() mutable { return func(); };
1118bf80f4bSopenharmony_ci    auto l = [wrapper](auto, const ICallContext::Ptr& context) { ::META_NS::CallFunction(context, wrapper); };
1128bf80f4bSopenharmony_ci    return IFunction::Ptr(new DefaultFunction<IObject, decltype(l)>("Bind", nullptr, BASE_NS::move(l), ccontext));
1138bf80f4bSopenharmony_ci}
1148bf80f4bSopenharmony_ci
1158bf80f4bSopenharmony_ci/**
1168bf80f4bSopenharmony_ci * @brief Create DefaultFunction object from lambda
1178bf80f4bSopenharmony_ci */
1188bf80f4bSopenharmony_citemplate<typename Func, typename... Args>
1198bf80f4bSopenharmony_ciIFunction::Ptr CreateBindFunctionSafe(Func func, Args&&... args)
1208bf80f4bSopenharmony_ci{
1218bf80f4bSopenharmony_ci    return CreateBindFunction(CaptureSafe(BASE_NS::move(func), BASE_NS::forward<Args>(args)...));
1228bf80f4bSopenharmony_ci}
1238bf80f4bSopenharmony_ci
1248bf80f4bSopenharmony_ci/**
1258bf80f4bSopenharmony_ci * @brief Create forwarding function object
1268bf80f4bSopenharmony_ci */
1278bf80f4bSopenharmony_ciinline IFunction::Ptr CreateFunction(const IObject::Ptr& obj, BASE_NS::string_view name)
1288bf80f4bSopenharmony_ci{
1298bf80f4bSopenharmony_ci    if (auto f = META_NS::GetObjectRegistry().Create<ISettableFunction>(ClassId::SettableFunction)) {
1308bf80f4bSopenharmony_ci        if (f->SetTarget(obj, name)) {
1318bf80f4bSopenharmony_ci            return f;
1328bf80f4bSopenharmony_ci        }
1338bf80f4bSopenharmony_ci    }
1348bf80f4bSopenharmony_ci    return nullptr;
1358bf80f4bSopenharmony_ci}
1368bf80f4bSopenharmony_ci
1378bf80f4bSopenharmony_ci/**
1388bf80f4bSopenharmony_ci * @brief Helper class for meta function call result.
1398bf80f4bSopenharmony_ci */
1408bf80f4bSopenharmony_citemplate<typename Type>
1418bf80f4bSopenharmony_cistruct CallResult {
1428bf80f4bSopenharmony_ci    explicit operator bool() const
1438bf80f4bSopenharmony_ci    {
1448bf80f4bSopenharmony_ci        return success;
1458bf80f4bSopenharmony_ci    }
1468bf80f4bSopenharmony_ci
1478bf80f4bSopenharmony_ci    /**
1488bf80f4bSopenharmony_ci     * @brief Call context that was used for the call.
1498bf80f4bSopenharmony_ci     */
1508bf80f4bSopenharmony_ci    ICallContext::Ptr context;
1518bf80f4bSopenharmony_ci    /**
1528bf80f4bSopenharmony_ci     * @brief True if it was possible to make the call (i.e. the argument types match the parameters).
1538bf80f4bSopenharmony_ci     */
1548bf80f4bSopenharmony_ci    bool success {};
1558bf80f4bSopenharmony_ci    /**
1568bf80f4bSopenharmony_ci     * @brief Return value of the function call.
1578bf80f4bSopenharmony_ci     */
1588bf80f4bSopenharmony_ci    Type value {};
1598bf80f4bSopenharmony_ci};
1608bf80f4bSopenharmony_ci
1618bf80f4bSopenharmony_citemplate<>
1628bf80f4bSopenharmony_cistruct CallResult<void> {
1638bf80f4bSopenharmony_ci    explicit operator bool() const
1648bf80f4bSopenharmony_ci    {
1658bf80f4bSopenharmony_ci        return success;
1668bf80f4bSopenharmony_ci    }
1678bf80f4bSopenharmony_ci
1688bf80f4bSopenharmony_ci    ICallContext::Ptr context;
1698bf80f4bSopenharmony_ci    bool success {};
1708bf80f4bSopenharmony_ci};
1718bf80f4bSopenharmony_ci
1728bf80f4bSopenharmony_citemplate<typename Ret, typename... Args, size_t... Index>
1738bf80f4bSopenharmony_ciCallResult<Ret> CallMetaFunctionImpl(const IFunction::Ptr& func, IndexSequence<Index...>, Args&&... args)
1748bf80f4bSopenharmony_ci{
1758bf80f4bSopenharmony_ci    auto context = func->CreateCallContext();
1768bf80f4bSopenharmony_ci    if (!context) {
1778bf80f4bSopenharmony_ci        return {};
1788bf80f4bSopenharmony_ci    }
1798bf80f4bSopenharmony_ci    auto params = context->GetParameters();
1808bf80f4bSopenharmony_ci    // Allow to use defaults from call context
1818bf80f4bSopenharmony_ci    if (params.size() < sizeof...(Args)) {
1828bf80f4bSopenharmony_ci        context->ReportError("invalid meta call");
1838bf80f4bSopenharmony_ci        return { context };
1848bf80f4bSopenharmony_ci    }
1858bf80f4bSopenharmony_ci
1868bf80f4bSopenharmony_ci    if (!(true && ... && Set<PlainType_t<Args>>(context, params[Index].name, args))) {
1878bf80f4bSopenharmony_ci        context->ReportError("invalid meta call");
1888bf80f4bSopenharmony_ci        return { context };
1898bf80f4bSopenharmony_ci    }
1908bf80f4bSopenharmony_ci
1918bf80f4bSopenharmony_ci    func->Invoke(context);
1928bf80f4bSopenharmony_ci    if (context->Succeeded()) {
1938bf80f4bSopenharmony_ci        if constexpr (BASE_NS::is_same_v<Ret, void>) {
1948bf80f4bSopenharmony_ci            return CallResult<Ret> { context, true };
1958bf80f4bSopenharmony_ci        }
1968bf80f4bSopenharmony_ci        if constexpr (!BASE_NS::is_same_v<Ret, void>) {
1978bf80f4bSopenharmony_ci            if (auto p = GetResult<Ret>(context)) {
1988bf80f4bSopenharmony_ci                return CallResult<Ret> { context, true, *p };
1998bf80f4bSopenharmony_ci            }
2008bf80f4bSopenharmony_ci        }
2018bf80f4bSopenharmony_ci    }
2028bf80f4bSopenharmony_ci    return { context };
2038bf80f4bSopenharmony_ci}
2048bf80f4bSopenharmony_ci
2058bf80f4bSopenharmony_ci/**
2068bf80f4bSopenharmony_ci * @brief Call function via interface with the given arguments.
2078bf80f4bSopenharmony_ci * @param func Function to call.
2088bf80f4bSopenharmony_ci * @param args Arguments for the function call.
2098bf80f4bSopenharmony_ci * @return Result of the call.
2108bf80f4bSopenharmony_ci * @see CallResult
2118bf80f4bSopenharmony_ci */
2128bf80f4bSopenharmony_citemplate<typename Ret, typename... Args>
2138bf80f4bSopenharmony_ciCallResult<Ret> CallMetaFunction(const IFunction::Ptr& func, Args&&... args)
2148bf80f4bSopenharmony_ci{
2158bf80f4bSopenharmony_ci    return CallMetaFunctionImpl<Ret>(func, MakeIndexSequenceFor<Args...>(), BASE_NS::forward<Args>(args)...);
2168bf80f4bSopenharmony_ci}
2178bf80f4bSopenharmony_ci
2188bf80f4bSopenharmony_citemplate<typename Signature>
2198bf80f4bSopenharmony_cistruct IsFunctionCompatibleImpl;
2208bf80f4bSopenharmony_ci
2218bf80f4bSopenharmony_citemplate<typename Ret, typename... Args>
2228bf80f4bSopenharmony_cistruct IsFunctionCompatibleImpl<Ret(Args...)> {
2238bf80f4bSopenharmony_ci    template<size_t... Index>
2248bf80f4bSopenharmony_ci    static bool Call(const IFunction::Ptr& func, IndexSequence<Index...>)
2258bf80f4bSopenharmony_ci    {
2268bf80f4bSopenharmony_ci        auto context = func->CreateCallContext();
2278bf80f4bSopenharmony_ci        // e.g. wrong number of parameters when implementing meta function
2288bf80f4bSopenharmony_ci        if (!context) {
2298bf80f4bSopenharmony_ci            return false;
2308bf80f4bSopenharmony_ci        }
2318bf80f4bSopenharmony_ci        auto params = context->GetParameters();
2328bf80f4bSopenharmony_ci        // Allow to use defaults from call context
2338bf80f4bSopenharmony_ci        if (params.size() < sizeof...(Args)) {
2348bf80f4bSopenharmony_ci            return false;
2358bf80f4bSopenharmony_ci        }
2368bf80f4bSopenharmony_ci
2378bf80f4bSopenharmony_ci        // if we have void, allow any return type, it will just be ignored
2388bf80f4bSopenharmony_ci        if constexpr (!BASE_NS::is_same_v<Ret, void>) {
2398bf80f4bSopenharmony_ci            if (!IsCompatibleWith<Ret>(context->GetResult())) {
2408bf80f4bSopenharmony_ci                return false;
2418bf80f4bSopenharmony_ci            }
2428bf80f4bSopenharmony_ci        }
2438bf80f4bSopenharmony_ci
2448bf80f4bSopenharmony_ci        if (!(true && ... && IsCompatibleWith<Args>(*params[Index].value))) {
2458bf80f4bSopenharmony_ci            return false;
2468bf80f4bSopenharmony_ci        }
2478bf80f4bSopenharmony_ci        return true;
2488bf80f4bSopenharmony_ci    }
2498bf80f4bSopenharmony_ci    static bool Call(const IFunction::Ptr& func)
2508bf80f4bSopenharmony_ci    {
2518bf80f4bSopenharmony_ci        if constexpr ((true && ... && HasUid_v<PlainType_t<Args>>)) {
2528bf80f4bSopenharmony_ci            return Call(func, MakeIndexSequenceFor<Args...>());
2538bf80f4bSopenharmony_ci        }
2548bf80f4bSopenharmony_ci        return false;
2558bf80f4bSopenharmony_ci    }
2568bf80f4bSopenharmony_ci};
2578bf80f4bSopenharmony_ci
2588bf80f4bSopenharmony_ci/**
2598bf80f4bSopenharmony_ci * @brief Check if function is compatible with given signature (The return type and parameter types match).
2608bf80f4bSopenharmony_ci */
2618bf80f4bSopenharmony_citemplate<typename FuncSignature>
2628bf80f4bSopenharmony_cibool IsFunctionCompatible(const IFunction::Ptr& func)
2638bf80f4bSopenharmony_ci{
2648bf80f4bSopenharmony_ci    return IsFunctionCompatibleImpl<FuncSignature>::Call(func);
2658bf80f4bSopenharmony_ci}
2668bf80f4bSopenharmony_ci
2678bf80f4bSopenharmony_ciMETA_END_NAMESPACE()
2688bf80f4bSopenharmony_ci
2698bf80f4bSopenharmony_ci#endif
270