/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_bluetooth_bluetoothinterfacehelpers_h #define mozilla_dom_bluetooth_bluetoothinterfacehelpers_h #include "BluetoothCommon.h" #include "nsThreadUtils.h" BEGIN_BLUETOOTH_NAMESPACE // // Conversion // nsresult Convert(nsresult aIn, BluetoothStatus& aOut); // // Result handling // // The classes of type |BluetoothResultRunnable[0..3]| transfer // a result handler from the I/O thread to the main thread for // execution. Call the methods |Create| and |Dispatch| to create or // create-and-dispatch a result runnable. // // You need to specify the called method. The |Create| and |Dispatch| // methods of |BluetoothResultRunnable[1..3]| receive an extra argument // for initializing the result's arguments. During creation, the result // runnable calls the supplied class's call operator with the result's // argument. This is where initialization and conversion from backend- // specific types is performed. // template class BluetoothResultRunnable0 : public nsRunnable { public: typedef BluetoothResultRunnable0 SelfType; template static already_AddRefed Create(Obj* aObj, Res (Obj::*aMethod)(), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aObj, aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Obj* aObj, Res (Obj::*aMethod)(), const InitOp& aInitOp) { if (!aObj) { return; // silently return if no result runnable has been given } nsRefPtr runnable = Create(aObj, aMethod, aInitOp); if (!runnable) { BT_LOGR("BluetoothResultRunnable0::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_LOGR("NS_DispatchToMainThread failed: %X", unsigned(rv)); } } NS_METHOD Run() override { ((*mObj).*mMethod)(); return NS_OK; } private: BluetoothResultRunnable0(Obj* aObj, Res (Obj::*aMethod)()) : mObj(aObj) , mMethod(aMethod) { MOZ_ASSERT(mObj); MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { return aInitOp(); } nsRefPtr mObj; void (Obj::*mMethod)(); }; template class BluetoothResultRunnable1 : public nsRunnable { public: typedef BluetoothResultRunnable1 SelfType; template static already_AddRefed Create(Obj* aObj, Res (Obj::*aMethod)(Arg1), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aObj, aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1), const InitOp& aInitOp) { if (!aObj) { return; // silently return if no result runnable has been given } nsRefPtr runnable = Create(aObj, aMethod, aInitOp); if (!runnable) { BT_LOGR("BluetoothResultRunnable1::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_LOGR("NS_DispatchToMainThread failed: %X", unsigned(rv)); } } NS_METHOD Run() override { ((*mObj).*mMethod)(mArg1); return NS_OK; } private: BluetoothResultRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1)) : mObj(aObj) , mMethod(aMethod) { MOZ_ASSERT(mObj); MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { return aInitOp(mArg1); } nsRefPtr mObj; Res (Obj::*mMethod)(Arg1); Tin1 mArg1; }; template class BluetoothResultRunnable3 : public nsRunnable { public: typedef BluetoothResultRunnable3 SelfType; template static already_AddRefed Create(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aObj, aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), const InitOp& aInitOp) { if (!aObj) { return; // silently return if no result runnable has been given } nsRefPtr runnable = Create(aObj, aMethod, aInitOp); if (!runnable) { BT_LOGR("BluetoothResultRunnable3::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { ((*mObj).*mMethod)(mArg1, mArg2, mArg3); return NS_OK; } private: BluetoothResultRunnable3(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3)) : mObj(aObj) , mMethod(aMethod) { MOZ_ASSERT(mObj); MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { return aInitOp(mArg1, mArg2, mArg3); } nsRefPtr mObj; Res (Obj::*mMethod)(Arg1, Arg2, Arg3); Tin1 mArg1; Tin2 mArg2; Tin3 mArg3; }; // // Notification handling // // The classes of type |BluetoothNotificationRunnable[0..5]| transfer // a notification from the I/O thread to a notification handler on the // main thread. Call the methods |Create| and |Dispatch| to create or // create-and-dispatch a notification runnable. // // Like with result runnables, you need to specify the called method. // And like with result runnables, the |Create| and |Dispatch| methods // of |BluetoothNotificationRunnable[1..5]| receive an extra argument // for initializing the notification's arguments. During creation, the // notification runnable calls the class's call operator with the // notification's argument. This is where initialization and conversion // from backend-specific types is performed. // template class BluetoothNotificationRunnable0 : public nsRunnable { public: typedef typename ObjectWrapper::ObjectType ObjectType; typedef BluetoothNotificationRunnable0 SelfType; template static already_AddRefed Create(Res (ObjectType::*aMethod)(), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Res (ObjectType::*aMethod)(), const InitOp& aInitOp) { nsRefPtr runnable = Create(aMethod, aInitOp); if (!runnable) { BT_WARNING("BluetoothNotificationRunnable0::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); ObjectType* obj = ObjectWrapper::GetInstance(); if (!obj) { BT_WARNING("Notification handler not initialized"); } else { ((*obj).*mMethod)(); } return NS_OK; } private: BluetoothNotificationRunnable0(Res (ObjectType::*aMethod)()) : mMethod(aMethod) { MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { return aInitOp(); } Res (ObjectType::*mMethod)(); }; template class BluetoothNotificationRunnable1 : public nsRunnable { public: typedef typename ObjectWrapper::ObjectType ObjectType; typedef BluetoothNotificationRunnable1 SelfType; template static already_AddRefed Create(Res (ObjectType::*aMethod)(Arg1), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Res (ObjectType::*aMethod)(Arg1), const InitOp& aInitOp) { nsRefPtr runnable = Create(aMethod, aInitOp); if (!runnable) { BT_WARNING("BluetoothNotificationRunnable1::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); ObjectType* obj = ObjectWrapper::GetInstance(); if (!obj) { BT_WARNING("Notification handler not initialized"); } else { ((*obj).*mMethod)(mArg1); } return NS_OK; } private: BluetoothNotificationRunnable1(Res (ObjectType::*aMethod)(Arg1)) : mMethod(aMethod) { MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { nsresult rv = aInitOp(mArg1); if (NS_FAILED(rv)) { return rv; } return NS_OK; } Res (ObjectType::*mMethod)(Arg1); Tin1 mArg1; }; template class BluetoothNotificationRunnable2 : public nsRunnable { public: typedef typename ObjectWrapper::ObjectType ObjectType; typedef BluetoothNotificationRunnable2 SelfType; template static already_AddRefed Create(Res (ObjectType::*aMethod)(Arg1, Arg2), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2), const InitOp& aInitOp) { nsRefPtr runnable = Create(aMethod, aInitOp); if (!runnable) { BT_WARNING("BluetoothNotificationRunnable2::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); ObjectType* obj = ObjectWrapper::GetInstance(); if (!obj) { BT_WARNING("Notification handler not initialized"); } else { ((*obj).*mMethod)(mArg1, mArg2); } return NS_OK; } private: BluetoothNotificationRunnable2( Res (ObjectType::*aMethod)(Arg1, Arg2)) : mMethod(aMethod) { MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { nsresult rv = aInitOp(mArg1, mArg2); if (NS_FAILED(rv)) { return rv; } return NS_OK; } Res (ObjectType::*mMethod)(Arg1, Arg2); Tin1 mArg1; Tin2 mArg2; }; template class BluetoothNotificationRunnable3 : public nsRunnable { public: typedef typename ObjectWrapper::ObjectType ObjectType; typedef BluetoothNotificationRunnable3 SelfType; template static already_AddRefed Create(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), const InitOp& aInitOp) { nsRefPtr runnable = Create(aMethod, aInitOp); if (!runnable) { BT_WARNING("BluetoothNotificationRunnable3::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); ObjectType* obj = ObjectWrapper::GetInstance(); if (!obj) { BT_WARNING("Notification handler not initialized"); } else { ((*obj).*mMethod)(mArg1, mArg2, mArg3); } return NS_OK; } private: BluetoothNotificationRunnable3( Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3)) : mMethod(aMethod) { MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { nsresult rv = aInitOp(mArg1, mArg2, mArg3); if (NS_FAILED(rv)) { return rv; } return NS_OK; } Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3); Tin1 mArg1; Tin2 mArg2; Tin3 mArg3; }; template class BluetoothNotificationRunnable4 : public nsRunnable { public: typedef typename ObjectWrapper::ObjectType ObjectType; typedef BluetoothNotificationRunnable4 SelfType; template static already_AddRefed Create( Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), const InitOp& aInitOp) { nsRefPtr runnable = Create(aMethod, aInitOp); if (!runnable) { BT_WARNING("BluetoothNotificationRunnable4::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); ObjectType* obj = ObjectWrapper::GetInstance(); if (!obj) { BT_WARNING("Notification handler not initialized"); } else { ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4); } return NS_OK; } private: BluetoothNotificationRunnable4( Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4)) : mMethod(aMethod) { MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4); if (NS_FAILED(rv)) { return rv; } return NS_OK; } Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4); Tin1 mArg1; Tin2 mArg2; Tin3 mArg3; Tin4 mArg4; }; template class BluetoothNotificationRunnable5 : public nsRunnable { public: typedef typename ObjectWrapper::ObjectType ObjectType; typedef BluetoothNotificationRunnable5 SelfType; template static already_AddRefed Create( Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), const InitOp& aInitOp) { nsRefPtr runnable(new SelfType(aMethod)); if (NS_FAILED(runnable->Init(aInitOp))) { return nullptr; } return runnable.forget(); } template static void Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), const InitOp& aInitOp) { nsRefPtr runnable = Create(aMethod, aInitOp); if (!runnable) { BT_WARNING("BluetoothNotificationRunnable5::Create failed"); return; } nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { BT_WARNING("NS_DispatchToMainThread failed: %X", rv); } } NS_METHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); ObjectType* obj = ObjectWrapper::GetInstance(); if (!obj) { BT_WARNING("Notification handler not initialized"); } else { ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4, mArg5); } return NS_OK; } private: BluetoothNotificationRunnable5( Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5)) : mMethod(aMethod) { MOZ_ASSERT(mMethod); } template nsresult Init(const InitOp& aInitOp) { nsresult rv = aInitOp(mArg1, mArg2, mArg3, mArg4, mArg5); if (NS_FAILED(rv)) { return rv; } return NS_OK; } Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4, Arg5); Tin1 mArg1; Tin2 mArg2; Tin3 mArg3; Tin4 mArg4; Tin5 mArg5; }; // // Init operators // // Below are general-purpose init operators for Bluetooth. The classes // of type |ConstantInitOp[1..3]| initialize results or notifications // with constant values. // template class ConstantInitOp1 final { public: ConstantInitOp1(const T1& aArg1) : mArg1(aArg1) { } nsresult operator () (T1& aArg1) const { aArg1 = mArg1; return NS_OK; } private: const T1& mArg1; }; template class ConstantInitOp2 final { public: ConstantInitOp2(const T1& aArg1, const T2& aArg2) : mArg1(aArg1) , mArg2(aArg2) { } nsresult operator () (T1& aArg1, T2& aArg2) const { aArg1 = mArg1; aArg2 = mArg2; return NS_OK; } private: const T1& mArg1; const T2& mArg2; }; template class ConstantInitOp3 final { public: ConstantInitOp3(const T1& aArg1, const T2& aArg2, const T3& aArg3) : mArg1(aArg1) , mArg2(aArg2) , mArg3(aArg3) { } nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const { aArg1 = mArg1; aArg2 = mArg2; aArg3 = mArg3; return NS_OK; } private: const T1& mArg1; const T2& mArg2; const T3& mArg3; }; END_BLUETOOTH_NAMESPACE #endif