Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / storage / Variant.h
bloba2b580e284de44499246e3c060949bbb5867dc2b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
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 #ifndef mozilla_storage_Variant_h__
8 #define mozilla_storage_Variant_h__
10 #include <utility>
12 #include "nsIVariant.h"
13 #include "nsMemory.h"
14 #include "nsString.h"
15 #include "nsTArray.h"
17 #define VARIANT_BASE_IID \
18 { /* 78888042-0fa3-4f7a-8b19-7996f99bf1aa */ \
19 0x78888042, 0x0fa3, 0x4f7a, { \
20 0x8b, 0x19, 0x79, 0x96, 0xf9, 0x9b, 0xf1, 0xaa \
21 } \
24 /**
25 * This class is used by the storage module whenever an nsIVariant needs to be
26 * returned. We provide traits for the basic sqlite types to make use easier.
27 * The following types map to the indicated sqlite type:
28 * int64_t -> INTEGER (use IntegerVariant)
29 * double -> FLOAT (use FloatVariant)
30 * nsString -> TEXT (use TextVariant)
31 * nsCString -> TEXT (use UTF8TextVariant)
32 * uint8_t[] -> BLOB (use BlobVariant)
33 * nullptr -> NULL (use NullVariant)
35 * The kvstore component also reuses this class as a common implementation
36 * of a simple threadsafe variant for the storage of primitive values only.
37 * The BooleanVariant type has been introduced for kvstore use cases and should
38 * be enhanced to provide full boolean variant support for mozStorage.
40 * Bug 1494102 tracks that work.
43 namespace mozilla {
44 namespace storage {
46 ////////////////////////////////////////////////////////////////////////////////
47 //// Base Class
49 class Variant_base : public nsIVariant {
50 public:
51 NS_DECL_THREADSAFE_ISUPPORTS
52 NS_DECL_NSIVARIANT
53 NS_DECLARE_STATIC_IID_ACCESSOR(VARIANT_BASE_IID)
55 protected:
56 virtual ~Variant_base() = default;
59 NS_DEFINE_STATIC_IID_ACCESSOR(Variant_base, VARIANT_BASE_IID)
61 ////////////////////////////////////////////////////////////////////////////////
62 //// Traits
64 /**
65 * Generics
68 template <typename DataType>
69 struct variant_traits {
70 static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; }
73 template <typename DataType, bool Adopting = false>
74 struct variant_storage_traits {
75 typedef DataType ConstructorType;
76 typedef DataType StorageType;
77 static inline void storage_conversion(const ConstructorType aData,
78 StorageType* _storage) {
79 *_storage = aData;
82 static inline void destroy(const StorageType& _storage) {}
85 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
87 template <typename DataType, bool Adopting = false>
88 struct variant_boolean_traits {
89 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
90 StorageType;
91 static inline nsresult asBool(const StorageType&, bool*) { NO_CONVERSION }
94 template <typename DataType, bool Adopting = false>
95 struct variant_integer_traits {
96 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
97 StorageType;
98 static inline nsresult asInt32(const StorageType&, int32_t*) { NO_CONVERSION }
99 static inline nsresult asInt64(const StorageType&, int64_t*) { NO_CONVERSION }
102 template <typename DataType, bool Adopting = false>
103 struct variant_float_traits {
104 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
105 StorageType;
106 static inline nsresult asDouble(const StorageType&, double*) { NO_CONVERSION }
109 template <typename DataType, bool Adopting = false>
110 struct variant_text_traits {
111 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
112 StorageType;
113 static inline nsresult asUTF8String(const StorageType&, nsACString&) {
114 NO_CONVERSION
116 static inline nsresult asString(const StorageType&, nsAString&) {
117 NO_CONVERSION
121 template <typename DataType, bool Adopting = false>
122 struct variant_blob_traits {
123 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
124 StorageType;
125 static inline nsresult asArray(const StorageType&, uint16_t*, uint32_t*,
126 void**) {
127 NO_CONVERSION
131 #undef NO_CONVERSION
134 * BOOLEAN type
137 template <>
138 struct variant_traits<bool> {
139 static inline uint16_t type() { return nsIDataType::VTYPE_BOOL; }
141 template <>
142 struct variant_boolean_traits<bool> {
143 static inline nsresult asBool(bool aValue, bool* _result) {
144 *_result = aValue;
145 return NS_OK;
148 // NB: It might be worth also providing conversions to int types.
150 // NB: It'd be nice to implement asBool conversions for 0 and 1, too.
151 // That would let us clean up some conversions in Places, such as:
152 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#564-565
153 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#1057
154 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/nsNavHistory.cpp#3189
158 * INTEGER types
161 template <>
162 struct variant_traits<int64_t> {
163 static inline uint16_t type() { return nsIDataType::VTYPE_INT64; }
165 template <>
166 struct variant_integer_traits<int64_t> {
167 static inline nsresult asInt32(int64_t aValue, int32_t* _result) {
168 if (aValue > INT32_MAX || aValue < INT32_MIN)
169 return NS_ERROR_CANNOT_CONVERT_DATA;
171 *_result = static_cast<int32_t>(aValue);
172 return NS_OK;
174 static inline nsresult asInt64(int64_t aValue, int64_t* _result) {
175 *_result = aValue;
176 return NS_OK;
179 // xpcvariant just calls get double for integers...
180 template <>
181 struct variant_float_traits<int64_t> {
182 static inline nsresult asDouble(int64_t aValue, double* _result) {
183 *_result = double(aValue);
184 return NS_OK;
189 * FLOAT types
192 template <>
193 struct variant_traits<double> {
194 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; }
196 template <>
197 struct variant_float_traits<double> {
198 static inline nsresult asDouble(double aValue, double* _result) {
199 *_result = aValue;
200 return NS_OK;
205 * TEXT types
208 template <>
209 struct variant_traits<nsString> {
210 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; }
212 template <>
213 struct variant_storage_traits<nsString> {
214 typedef const nsAString& ConstructorType;
215 typedef nsString StorageType;
216 static inline void storage_conversion(ConstructorType aText,
217 StorageType* _outData) {
218 *_outData = aText;
220 static inline void destroy(const StorageType& _outData) {}
222 template <>
223 struct variant_text_traits<nsString> {
224 static inline nsresult asUTF8String(const nsString& aValue,
225 nsACString& _result) {
226 CopyUTF16toUTF8(aValue, _result);
227 return NS_OK;
229 static inline nsresult asString(const nsString& aValue, nsAString& _result) {
230 _result = aValue;
231 return NS_OK;
235 template <>
236 struct variant_traits<nsCString> {
237 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; }
239 template <>
240 struct variant_storage_traits<nsCString> {
241 typedef const nsACString& ConstructorType;
242 typedef nsCString StorageType;
243 static inline void storage_conversion(ConstructorType aText,
244 StorageType* _outData) {
245 *_outData = aText;
247 static inline void destroy(const StorageType& aData) {}
249 template <>
250 struct variant_text_traits<nsCString> {
251 static inline nsresult asUTF8String(const nsCString& aValue,
252 nsACString& _result) {
253 _result = aValue;
254 return NS_OK;
256 static inline nsresult asString(const nsCString& aValue, nsAString& _result) {
257 CopyUTF8toUTF16(aValue, _result);
258 return NS_OK;
263 * BLOB types
266 template <>
267 struct variant_traits<uint8_t[]> {
268 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; }
270 template <>
271 struct variant_storage_traits<uint8_t[], false> {
272 typedef std::pair<const void*, int> ConstructorType;
273 typedef FallibleTArray<uint8_t> StorageType;
274 static inline void storage_conversion(ConstructorType aBlob,
275 StorageType* _outData) {
276 _outData->Clear();
277 (void)_outData->AppendElements(static_cast<const uint8_t*>(aBlob.first),
278 aBlob.second, fallible);
280 static inline void destroy(const StorageType& _outData) {}
282 template <>
283 struct variant_storage_traits<uint8_t[], true> {
284 typedef std::pair<uint8_t*, int> ConstructorType;
285 typedef std::pair<uint8_t*, int> StorageType;
286 static inline void storage_conversion(ConstructorType aBlob,
287 StorageType* _outData) {
288 *_outData = aBlob;
290 static inline void destroy(StorageType& aData) {
291 if (aData.first) {
292 free(aData.first);
293 aData.first = nullptr;
297 template <>
298 struct variant_blob_traits<uint8_t[], false> {
299 static inline nsresult asArray(FallibleTArray<uint8_t>& aData,
300 uint16_t* _type, uint32_t* _size,
301 void** _result) {
302 // For empty blobs, we return nullptr.
303 if (aData.Length() == 0) {
304 *_result = nullptr;
305 *_type = nsIDataType::VTYPE_UINT8;
306 *_size = 0;
307 return NS_OK;
310 // Otherwise, we copy the array.
311 *_result = moz_xmemdup(aData.Elements(), aData.Length() * sizeof(uint8_t));
313 // Set type and size
314 *_type = nsIDataType::VTYPE_UINT8;
315 *_size = aData.Length();
316 return NS_OK;
320 template <>
321 struct variant_blob_traits<uint8_t[], true> {
322 static inline nsresult asArray(std::pair<uint8_t*, int>& aData,
323 uint16_t* _type, uint32_t* _size,
324 void** _result) {
325 // For empty blobs, we return nullptr.
326 if (aData.second == 0) {
327 *_result = nullptr;
328 *_type = nsIDataType::VTYPE_UINT8;
329 *_size = 0;
330 return NS_OK;
333 // Otherwise, transfer the data out.
334 *_result = aData.first;
335 aData.first = nullptr;
336 MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting!
338 // Set type and size
339 *_type = nsIDataType::VTYPE_UINT8;
340 *_size = aData.second;
341 return NS_OK;
346 * nullptr type
349 class NullVariant : public Variant_base {
350 public:
351 uint16_t GetDataType() override { return nsIDataType::VTYPE_EMPTY; }
353 NS_IMETHOD GetAsAUTF8String(nsACString& _str) override {
354 // Return a void string.
355 _str.SetIsVoid(true);
356 return NS_OK;
359 NS_IMETHOD GetAsAString(nsAString& _str) override {
360 // Return a void string.
361 _str.SetIsVoid(true);
362 return NS_OK;
366 ////////////////////////////////////////////////////////////////////////////////
367 //// Template Implementation
369 template <typename DataType, bool Adopting = false>
370 class Variant final : public Variant_base {
371 ~Variant() { variant_storage_traits<DataType, Adopting>::destroy(mData); }
373 public:
374 explicit Variant(
375 const typename variant_storage_traits<DataType, Adopting>::ConstructorType
376 aData) {
377 variant_storage_traits<DataType, Adopting>::storage_conversion(aData,
378 &mData);
381 uint16_t GetDataType() override { return variant_traits<DataType>::type(); }
383 NS_IMETHOD GetAsBool(bool* _boolean) override {
384 return variant_boolean_traits<DataType, Adopting>::asBool(mData, _boolean);
387 NS_IMETHOD GetAsInt32(int32_t* _integer) override {
388 return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer);
391 NS_IMETHOD GetAsInt64(int64_t* _integer) override {
392 return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer);
395 NS_IMETHOD GetAsDouble(double* _double) override {
396 return variant_float_traits<DataType, Adopting>::asDouble(mData, _double);
399 NS_IMETHOD GetAsAUTF8String(nsACString& _str) override {
400 return variant_text_traits<DataType, Adopting>::asUTF8String(mData, _str);
403 NS_IMETHOD GetAsAString(nsAString& _str) override {
404 return variant_text_traits<DataType, Adopting>::asString(mData, _str);
407 NS_IMETHOD GetAsArray(uint16_t* _type, nsIID*, uint32_t* _size,
408 void** _data) override {
409 return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size,
410 _data);
413 private:
414 typename variant_storage_traits<DataType, Adopting>::StorageType mData;
417 ////////////////////////////////////////////////////////////////////////////////
418 //// Handy typedefs! Use these for the right mapping.
420 // Currently, BooleanVariant is only useful for kvstore.
421 // Bug 1494102 tracks implementing full boolean variant support for mozStorage.
422 typedef Variant<bool> BooleanVariant;
424 typedef Variant<int64_t> IntegerVariant;
425 typedef Variant<double> FloatVariant;
426 typedef Variant<nsString> TextVariant;
427 typedef Variant<nsCString> UTF8TextVariant;
428 typedef Variant<uint8_t[], false> BlobVariant;
429 typedef Variant<uint8_t[], true> AdoptedBlobVariant;
431 } // namespace storage
432 } // namespace mozilla
434 #include "Variant_inl.h"
436 #endif // mozilla_storage_Variant_h__