Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef AddonManagerStartup_inlines_h
7 : #define AddonManagerStartup_inlines_h
8 :
9 : #include "jsapi.h"
10 : #include "nsJSUtils.h"
11 :
12 : #include "mozilla/Maybe.h"
13 : #include "mozilla/Move.h"
14 :
15 : namespace mozilla {
16 :
17 : class ArrayIterElem;
18 : class PropertyIterElem;
19 :
20 :
21 : /*****************************************************************************
22 : * Object iterator base classes
23 : *****************************************************************************/
24 :
25 : template<class T, class PropertyType>
26 : class MOZ_STACK_CLASS BaseIter {
27 : public:
28 : typedef T SelfType;
29 :
30 6 : PropertyType begin() const
31 : {
32 12 : PropertyType elem(Self());
33 12 : return Move(elem);
34 : }
35 :
36 6 : PropertyType end() const
37 : {
38 12 : PropertyType elem(Self());
39 12 : return elem.End();
40 : }
41 :
42 18 : void* Context() const { return mContext; }
43 :
44 : protected:
45 8 : BaseIter(JSContext* cx, JS::HandleObject object, void* context = nullptr)
46 : : mCx(cx)
47 : , mObject(object)
48 8 : , mContext(context)
49 8 : {}
50 :
51 12 : const SelfType& Self() const
52 : {
53 12 : return *static_cast<const SelfType*>(this);
54 : }
55 : SelfType& Self()
56 : {
57 : return *static_cast<SelfType*>(this);
58 : }
59 :
60 : JSContext* mCx;
61 :
62 : JS::HandleObject mObject;
63 :
64 : void* mContext;
65 : };
66 :
67 : template<class T, class IterType>
68 : class MOZ_STACK_CLASS BaseIterElem {
69 : public:
70 : typedef T SelfType;
71 :
72 54 : explicit BaseIterElem(const IterType& iter, uint32_t index = 0)
73 : : mIter(iter)
74 54 : , mIndex(index)
75 54 : {}
76 :
77 54 : uint32_t Length() const
78 : {
79 54 : return mIter.Length();
80 : }
81 :
82 24 : JS::Value Value()
83 : {
84 48 : JS::RootedValue value(mIter.mCx, JS::UndefinedValue());
85 :
86 24 : auto& self = Self();
87 24 : if (!self.GetValue(&value)) {
88 0 : JS_ClearPendingException(mIter.mCx);
89 : }
90 :
91 48 : return value;
92 : }
93 :
94 24 : SelfType& operator*() { return Self(); }
95 :
96 24 : SelfType& operator++()
97 : {
98 24 : MOZ_ASSERT(mIndex < Length());
99 24 : mIndex++;
100 24 : return Self();
101 : }
102 :
103 30 : bool operator!=(const SelfType& other) const
104 : {
105 30 : return &mIter != &other.mIter || mIndex != other.mIndex;
106 : }
107 :
108 :
109 6 : SelfType End() const
110 : {
111 12 : SelfType end(mIter);
112 6 : end.mIndex = Length();
113 12 : return Move(end);
114 : }
115 :
116 18 : void* Context() const { return mIter.Context(); }
117 :
118 : protected:
119 : const SelfType& Self() const
120 : {
121 : return *static_cast<const SelfType*>(this);
122 : }
123 72 : SelfType& Self() {
124 72 : return *static_cast<SelfType*>(this);
125 : }
126 :
127 : const IterType& mIter;
128 :
129 : uint32_t mIndex;
130 : };
131 :
132 :
133 : /*****************************************************************************
134 : * Property iteration
135 : *****************************************************************************/
136 :
137 8 : class MOZ_STACK_CLASS PropertyIter
138 : : public BaseIter<PropertyIter, PropertyIterElem>
139 : {
140 : friend class PropertyIterElem;
141 : friend class BaseIterElem<PropertyIterElem, PropertyIter>;
142 :
143 : public:
144 8 : PropertyIter(JSContext* cx, JS::HandleObject object, void* context = nullptr)
145 8 : : BaseIter(cx, object, context)
146 8 : , mIds(cx, JS::IdVector(cx))
147 : {
148 8 : if (!JS_Enumerate(cx, object, &mIds)) {
149 0 : JS_ClearPendingException(cx);
150 : }
151 8 : }
152 :
153 : PropertyIter(const PropertyIter& other)
154 : : PropertyIter(other.mCx, other.mObject, other.mContext)
155 : {}
156 :
157 : PropertyIter& operator=(const PropertyIter& other)
158 : {
159 : MOZ_ASSERT(other.mObject == mObject);
160 : mCx = other.mCx;
161 : mContext = other.mContext;
162 :
163 : mIds.clear();
164 : if (!JS_Enumerate(mCx, mObject, &mIds)) {
165 : JS_ClearPendingException(mCx);
166 : }
167 : return *this;
168 : }
169 :
170 54 : int32_t Length() const
171 : {
172 54 : return mIds.length();
173 : }
174 :
175 : protected:
176 : JS::Rooted<JS::IdVector> mIds;
177 : };
178 :
179 54 : class MOZ_STACK_CLASS PropertyIterElem
180 : : public BaseIterElem<PropertyIterElem, PropertyIter>
181 : {
182 : friend class BaseIterElem<PropertyIterElem, PropertyIter>;
183 :
184 : public:
185 18 : using BaseIterElem::BaseIterElem;
186 :
187 36 : PropertyIterElem(const PropertyIterElem& other)
188 36 : : BaseIterElem(other.mIter, other.mIndex)
189 36 : {}
190 :
191 42 : jsid Id()
192 : {
193 42 : MOZ_ASSERT(mIndex < mIter.mIds.length());
194 :
195 42 : return mIter.mIds[mIndex];
196 : }
197 :
198 18 : const nsAString& Name()
199 : {
200 18 : if(mName.isNothing()) {
201 18 : mName.emplace();
202 18 : mName.ref().init(mIter.mCx, Id());
203 : }
204 18 : return mName.ref();
205 : }
206 :
207 24 : JSContext* Cx() { return mIter.mCx; }
208 :
209 : protected:
210 24 : bool GetValue(JS::MutableHandleValue value)
211 : {
212 24 : MOZ_ASSERT(mIndex < Length());
213 48 : JS::Rooted<jsid> id(mIter.mCx, Id());
214 :
215 48 : return JS_GetPropertyById(mIter.mCx, mIter.mObject, id, value);
216 : }
217 :
218 : private:
219 : Maybe<nsAutoJSString> mName;
220 : };
221 :
222 :
223 : /*****************************************************************************
224 : * Array iteration
225 : *****************************************************************************/
226 :
227 : class MOZ_STACK_CLASS ArrayIter
228 : : public BaseIter<ArrayIter, ArrayIterElem>
229 : {
230 : friend class ArrayIterElem;
231 : friend class BaseIterElem<ArrayIterElem, ArrayIter>;
232 :
233 : public:
234 : ArrayIter(JSContext* cx, JS::HandleObject object)
235 : : BaseIter(cx, object)
236 : , mLength(0)
237 : {
238 : bool isArray;
239 : if (!JS_IsArrayObject(cx, object, &isArray) || !isArray) {
240 : JS_ClearPendingException(cx);
241 : return;
242 : }
243 :
244 : if (!JS_GetArrayLength(cx, object, &mLength)) {
245 : JS_ClearPendingException(cx);
246 : }
247 : }
248 :
249 : uint32_t Length() const
250 : {
251 : return mLength;
252 : }
253 :
254 : private:
255 : uint32_t mLength;
256 : };
257 :
258 : class MOZ_STACK_CLASS ArrayIterElem
259 : : public BaseIterElem<ArrayIterElem, ArrayIter>
260 : {
261 : friend class BaseIterElem<ArrayIterElem, ArrayIter>;
262 :
263 : public:
264 : using BaseIterElem::BaseIterElem;
265 :
266 : ArrayIterElem(const ArrayIterElem& other)
267 : : BaseIterElem(other.mIter, other.mIndex)
268 : {}
269 :
270 : protected:
271 : bool
272 : GetValue(JS::MutableHandleValue value)
273 : {
274 : MOZ_ASSERT(mIndex < Length());
275 : return JS_GetElement(mIter.mCx, mIter.mObject, mIndex, value);
276 : }
277 : };
278 :
279 : }
280 :
281 : #endif // AddonManagerStartup_inlines_h
|