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 <utility> 10 11 #include "js/Array.h" // JS::GetArrayLength, JS::IsArrayObject 12 #include "jsapi.h" 13 #include "mozilla/Maybe.h" 14 #include "nsJSUtils.h" 15 16 namespace mozilla { 17 18 class ArrayIterElem; 19 class PropertyIterElem; 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 begin()30 PropertyType begin() const { return PropertyType(Self()); } 31 end()32 PropertyType end() const { 33 PropertyType elem(Self()); 34 return elem.End(); 35 } 36 Context()37 void* Context() const { return mContext; } 38 39 protected: 40 BaseIter(JSContext* cx, JS::HandleObject object, void* context = nullptr) mCx(cx)41 : mCx(cx), mObject(object), mContext(context) {} 42 Self()43 const SelfType& Self() const { return *static_cast<const SelfType*>(this); } Self()44 SelfType& Self() { return *static_cast<SelfType*>(this); } 45 46 JSContext* mCx; 47 48 JS::HandleObject mObject; 49 50 void* mContext; 51 }; 52 53 template <class T, class IterType> 54 class MOZ_STACK_CLASS BaseIterElem { 55 public: 56 typedef T SelfType; 57 58 explicit BaseIterElem(const IterType& iter, uint32_t index = 0) mIter(iter)59 : mIter(iter), mIndex(index) {} 60 Length()61 uint32_t Length() const { return mIter.Length(); } 62 Value()63 JS::Value Value() { 64 JS::RootedValue value(mIter.mCx, JS::UndefinedValue()); 65 66 auto& self = Self(); 67 if (!self.GetValue(&value)) { 68 JS_ClearPendingException(mIter.mCx); 69 } 70 71 return value; 72 } 73 74 SelfType& operator*() { return Self(); } 75 76 SelfType& operator++() { 77 MOZ_ASSERT(mIndex < Length()); 78 mIndex++; 79 return Self(); 80 } 81 82 bool operator!=(const SelfType& other) const { 83 return &mIter != &other.mIter || mIndex != other.mIndex; 84 } 85 End()86 SelfType End() const { 87 SelfType end(mIter); 88 end.mIndex = Length(); 89 return end; 90 } 91 Context()92 void* Context() const { return mIter.Context(); } 93 94 protected: Self()95 const SelfType& Self() const { return *static_cast<const SelfType*>(this); } Self()96 SelfType& Self() { return *static_cast<SelfType*>(this); } 97 98 const IterType& mIter; 99 100 uint32_t mIndex; 101 }; 102 103 /***************************************************************************** 104 * Property iteration 105 *****************************************************************************/ 106 107 class MOZ_STACK_CLASS PropertyIter 108 : public BaseIter<PropertyIter, PropertyIterElem> { 109 friend class PropertyIterElem; 110 friend class BaseIterElem<PropertyIterElem, PropertyIter>; 111 112 public: 113 PropertyIter(JSContext* cx, JS::HandleObject object, void* context = nullptr) BaseIter(cx,object,context)114 : BaseIter(cx, object, context), mIds(cx, JS::IdVector(cx)) { 115 if (!JS_Enumerate(cx, object, &mIds)) { 116 JS_ClearPendingException(cx); 117 } 118 } 119 PropertyIter(const PropertyIter & other)120 PropertyIter(const PropertyIter& other) 121 : PropertyIter(other.mCx, other.mObject, other.mContext) {} 122 123 PropertyIter& operator=(const PropertyIter& other) { 124 MOZ_ASSERT(other.mObject == mObject); 125 mCx = other.mCx; 126 mContext = other.mContext; 127 128 mIds.clear(); 129 if (!JS_Enumerate(mCx, mObject, &mIds)) { 130 JS_ClearPendingException(mCx); 131 } 132 return *this; 133 } 134 Length()135 int32_t Length() const { return mIds.length(); } 136 137 protected: 138 JS::Rooted<JS::IdVector> mIds; 139 }; 140 141 class MOZ_STACK_CLASS PropertyIterElem 142 : public BaseIterElem<PropertyIterElem, PropertyIter> { 143 friend class BaseIterElem<PropertyIterElem, PropertyIter>; 144 145 public: 146 using BaseIterElem::BaseIterElem; 147 PropertyIterElem(const PropertyIterElem & other)148 PropertyIterElem(const PropertyIterElem& other) 149 : BaseIterElem(other.mIter, other.mIndex) {} 150 Id()151 jsid Id() { 152 MOZ_ASSERT(mIndex < mIter.mIds.length()); 153 154 return mIter.mIds[mIndex]; 155 } 156 Name()157 const nsAString& Name() { 158 if (mName.isNothing()) { 159 mName.emplace(); 160 mName.ref().init(mIter.mCx, Id()); 161 } 162 return mName.ref(); 163 } 164 Cx()165 JSContext* Cx() { return mIter.mCx; } 166 167 protected: GetValue(JS::MutableHandleValue value)168 bool GetValue(JS::MutableHandleValue value) { 169 MOZ_ASSERT(mIndex < Length()); 170 JS::Rooted<jsid> id(mIter.mCx, Id()); 171 172 return JS_GetPropertyById(mIter.mCx, mIter.mObject, id, value); 173 } 174 175 private: 176 Maybe<nsAutoJSString> mName; 177 }; 178 179 /***************************************************************************** 180 * Array iteration 181 *****************************************************************************/ 182 183 class MOZ_STACK_CLASS ArrayIter : public BaseIter<ArrayIter, ArrayIterElem> { 184 friend class ArrayIterElem; 185 friend class BaseIterElem<ArrayIterElem, ArrayIter>; 186 187 public: ArrayIter(JSContext * cx,JS::HandleObject object)188 ArrayIter(JSContext* cx, JS::HandleObject object) 189 : BaseIter(cx, object), mLength(0) { 190 bool isArray; 191 if (!JS::IsArrayObject(cx, object, &isArray) || !isArray) { 192 JS_ClearPendingException(cx); 193 return; 194 } 195 196 if (!JS::GetArrayLength(cx, object, &mLength)) { 197 JS_ClearPendingException(cx); 198 } 199 } 200 Length()201 uint32_t Length() const { return mLength; } 202 203 private: 204 uint32_t mLength; 205 }; 206 207 class MOZ_STACK_CLASS ArrayIterElem 208 : public BaseIterElem<ArrayIterElem, ArrayIter> { 209 friend class BaseIterElem<ArrayIterElem, ArrayIter>; 210 211 public: 212 using BaseIterElem::BaseIterElem; 213 ArrayIterElem(const ArrayIterElem & other)214 ArrayIterElem(const ArrayIterElem& other) 215 : BaseIterElem(other.mIter, other.mIndex) {} 216 217 protected: GetValue(JS::MutableHandleValue value)218 bool GetValue(JS::MutableHandleValue value) { 219 MOZ_ASSERT(mIndex < Length()); 220 return JS_GetElement(mIter.mCx, mIter.mObject, mIndex, value); 221 } 222 }; 223 224 } // namespace mozilla 225 226 #endif // AddonManagerStartup_inlines_h 227