blob: 590e73d97b8d8ee15fbc5358dabb788615b9c58b [file] [log] [blame]
/*
* Copyright 2025 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SIGSLOT_TRAMPOLINE_H_
#define RTC_BASE_SIGSLOT_TRAMPOLINE_H_
#include <utility>
#include "absl/functional/any_invocable.h"
#include "rtc_base/callback_list.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
namespace webrtc {
// A template to simplify the replacement of sigslot::Signal with a
// CallbackList.
// THIS IS A TEMPORARY OBJECT:
// Once all callers have converted to Subscribe* and Notify*, the signal
// and the trampoline can be replaced with a CallbackList, or, for the case
// where only one listener can ever exist, a simple callback.
// Usage, for class MyClass and signal SignalMyNamedEvent:
// class MyClass {
// MyClass()
// : my_named_event_trampoline_(this) {}
// // existing:
// sigslot::signal0<> SignalMyNamedEvent;
// // new, this is what we want callers to use instead
// void NotifyMyNamedEvent() { SignalMyNamedEvent(); }
// void SubscribeMyNamedEvent(absl::AnyInvocable<void()> callback) {
// my_named_event_trampoline_.Subscribe(std::move(callback));
// }
// private:
// SignalTrampoline<MyClass, &MyClass::SignalMyNamedEvent>
// my_named_event_trampoline_;
// }
//
// At caller, replace:
// my_class_object.SignalMyNamedEvent.connect(target, function)
// with:
// my_class_object.SubscribeMyNamedEvent([target]{ target.function(); }
// Note that the SubscribeMyNamedEvent will NOT guarantee that the target
// continues to exist; if there is any doubt about that, use a SafeInvocable:
// my_class_object.SubscibeMyNamedEvent(
// SafeInvocable(target.safety_flag_.flag(),
// [target] { target.function(); }
namespace internal {
template <typename MemberPtrT>
struct member_pointer_traits;
// Used to find the type of ClassT::Member
template <typename ClassT, typename MemberT>
struct member_pointer_traits<MemberT ClassT::*> {
using member_type = MemberT;
};
template <typename SignalT>
class SignalTrampolineBase;
template <typename... Args>
class SignalTrampolineBase<sigslot::signal<Args...>>
: public sigslot::has_slots<> {
public:
void Subscribe(absl::AnyInvocable<void(Args...)> callback) {
callbacks_.AddReceiver(std::move(callback));
}
void Subscribe(const void* tag, absl::AnyInvocable<void(Args...)> callback) {
callbacks_.AddReceiver(tag, std::move(callback));
}
void Unsubscribe(const void* tag) { callbacks_.RemoveReceivers(tag); }
void Notify(Args... args) { callbacks_.Send(args...); }
private:
CallbackList<Args...> callbacks_;
};
template <typename T, auto member_signal>
using SignalTrampolineMemberBase =
SignalTrampolineBase<typename internal::member_pointer_traits<
decltype(member_signal)>::member_type>;
} // namespace internal
template <class T, auto member_signal>
class SignalTrampoline
: public internal::SignalTrampolineMemberBase<T, member_signal> {
private:
using Base = internal::SignalTrampolineMemberBase<T, member_signal>;
public:
explicit SignalTrampoline(T* that) {
(that->*member_signal).connect(static_cast<Base*>(this), &Base::Notify);
}
};
} // namespace webrtc
#endif // RTC_BASE_SIGSLOT_TRAMPOLINE_H_