Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / ds / nsHashPropertyBag.cpp
blob9e3ee630798ccb932855710930821c5ceb7b4cd9
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/. */
7 #include "nsHashPropertyBag.h"
9 #include <utility>
11 #include "mozilla/Attributes.h"
12 #include "mozilla/SimpleEnumerator.h"
13 #include "nsArray.h"
14 #include "nsArrayEnumerator.h"
15 #include "nsIProperty.h"
16 #include "nsIVariant.h"
17 #include "nsThreadUtils.h"
18 #include "nsVariant.h"
20 using mozilla::MakeRefPtr;
21 using mozilla::SimpleEnumerator;
22 using mozilla::Unused;
24 extern "C" {
26 // This function uses C linkage because it's exposed to Rust to support the
27 // `HashPropertyBag` wrapper in the `storage_variant` crate.
28 void NS_NewHashPropertyBag(nsIWritablePropertyBag** aBag) {
29 MakeRefPtr<nsHashPropertyBag>().forget(aBag);
32 } // extern "C"
35 * nsHashPropertyBagBase implementation.
38 NS_IMETHODIMP
39 nsHashPropertyBagBase::HasKey(const nsAString& aName, bool* aResult) {
40 *aResult = mPropertyHash.Get(aName, nullptr);
41 return NS_OK;
44 NS_IMETHODIMP
45 nsHashPropertyBagBase::Get(const nsAString& aName, nsIVariant** aResult) {
46 if (!mPropertyHash.Get(aName, aResult)) {
47 *aResult = nullptr;
50 return NS_OK;
53 NS_IMETHODIMP
54 nsHashPropertyBagBase::GetProperty(const nsAString& aName,
55 nsIVariant** aResult) {
56 bool isFound = mPropertyHash.Get(aName, aResult);
57 if (!isFound) {
58 return NS_ERROR_FAILURE;
61 return NS_OK;
64 NS_IMETHODIMP
65 nsHashPropertyBagBase::SetProperty(const nsAString& aName, nsIVariant* aValue) {
66 if (NS_WARN_IF(!aValue)) {
67 return NS_ERROR_INVALID_ARG;
70 mPropertyHash.Put(aName, aValue);
72 return NS_OK;
75 NS_IMETHODIMP
76 nsHashPropertyBagBase::DeleteProperty(const nsAString& aName) {
77 return mPropertyHash.Remove(aName) ? NS_OK : NS_ERROR_FAILURE;
81 // nsSimpleProperty class and impl; used for GetEnumerator
84 class nsSimpleProperty final : public nsIProperty {
85 ~nsSimpleProperty() = default;
87 public:
88 nsSimpleProperty(const nsAString& aName, nsIVariant* aValue)
89 : mName(aName), mValue(aValue) {}
91 NS_DECL_ISUPPORTS
92 NS_DECL_NSIPROPERTY
93 protected:
94 nsString mName;
95 nsCOMPtr<nsIVariant> mValue;
98 NS_IMPL_ISUPPORTS(nsSimpleProperty, nsIProperty)
100 NS_IMETHODIMP
101 nsSimpleProperty::GetName(nsAString& aName) {
102 aName.Assign(mName);
103 return NS_OK;
106 NS_IMETHODIMP
107 nsSimpleProperty::GetValue(nsIVariant** aValue) {
108 NS_IF_ADDREF(*aValue = mValue);
109 return NS_OK;
112 // end nsSimpleProperty
114 NS_IMETHODIMP
115 nsHashPropertyBagBase::GetEnumerator(nsISimpleEnumerator** aResult) {
116 nsCOMPtr<nsIMutableArray> propertyArray = nsArray::Create();
117 if (!propertyArray) {
118 return NS_ERROR_OUT_OF_MEMORY;
121 for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
122 const nsAString& key = iter.Key();
123 nsIVariant* data = iter.UserData();
124 nsSimpleProperty* sprop = new nsSimpleProperty(key, data);
125 propertyArray->AppendElement(sprop);
128 return NS_NewArrayEnumerator(aResult, propertyArray, NS_GET_IID(nsIProperty));
131 #define IMPL_GETSETPROPERTY_AS(Name, Type) \
132 NS_IMETHODIMP \
133 nsHashPropertyBagBase::GetPropertyAs##Name(const nsAString& prop, \
134 Type* _retval) { \
135 nsIVariant* v = mPropertyHash.GetWeak(prop); \
136 if (!v) return NS_ERROR_NOT_AVAILABLE; \
137 return v->GetAs##Name(_retval); \
140 NS_IMETHODIMP \
141 nsHashPropertyBagBase::SetPropertyAs##Name(const nsAString& prop, \
142 Type value) { \
143 nsCOMPtr<nsIWritableVariant> var = new nsVariant(); \
144 var->SetAs##Name(value); \
145 return SetProperty(prop, var); \
148 IMPL_GETSETPROPERTY_AS(Int32, int32_t)
149 IMPL_GETSETPROPERTY_AS(Uint32, uint32_t)
150 IMPL_GETSETPROPERTY_AS(Int64, int64_t)
151 IMPL_GETSETPROPERTY_AS(Uint64, uint64_t)
152 IMPL_GETSETPROPERTY_AS(Double, double)
153 IMPL_GETSETPROPERTY_AS(Bool, bool)
155 NS_IMETHODIMP
156 nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp,
157 nsAString& aResult) {
158 nsIVariant* v = mPropertyHash.GetWeak(aProp);
159 if (!v) {
160 return NS_ERROR_NOT_AVAILABLE;
162 return v->GetAsAString(aResult);
165 NS_IMETHODIMP
166 nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp,
167 nsACString& aResult) {
168 nsIVariant* v = mPropertyHash.GetWeak(aProp);
169 if (!v) {
170 return NS_ERROR_NOT_AVAILABLE;
172 return v->GetAsACString(aResult);
175 NS_IMETHODIMP
176 nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp,
177 nsACString& aResult) {
178 nsIVariant* v = mPropertyHash.GetWeak(aProp);
179 if (!v) {
180 return NS_ERROR_NOT_AVAILABLE;
182 return v->GetAsAUTF8String(aResult);
185 NS_IMETHODIMP
186 nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp,
187 const nsIID& aIID,
188 void** aResult) {
189 nsIVariant* v = mPropertyHash.GetWeak(aProp);
190 if (!v) {
191 return NS_ERROR_NOT_AVAILABLE;
193 nsCOMPtr<nsISupports> val;
194 nsresult rv = v->GetAsISupports(getter_AddRefs(val));
195 if (NS_FAILED(rv)) {
196 return rv;
198 if (!val) {
199 // We have a value, but it's null
200 *aResult = nullptr;
201 return NS_OK;
203 return val->QueryInterface(aIID, aResult);
206 NS_IMETHODIMP
207 nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp,
208 const nsAString& aValue) {
209 nsCOMPtr<nsIWritableVariant> var = new nsVariant();
210 var->SetAsAString(aValue);
211 return SetProperty(aProp, var);
214 NS_IMETHODIMP
215 nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp,
216 const nsACString& aValue) {
217 nsCOMPtr<nsIWritableVariant> var = new nsVariant();
218 var->SetAsACString(aValue);
219 return SetProperty(aProp, var);
222 NS_IMETHODIMP
223 nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp,
224 const nsACString& aValue) {
225 nsCOMPtr<nsIWritableVariant> var = new nsVariant();
226 var->SetAsAUTF8String(aValue);
227 return SetProperty(aProp, var);
230 NS_IMETHODIMP
231 nsHashPropertyBagBase::SetPropertyAsInterface(const nsAString& aProp,
232 nsISupports* aValue) {
233 nsCOMPtr<nsIWritableVariant> var = new nsVariant();
234 var->SetAsISupports(aValue);
235 return SetProperty(aProp, var);
238 void nsHashPropertyBagBase::CopyFrom(const nsHashPropertyBagBase* aOther) {
239 for (auto iter = aOther->mPropertyHash.ConstIter(); !iter.Done();
240 iter.Next()) {
241 SetProperty(iter.Key(), iter.UserData());
245 void nsHashPropertyBagBase::CopyFrom(nsIPropertyBag* aOther) {
246 CopyFrom(this, aOther);
249 /* static */ void nsHashPropertyBagBase::CopyFrom(nsIWritablePropertyBag* aTo,
250 nsIPropertyBag* aFrom) {
251 if (aTo && aFrom) {
252 nsCOMPtr<nsISimpleEnumerator> enumerator;
253 if (NS_SUCCEEDED(aFrom->GetEnumerator(getter_AddRefs(enumerator)))) {
254 for (auto& property : SimpleEnumerator<nsIProperty>(enumerator)) {
255 nsString name;
256 nsCOMPtr<nsIVariant> value;
257 Unused << NS_WARN_IF(NS_FAILED(property->GetName(name)));
258 Unused << NS_WARN_IF(
259 NS_FAILED(property->GetValue(getter_AddRefs(value))));
260 Unused << NS_WARN_IF(
261 NS_FAILED(aTo->SetProperty(std::move(name), value)));
263 } else {
264 NS_WARNING("Unable to copy nsIPropertyBag");
270 * nsHashPropertyBag implementation.
273 NS_IMPL_ADDREF(nsHashPropertyBag)
274 NS_IMPL_RELEASE(nsHashPropertyBag)
276 NS_INTERFACE_MAP_BEGIN(nsHashPropertyBag)
277 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
278 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
279 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
280 NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
281 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
282 NS_INTERFACE_MAP_END
285 * We need to ensure that the hashtable is destroyed on the main thread, as
286 * the nsIVariant values are main-thread only objects.
288 class ProxyHashtableDestructor final : public mozilla::Runnable {
289 public:
290 using HashtableType = nsInterfaceHashtable<nsStringHashKey, nsIVariant>;
291 explicit ProxyHashtableDestructor(HashtableType&& aTable)
292 : mozilla::Runnable("ProxyHashtableDestructor"),
293 mPropertyHash(std::move(aTable)) {}
295 NS_IMETHODIMP
296 Run() override {
297 MOZ_ASSERT(NS_IsMainThread());
298 HashtableType table(std::move(mPropertyHash));
299 return NS_OK;
302 private:
303 HashtableType mPropertyHash;
306 nsHashPropertyBag::~nsHashPropertyBag() {
307 if (!NS_IsMainThread()) {
308 RefPtr<ProxyHashtableDestructor> runnable =
309 new ProxyHashtableDestructor(std::move(mPropertyHash));
310 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
315 * nsHashPropertyBagCC implementation.
318 NS_IMPL_CYCLE_COLLECTION(nsHashPropertyBagCC, mPropertyHash)
320 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHashPropertyBagCC)
321 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHashPropertyBagCC)
323 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHashPropertyBagCC)
324 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
325 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
326 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
327 NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
328 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
329 NS_INTERFACE_MAP_END