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 nsImportModule_h
8 #define nsImportModule_h
9 
10 #include "mozilla/Attributes.h"
11 
12 #include "nsCOMPtr.h"
13 #include "mozilla/RefPtr.h"
14 
15 namespace mozilla {
16 namespace loader {
17 
18 nsresult ImportModule(const char* aURI, const char* aExportName,
19                       const nsIID& aIID, void** aResult);
20 
21 }  // namespace loader
22 }  // namespace mozilla
23 
24 class MOZ_STACK_CLASS nsImportModule final : public nsCOMPtr_helper {
25  public:
nsImportModule(const char * aURI,const char * aExportName,nsresult * aErrorPtr)26   nsImportModule(const char* aURI, const char* aExportName, nsresult* aErrorPtr)
27       : mURI(aURI), mExportName(aExportName), mErrorPtr(aErrorPtr) {}
28 
operator()29   virtual nsresult NS_FASTCALL operator()(const nsIID& aIID,
30                                           void** aResult) const override {
31     nsresult rv =
32         ::mozilla::loader::ImportModule(mURI, mExportName, aIID, aResult);
33     if (mErrorPtr) {
34       *mErrorPtr = rv;
35     }
36     return rv;
37   }
38 
39  private:
40   const char* mURI;
41   const char* mExportName;
42   nsresult* mErrorPtr;
43 };
44 
45 /**
46  * These helpers make it considerably easier for C++ code to import a JS module
47  * and wrap it in an appropriately-defined XPIDL interface for its exports.
48  * Typical usage is something like:
49  *
50  * Foo.jsm:
51  *
52  *   var EXPORTED_SYMBOLS = ["foo"];
53  *
54  *   function foo(bar) {
55  *     return bar.toString();
56  *   }
57  *
58  * mozIFoo.idl:
59  *
60  *   interface mozIFoo : nsISupports {
61  *     AString foo(double meh);
62  *   }
63  *
64  * Thing.cpp:
65  *
66  *   nsCOMPtr<mozIFoo> foo = do_ImportModule(
67  *     "resource://meh/Foo.jsm");
68  *
69  *   MOZ_TRY(foo->Foo(42));
70  *
71  * For JS modules which export all fields within a single named object, a second
72  * argument can be passed naming that object.
73  *
74  * Foo.jsm:
75  *
76  *   var EXPORTED_SYMBOLS = ["Foo"];
77  *
78  *   var Foo = {
79  *     function foo(bar) {
80  *       return bar.toString();
81  *     }
82  *   };
83  *
84  * Thing.cpp:
85  *
86  *   nsCOMPtr<mozIFoo> foo = do_ImportModule(
87  *       "resource:://meh/Foo.jsm", "Foo");
88  */
89 
90 template <size_t N>
do_ImportModule(const char (& aURI)[N])91 inline nsImportModule do_ImportModule(const char (&aURI)[N]) {
92   return {aURI, nullptr, nullptr};
93 }
94 
95 template <size_t N>
do_ImportModule(const char (& aURI)[N],nsresult * aRv)96 inline nsImportModule do_ImportModule(const char (&aURI)[N], nsresult* aRv) {
97   return {aURI, nullptr, aRv};
98 }
99 
100 template <size_t N, size_t N2>
do_ImportModule(const char (& aURI)[N],const char (& aExportName)[N2])101 inline nsImportModule do_ImportModule(const char (&aURI)[N],
102                                       const char (&aExportName)[N2]) {
103   return {aURI, aExportName, nullptr};
104 }
105 
106 template <size_t N, size_t N2>
do_ImportModule(const char (& aURI)[N],const char (& aExportName)[N2],nsresult * aRv)107 inline nsImportModule do_ImportModule(const char (&aURI)[N],
108                                       const char (&aExportName)[N2],
109                                       nsresult* aRv) {
110   return {aURI, aExportName, aRv};
111 }
112 
113 #endif  // defined nsImportModule_h
114