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__
12 #include "nsIVariant.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 \
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.
46 ////////////////////////////////////////////////////////////////////////////////
49 class Variant_base
: public nsIVariant
{
51 NS_DECL_THREADSAFE_ISUPPORTS
53 NS_DECLARE_STATIC_IID_ACCESSOR(VARIANT_BASE_IID
)
56 virtual ~Variant_base() = default;
59 NS_DEFINE_STATIC_IID_ACCESSOR(Variant_base
, VARIANT_BASE_IID
)
61 ////////////////////////////////////////////////////////////////////////////////
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
) {
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
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
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
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
113 static inline nsresult
asUTF8String(const StorageType
&, nsACString
&) {
116 static inline nsresult
asString(const StorageType
&, nsAString
&) {
121 template <typename DataType
, bool Adopting
= false>
122 struct variant_blob_traits
{
123 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
125 static inline nsresult
asArray(const StorageType
&, uint16_t*, uint32_t*,
138 struct variant_traits
<bool> {
139 static inline uint16_t type() { return nsIDataType::VTYPE_BOOL
; }
142 struct variant_boolean_traits
<bool> {
143 static inline nsresult
asBool(bool aValue
, bool* _result
) {
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
162 struct variant_traits
<int64_t> {
163 static inline uint16_t type() { return nsIDataType::VTYPE_INT64
; }
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
);
174 static inline nsresult
asInt64(int64_t aValue
, int64_t* _result
) {
179 // xpcvariant just calls get double for integers...
181 struct variant_float_traits
<int64_t> {
182 static inline nsresult
asDouble(int64_t aValue
, double* _result
) {
183 *_result
= double(aValue
);
193 struct variant_traits
<double> {
194 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE
; }
197 struct variant_float_traits
<double> {
198 static inline nsresult
asDouble(double aValue
, double* _result
) {
209 struct variant_traits
<nsString
> {
210 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING
; }
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
) {
220 static inline void destroy(const StorageType
& _outData
) {}
223 struct variant_text_traits
<nsString
> {
224 static inline nsresult
asUTF8String(const nsString
& aValue
,
225 nsACString
& _result
) {
226 CopyUTF16toUTF8(aValue
, _result
);
229 static inline nsresult
asString(const nsString
& aValue
, nsAString
& _result
) {
236 struct variant_traits
<nsCString
> {
237 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING
; }
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
) {
247 static inline void destroy(const StorageType
& aData
) {}
250 struct variant_text_traits
<nsCString
> {
251 static inline nsresult
asUTF8String(const nsCString
& aValue
,
252 nsACString
& _result
) {
256 static inline nsresult
asString(const nsCString
& aValue
, nsAString
& _result
) {
257 CopyUTF8toUTF16(aValue
, _result
);
267 struct variant_traits
<uint8_t[]> {
268 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY
; }
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
) {
277 (void)_outData
->AppendElements(static_cast<const uint8_t*>(aBlob
.first
),
278 aBlob
.second
, fallible
);
280 static inline void destroy(const StorageType
& _outData
) {}
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
) {
290 static inline void destroy(StorageType
& aData
) {
293 aData
.first
= nullptr;
298 struct variant_blob_traits
<uint8_t[], false> {
299 static inline nsresult
asArray(FallibleTArray
<uint8_t>& aData
,
300 uint16_t* _type
, uint32_t* _size
,
302 // For empty blobs, we return nullptr.
303 if (aData
.Length() == 0) {
305 *_type
= nsIDataType::VTYPE_UINT8
;
310 // Otherwise, we copy the array.
311 *_result
= moz_xmemdup(aData
.Elements(), aData
.Length() * sizeof(uint8_t));
314 *_type
= nsIDataType::VTYPE_UINT8
;
315 *_size
= aData
.Length();
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
,
325 // For empty blobs, we return nullptr.
326 if (aData
.second
== 0) {
328 *_type
= nsIDataType::VTYPE_UINT8
;
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!
339 *_type
= nsIDataType::VTYPE_UINT8
;
340 *_size
= aData
.second
;
349 class NullVariant
: public Variant_base
{
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);
359 NS_IMETHOD
GetAsAString(nsAString
& _str
) override
{
360 // Return a void string.
361 _str
.SetIsVoid(true);
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
); }
375 const typename variant_storage_traits
<DataType
, Adopting
>::ConstructorType
377 variant_storage_traits
<DataType
, Adopting
>::storage_conversion(aData
,
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
,
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__