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"
16 #define VARIANT_BASE_IID \
17 { /* 78888042-0fa3-4f7a-8b19-7996f99bf1aa */ \
18 0x78888042, 0x0fa3, 0x4f7a, { \
19 0x8b, 0x19, 0x79, 0x96, 0xf9, 0x9b, 0xf1, 0xaa \
24 * This class is used by the storage module whenever an nsIVariant needs to be
25 * returned. We provide traits for the basic sqlite types to make use easier.
26 * The following types map to the indicated sqlite type:
27 * int64_t -> INTEGER (use IntegerVariant)
28 * double -> FLOAT (use FloatVariant)
29 * nsString -> TEXT (use TextVariant)
30 * nsCString -> TEXT (use UTF8TextVariant)
31 * uint8_t[] -> BLOB (use BlobVariant)
32 * nullptr -> NULL (use NullVariant)
34 * The kvstore component also reuses this class as a common implementation
35 * of a simple threadsafe variant for the storage of primitive values only.
36 * The BooleanVariant type has been introduced for kvstore use cases and should
37 * be enhanced to provide full boolean variant support for mozStorage.
39 * Bug 1494102 tracks that work.
45 ////////////////////////////////////////////////////////////////////////////////
48 class Variant_base
: public nsIVariant
{
50 NS_DECL_THREADSAFE_ISUPPORTS
52 NS_DECLARE_STATIC_IID_ACCESSOR(VARIANT_BASE_IID
)
55 virtual ~Variant_base() = default;
58 NS_DEFINE_STATIC_IID_ACCESSOR(Variant_base
, VARIANT_BASE_IID
)
60 ////////////////////////////////////////////////////////////////////////////////
67 template <typename DataType
>
68 struct variant_traits
{
69 static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY
; }
72 template <typename DataType
, bool Adopting
= false>
73 struct variant_storage_traits
{
74 typedef DataType ConstructorType
;
75 typedef DataType StorageType
;
76 static inline void storage_conversion(const ConstructorType aData
,
77 StorageType
* _storage
) {
81 static inline void destroy(const StorageType
& _storage
) {}
84 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
86 template <typename DataType
, bool Adopting
= false>
87 struct variant_boolean_traits
{
88 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
90 static inline nsresult
asBool(const StorageType
&, bool*) { NO_CONVERSION
}
93 template <typename DataType
, bool Adopting
= false>
94 struct variant_integer_traits
{
95 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
97 static inline nsresult
asInt32(const StorageType
&, int32_t*) { NO_CONVERSION
}
98 static inline nsresult
asInt64(const StorageType
&, int64_t*) { NO_CONVERSION
}
101 template <typename DataType
, bool Adopting
= false>
102 struct variant_float_traits
{
103 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
105 static inline nsresult
asDouble(const StorageType
&, double*) { NO_CONVERSION
}
108 template <typename DataType
, bool Adopting
= false>
109 struct variant_text_traits
{
110 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
112 static inline nsresult
asUTF8String(const StorageType
&, nsACString
&) {
115 static inline nsresult
asString(const StorageType
&, nsAString
&) {
120 template <typename DataType
, bool Adopting
= false>
121 struct variant_blob_traits
{
122 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
124 static inline nsresult
asArray(const StorageType
&, uint16_t*, uint32_t*,
137 struct variant_traits
<bool> {
138 static inline uint16_t type() { return nsIDataType::VTYPE_BOOL
; }
141 struct variant_boolean_traits
<bool> {
142 static inline nsresult
asBool(bool aValue
, bool* _result
) {
147 // NB: It might be worth also providing conversions to int types.
149 // NB: It'd be nice to implement asBool conversions for 0 and 1, too.
150 // That would let us clean up some conversions in Places, such as:
151 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#564-565
152 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#1057
153 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/nsNavHistory.cpp#3189
161 struct variant_traits
<int64_t> {
162 static inline uint16_t type() { return nsIDataType::VTYPE_INT64
; }
165 struct variant_integer_traits
<int64_t> {
166 static inline nsresult
asInt32(int64_t aValue
, int32_t* _result
) {
167 if (aValue
> INT32_MAX
|| aValue
< INT32_MIN
)
168 return NS_ERROR_CANNOT_CONVERT_DATA
;
170 *_result
= static_cast<int32_t>(aValue
);
173 static inline nsresult
asInt64(int64_t aValue
, int64_t* _result
) {
178 // xpcvariant just calls get double for integers...
180 struct variant_float_traits
<int64_t> {
181 static inline nsresult
asDouble(int64_t aValue
, double* _result
) {
182 *_result
= double(aValue
);
192 struct variant_traits
<double> {
193 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE
; }
196 struct variant_float_traits
<double> {
197 static inline nsresult
asDouble(double aValue
, double* _result
) {
208 struct variant_traits
<nsString
> {
209 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING
; }
212 struct variant_storage_traits
<nsString
> {
213 typedef const nsAString
& ConstructorType
;
214 typedef nsString StorageType
;
215 static inline void storage_conversion(ConstructorType aText
,
216 StorageType
* _outData
) {
219 static inline void destroy(const StorageType
& _outData
) {}
222 struct variant_text_traits
<nsString
> {
223 static inline nsresult
asUTF8String(const nsString
& aValue
,
224 nsACString
& _result
) {
225 CopyUTF16toUTF8(aValue
, _result
);
228 static inline nsresult
asString(const nsString
& aValue
, nsAString
& _result
) {
235 struct variant_traits
<nsCString
> {
236 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING
; }
239 struct variant_storage_traits
<nsCString
> {
240 typedef const nsACString
& ConstructorType
;
241 typedef nsCString StorageType
;
242 static inline void storage_conversion(ConstructorType aText
,
243 StorageType
* _outData
) {
246 static inline void destroy(const StorageType
& aData
) {}
249 struct variant_text_traits
<nsCString
> {
250 static inline nsresult
asUTF8String(const nsCString
& aValue
,
251 nsACString
& _result
) {
255 static inline nsresult
asString(const nsCString
& aValue
, nsAString
& _result
) {
256 CopyUTF8toUTF16(aValue
, _result
);
266 struct variant_traits
<uint8_t[]> {
267 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY
; }
270 struct variant_storage_traits
<uint8_t[], false> {
271 typedef std::pair
<const void*, int> ConstructorType
;
272 typedef FallibleTArray
<uint8_t> StorageType
;
273 static inline void storage_conversion(ConstructorType aBlob
,
274 StorageType
* _outData
) {
276 (void)_outData
->AppendElements(static_cast<const uint8_t*>(aBlob
.first
),
277 aBlob
.second
, fallible
);
279 static inline void destroy(const StorageType
& _outData
) {}
282 struct variant_storage_traits
<uint8_t[], true> {
283 typedef std::pair
<uint8_t*, int> ConstructorType
;
284 typedef std::pair
<uint8_t*, int> StorageType
;
285 static inline void storage_conversion(ConstructorType aBlob
,
286 StorageType
* _outData
) {
289 static inline void destroy(StorageType
& aData
) {
292 aData
.first
= nullptr;
297 struct variant_blob_traits
<uint8_t[], false> {
298 static inline nsresult
asArray(FallibleTArray
<uint8_t>& aData
,
299 uint16_t* _type
, uint32_t* _size
,
301 // For empty blobs, we return nullptr.
302 if (aData
.Length() == 0) {
304 *_type
= nsIDataType::VTYPE_UINT8
;
309 // Otherwise, we copy the array.
310 *_result
= moz_xmemdup(aData
.Elements(), aData
.Length() * sizeof(uint8_t));
313 *_type
= nsIDataType::VTYPE_UINT8
;
314 *_size
= aData
.Length();
320 struct variant_blob_traits
<uint8_t[], true> {
321 static inline nsresult
asArray(std::pair
<uint8_t*, int>& aData
,
322 uint16_t* _type
, uint32_t* _size
,
324 // For empty blobs, we return nullptr.
325 if (aData
.second
== 0) {
327 *_type
= nsIDataType::VTYPE_UINT8
;
332 // Otherwise, transfer the data out.
333 *_result
= aData
.first
;
334 aData
.first
= nullptr;
335 MOZ_ASSERT(*_result
); // We asked for it twice, better not use adopting!
338 *_type
= nsIDataType::VTYPE_UINT8
;
339 *_size
= aData
.second
;
348 class NullVariant
: public Variant_base
{
350 uint16_t GetDataType() override
{ return nsIDataType::VTYPE_EMPTY
; }
352 NS_IMETHOD
GetAsAUTF8String(nsACString
& _str
) override
{
353 // Return a void string.
354 _str
.SetIsVoid(true);
358 NS_IMETHOD
GetAsAString(nsAString
& _str
) override
{
359 // Return a void string.
360 _str
.SetIsVoid(true);
365 ////////////////////////////////////////////////////////////////////////////////
366 //// Template Implementation
368 template <typename DataType
, bool Adopting
= false>
369 class Variant final
: public Variant_base
{
370 ~Variant() { variant_storage_traits
<DataType
, Adopting
>::destroy(mData
); }
374 const typename variant_storage_traits
<DataType
, Adopting
>::ConstructorType
376 variant_storage_traits
<DataType
, Adopting
>::storage_conversion(aData
,
380 uint16_t GetDataType() override
{ return variant_traits
<DataType
>::type(); }
382 NS_IMETHOD
GetAsBool(bool* _boolean
) override
{
383 return variant_boolean_traits
<DataType
, Adopting
>::asBool(mData
, _boolean
);
386 NS_IMETHOD
GetAsInt32(int32_t* _integer
) override
{
387 return variant_integer_traits
<DataType
, Adopting
>::asInt32(mData
, _integer
);
390 NS_IMETHOD
GetAsInt64(int64_t* _integer
) override
{
391 return variant_integer_traits
<DataType
, Adopting
>::asInt64(mData
, _integer
);
394 NS_IMETHOD
GetAsDouble(double* _double
) override
{
395 return variant_float_traits
<DataType
, Adopting
>::asDouble(mData
, _double
);
398 NS_IMETHOD
GetAsAUTF8String(nsACString
& _str
) override
{
399 return variant_text_traits
<DataType
, Adopting
>::asUTF8String(mData
, _str
);
402 NS_IMETHOD
GetAsAString(nsAString
& _str
) override
{
403 return variant_text_traits
<DataType
, Adopting
>::asString(mData
, _str
);
406 NS_IMETHOD
GetAsArray(uint16_t* _type
, nsIID
*, uint32_t* _size
,
407 void** _data
) override
{
408 return variant_blob_traits
<DataType
, Adopting
>::asArray(mData
, _type
, _size
,
413 typename variant_storage_traits
<DataType
, Adopting
>::StorageType mData
;
416 ////////////////////////////////////////////////////////////////////////////////
417 //// Handy typedefs! Use these for the right mapping.
419 // Currently, BooleanVariant is only useful for kvstore.
420 // Bug 1494102 tracks implementing full boolean variant support for mozStorage.
421 typedef Variant
<bool> BooleanVariant
;
423 typedef Variant
<int64_t> IntegerVariant
;
424 typedef Variant
<double> FloatVariant
;
425 typedef Variant
<nsString
> TextVariant
;
426 typedef Variant
<nsCString
> UTF8TextVariant
;
427 typedef Variant
<uint8_t[], false> BlobVariant
;
428 typedef Variant
<uint8_t[], true> AdoptedBlobVariant
;
430 } // namespace storage
431 } // namespace mozilla
433 #include "Variant_inl.h"
435 #endif // mozilla_storage_Variant_h__