Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / xpcom / ds / nsHashPropertyBag.cpp
blob68dd612c572d4fae663966cead454de347a86528
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.InsertOrUpdate(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 (const auto& entry : aOther->mPropertyHash) {
240 SetProperty(entry.GetKey(), entry.GetWeak());
244 void nsHashPropertyBagBase::CopyFrom(nsIPropertyBag* aOther) {
245 CopyFrom(this, aOther);
248 /* static */ void nsHashPropertyBagBase::CopyFrom(nsIWritablePropertyBag* aTo,
249 nsIPropertyBag* aFrom) {
250 if (aTo && aFrom) {
251 nsCOMPtr<nsISimpleEnumerator> enumerator;
252 if (NS_SUCCEEDED(aFrom->GetEnumerator(getter_AddRefs(enumerator)))) {
253 for (auto& property : SimpleEnumerator<nsIProperty>(enumerator)) {
254 nsString name;
255 nsCOMPtr<nsIVariant> value;
256 Unused << NS_WARN_IF(NS_FAILED(property->GetName(name)));
257 Unused << NS_WARN_IF(
258 NS_FAILED(property->GetValue(getter_AddRefs(value))));
259 Unused << NS_WARN_IF(
260 NS_FAILED(aTo->SetProperty(std::move(name), value)));
262 } else {
263 NS_WARNING("Unable to copy nsIPropertyBag");
268 nsresult nsGetProperty::operator()(const nsIID& aIID,
269 void** aInstancePtr) const {
270 nsresult rv;
272 if (mPropBag) {
273 rv = mPropBag->GetPropertyAsInterface(mPropName, aIID, aInstancePtr);
274 } else {
275 rv = NS_ERROR_NULL_POINTER;
276 *aInstancePtr = 0;
279 if (mErrorPtr) {
280 *mErrorPtr = rv;
282 return rv;
286 * nsHashPropertyBag implementation.
289 NS_IMPL_ADDREF(nsHashPropertyBag)
290 NS_IMPL_RELEASE(nsHashPropertyBag)
292 NS_INTERFACE_MAP_BEGIN(nsHashPropertyBag)
293 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
294 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
295 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
296 NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
297 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
298 NS_INTERFACE_MAP_END
301 * We need to ensure that the hashtable is destroyed on the main thread, as
302 * the nsIVariant values are main-thread only objects.
304 class ProxyHashtableDestructor final : public mozilla::Runnable {
305 public:
306 using HashtableType = nsInterfaceHashtable<nsStringHashKey, nsIVariant>;
307 explicit ProxyHashtableDestructor(HashtableType&& aTable)
308 : mozilla::Runnable("ProxyHashtableDestructor"),
309 mPropertyHash(std::move(aTable)) {}
311 NS_IMETHODIMP
312 Run() override {
313 MOZ_ASSERT(NS_IsMainThread());
314 HashtableType table(std::move(mPropertyHash));
315 return NS_OK;
318 private:
319 HashtableType mPropertyHash;
322 nsHashPropertyBag::~nsHashPropertyBag() {
323 if (!NS_IsMainThread()) {
324 RefPtr<ProxyHashtableDestructor> runnable =
325 new ProxyHashtableDestructor(std::move(mPropertyHash));
326 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
331 * nsHashPropertyBagOMT implementation
333 NS_IMPL_ADDREF(nsHashPropertyBagOMT)
334 NS_IMPL_RELEASE(nsHashPropertyBagOMT)
336 NS_INTERFACE_MAP_BEGIN(nsHashPropertyBagOMT)
337 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
338 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
339 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
340 NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
341 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
342 NS_INTERFACE_MAP_END
344 nsHashPropertyBagOMT::nsHashPropertyBagOMT() {
345 // nsHashPropertyBagOMT is supposed to be used off-main thread. If you need a
346 // single threaded property bag on the main thread, you should consider using
347 // nsHashPropertyBagCC instead, to prevent leaks.
348 MOZ_ASSERT(!NS_IsMainThread());
352 * nsHashPropertyBagCC implementation.
355 NS_IMPL_CYCLE_COLLECTION(nsHashPropertyBagCC, mPropertyHash)
357 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHashPropertyBagCC)
358 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHashPropertyBagCC)
360 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHashPropertyBagCC)
361 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
362 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
363 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
364 NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
365 NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
366 NS_INTERFACE_MAP_END