blob: 5763690df5193b734fc5744152a79ef893ac653d [file] [log] [blame]
#pragma once
#include <tuple>
#include <utility>
namespace chip {
namespace detail {
template <typename T>
struct SplitLambdaCallerImpl;
// Detail -- Specialization to extract argument and return types from the callable type.
template <class TReturn, class TCallable, class... TArgs>
struct SplitLambdaCallerImpl<TReturn (TCallable::*)(TArgs...) const>
{
// This call function knows the arguments and provides the signature required for the C-like callbacks
static TReturn Call(TArgs... args, void * context)
{
return (*static_cast<TCallable *>(context))(std::forward<TArgs>(args)...);
}
};
} // namespace detail
/// @brief Helper Object to use Lambdas through C-Like APIs where context is split from the callback.
/// This incurs no runtime code execution; just keeps everything typesafe.
/// @tparam TCallable
/// @example
/// /* FunctionAPI */
/// int api_function(void (*callback) (int api_value, void * context), void * context );
///
/// int local_function()
/// {
/// int local_api_value = -1;
/// int other_local_variable = 7;
///
/// SplitLambda on_api_update_my_vars = [&](int value){
/// local_api_value = value;
/// other_local_variable = value +3;
/// };
///
/// /*Call API */
/// return api_function(on_api_update_my_vars.Caller(), on_api_update_my_vars.Context());
/// }
template <class TCallable>
struct SplitLambda : detail::SplitLambdaCallerImpl<decltype(&TCallable::operator())>
{
TCallable callable;
SplitLambda(TCallable callable_) : callable(callable_) {}
SplitLambda(SplitLambda &) = delete; // Cannot be copied
SplitLambda(SplitLambda &&) = delete; // Cannot be moved
inline void * Context() { return static_cast<void *>(&callable); }
inline auto Caller() { return &this->Call; }
};
template <class TCallable>
SplitLambda(TCallable callable_) -> SplitLambda<TCallable>;
} // namespace chip