| /* |
| * 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_ |