#ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDER_MAP_H_
#define MOJO_PUBLIC_CPP_BINDINGS_BINDER_MAP_H_
#include <map>
#include <string>
#include <type_traits>
#include <vector>
#include "base/component_export.h"
#include "base/containers/contains.h"
#include "base/containers/variant_map.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/types/pass_key.h"
#include "build/chromecast_buildflags.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/bindings/lib/binder_map_internal.h"
namespace mojo {
template <typename ContextType>
class BinderMapWithContext {
public:
using PassKey = base::PassKey<BinderMapWithContext>;
using Traits = internal::BinderContextTraits<ContextType>;
using ContextValueType = typename Traits::ValueType;
using GenericBinderType = typename Traits::GenericBinderType;
template <typename Interface>
using BinderType = typename Traits::template BinderType<Interface>;
template <typename Interface>
using FuncType = typename Traits::template FuncType<Interface>;
BinderMapWithContext() : binders_(PassKey()) {}
BinderMapWithContext(const BinderMapWithContext&) = default;
BinderMapWithContext(BinderMapWithContext&&) = default;
~BinderMapWithContext() = default;
BinderMapWithContext& operator=(const BinderMapWithContext&) = default;
BinderMapWithContext& operator=(BinderMapWithContext&&) = default;
template <typename Interface>
void Add(std::type_identity_t<BinderType<Interface>> binder,
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
Add(internal::StaticString(Interface::Name_),
internal::GenericCallbackBinderWithContext<ContextType>(
Traits::MakeGenericBinder(std::move(binder)),
std::move(task_runner)));
}
template <typename Interface>
void Add(std::type_identity_t<FuncType<Interface>>* func,
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr) {
Add(internal::StaticString(Interface::Name_),
internal::GenericCallbackBinderWithContext<ContextType>(
Traits::MakeGenericBinder(func), std::move(task_runner)));
}
template <typename Interface>
bool Contains() {
return base::Contains(binders_, Interface::Name_);
}
[[nodiscard]] bool TryBind(mojo::GenericPendingReceiver* receiver) {
static_assert(IsVoidContext::value,
"TryBind() must be called with a context value when "
"ContextType is non-void.");
auto it = binders_.find(*receiver->interface_name());
if (it == binders_.end()) {
return false;
}
it->second.BindInterface(receiver->PassPipe());
return true;
}
[[nodiscard]] bool TryBind(ContextValueType context,
mojo::GenericPendingReceiver* receiver) {
static_assert(!IsVoidContext::value,
"TryBind() must be called without a context value when "
"ContextType is void.");
auto it = binders_.find(*receiver->interface_name());
if (it == binders_.end()) {
#if BUILDFLAG(IS_CASTOS) || BUILDFLAG(IS_CAST_ANDROID)
return default_binder_ && default_binder_.Run(context, *receiver);
#else
return false;
#endif
}
it->second.BindInterface(std::move(context), receiver->PassPipe());
return true;
}
#if BUILDFLAG(IS_CASTOS) || BUILDFLAG(IS_CAST_ANDROID)
using DefaultBinder =
base::RepeatingCallback<bool(ContextValueType context,
mojo::GenericPendingReceiver&)>;
void SetDefaultBinderDeprecated(DefaultBinder binder) {
default_binder_ = std::move(binder);
}
#endif
void GetInterfacesForTesting(std::vector<std::string>& out) {
for (const auto& [key, _] : binders_) {
out.push_back(std::string(key));
}
}
private:
using IsVoidContext = std::is_same<ContextType, void>;
void Add(internal::StaticString name,
internal::GenericCallbackBinderWithContext<ContextType>&& binder) {
auto key = std::string_view(name);
binders_.erase(key);
binders_.try_emplace(key, std::move(binder));
}
base::VariantMap<std::string_view,
internal::GenericCallbackBinderWithContext<ContextType>>
binders_;
#if BUILDFLAG(IS_CASTOS) || BUILDFLAG(IS_CAST_ANDROID)
DefaultBinder default_binder_;
#endif
};
class BinderMap : public BinderMapWithContext<void> {};
}
#endif