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"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/SimpleEnumerator.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
;
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
);
35 * nsHashPropertyBagBase implementation.
39 nsHashPropertyBagBase::HasKey(const nsAString
& aName
, bool* aResult
) {
40 *aResult
= mPropertyHash
.Get(aName
, nullptr);
45 nsHashPropertyBagBase::Get(const nsAString
& aName
, nsIVariant
** aResult
) {
46 if (!mPropertyHash
.Get(aName
, aResult
)) {
54 nsHashPropertyBagBase::GetProperty(const nsAString
& aName
,
55 nsIVariant
** aResult
) {
56 bool isFound
= mPropertyHash
.Get(aName
, aResult
);
58 return NS_ERROR_FAILURE
;
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
);
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;
88 nsSimpleProperty(const nsAString
& aName
, nsIVariant
* aValue
)
89 : mName(aName
), mValue(aValue
) {}
95 nsCOMPtr
<nsIVariant
> mValue
;
98 NS_IMPL_ISUPPORTS(nsSimpleProperty
, nsIProperty
)
101 nsSimpleProperty::GetName(nsAString
& aName
) {
107 nsSimpleProperty::GetValue(nsIVariant
** aValue
) {
108 NS_IF_ADDREF(*aValue
= mValue
);
112 // end nsSimpleProperty
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) \
133 nsHashPropertyBagBase::GetPropertyAs##Name(const nsAString& prop, \
135 nsIVariant* v = mPropertyHash.GetWeak(prop); \
136 if (!v) return NS_ERROR_NOT_AVAILABLE; \
137 return v->GetAs##Name(_retval); \
141 nsHashPropertyBagBase::SetPropertyAs##Name(const nsAString& prop, \
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)
156 nsHashPropertyBagBase::GetPropertyAsAString(const nsAString
& aProp
,
157 nsAString
& aResult
) {
158 nsIVariant
* v
= mPropertyHash
.GetWeak(aProp
);
160 return NS_ERROR_NOT_AVAILABLE
;
162 return v
->GetAsAString(aResult
);
166 nsHashPropertyBagBase::GetPropertyAsACString(const nsAString
& aProp
,
167 nsACString
& aResult
) {
168 nsIVariant
* v
= mPropertyHash
.GetWeak(aProp
);
170 return NS_ERROR_NOT_AVAILABLE
;
172 return v
->GetAsACString(aResult
);
176 nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString
& aProp
,
177 nsACString
& aResult
) {
178 nsIVariant
* v
= mPropertyHash
.GetWeak(aProp
);
180 return NS_ERROR_NOT_AVAILABLE
;
182 return v
->GetAsAUTF8String(aResult
);
186 nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString
& aProp
,
189 nsIVariant
* v
= mPropertyHash
.GetWeak(aProp
);
191 return NS_ERROR_NOT_AVAILABLE
;
193 nsCOMPtr
<nsISupports
> val
;
194 nsresult rv
= v
->GetAsISupports(getter_AddRefs(val
));
199 // We have a value, but it's null
203 return val
->QueryInterface(aIID
, aResult
);
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
);
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
);
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
);
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();
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
) {
252 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
253 if (NS_SUCCEEDED(aFrom
->GetEnumerator(getter_AddRefs(enumerator
)))) {
254 for (auto& property
: SimpleEnumerator
<nsIProperty
>(enumerator
)) {
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
)));
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
)
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
{
290 using HashtableType
= nsInterfaceHashtable
<nsStringHashKey
, nsIVariant
>;
291 explicit ProxyHashtableDestructor(HashtableType
&& aTable
)
292 : mozilla::Runnable("ProxyHashtableDestructor"),
293 mPropertyHash(std::move(aTable
)) {}
297 MOZ_ASSERT(NS_IsMainThread());
298 HashtableType
table(std::move(mPropertyHash
));
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
)