1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_GenericModule_h
8 #define mozilla_GenericModule_h
9 
10 #include <type_traits>
11 
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Module.h"
14 
15 #define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass)                         \
16   static nsresult _InstanceClass##Constructor(nsISupports* aOuter,             \
17                                               REFNSIID aIID, void** aResult) { \
18     RefPtr<_InstanceClass> inst;                                               \
19                                                                                \
20     *aResult = nullptr;                                                        \
21     if (nullptr != aOuter) {                                                   \
22       return NS_ERROR_NO_AGGREGATION;                                          \
23     }                                                                          \
24                                                                                \
25     inst = new _InstanceClass();                                               \
26     return inst->QueryInterface(aIID, aResult);                                \
27   }
28 
29 #define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod)       \
30   static nsresult _InstanceClass##Constructor(nsISupports* aOuter,             \
31                                               REFNSIID aIID, void** aResult) { \
32     nsresult rv;                                                               \
33                                                                                \
34     RefPtr<_InstanceClass> inst;                                               \
35                                                                                \
36     *aResult = nullptr;                                                        \
37     if (nullptr != aOuter) {                                                   \
38       return NS_ERROR_NO_AGGREGATION;                                          \
39     }                                                                          \
40                                                                                \
41     inst = new _InstanceClass();                                               \
42     rv = inst->_InitMethod();                                                  \
43     if (NS_SUCCEEDED(rv)) {                                                    \
44       rv = inst->QueryInterface(aIID, aResult);                                \
45     }                                                                          \
46                                                                                \
47     return rv;                                                                 \
48   }
49 
50 namespace mozilla {
51 namespace detail {
52 
53 template <typename T>
54 struct RemoveAlreadyAddRefed {
55   using Type = T;
56 };
57 
58 template <typename T>
59 struct RemoveAlreadyAddRefed<already_AddRefed<T>> {
60   using Type = T;
61 };
62 
63 }  // namespace detail
64 }  // namespace mozilla
65 
66 // 'Constructor' that uses an existing getter function that gets a singleton.
67 #define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(_InstanceClass, _GetterProc)  \
68   static nsresult _InstanceClass##Constructor(nsISupports* aOuter,             \
69                                               REFNSIID aIID, void** aResult) { \
70     RefPtr<_InstanceClass> inst;                                               \
71                                                                                \
72     *aResult = nullptr;                                                        \
73     if (nullptr != aOuter) {                                                   \
74       return NS_ERROR_NO_AGGREGATION;                                          \
75     }                                                                          \
76                                                                                \
77     using T =                                                                  \
78         mozilla::detail::RemoveAlreadyAddRefed<decltype(_GetterProc())>::Type; \
79     static_assert(                                                             \
80         std::is_same_v<already_AddRefed<T>, decltype(_GetterProc())>,          \
81         "Singleton constructor must return already_AddRefed");                 \
82     static_assert(                                                             \
83         std::is_base_of<_InstanceClass, T>::value,                             \
84         "Singleton constructor must return correct already_AddRefed");         \
85     inst = _GetterProc();                                                      \
86     if (nullptr == inst) {                                                     \
87       return NS_ERROR_OUT_OF_MEMORY;                                           \
88     }                                                                          \
89     return inst->QueryInterface(aIID, aResult);                                \
90   }
91 
92 #endif  // mozilla_GenericModule_h
93