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() {}
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 *) {
101 static inline nsresult
asInt64(const StorageType
&, int64_t *) {
106 template <typename DataType
, bool Adopting
= false>
107 struct variant_float_traits
{
108 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
110 static inline nsresult
asDouble(const StorageType
&, double *) {
115 template <typename DataType
, bool Adopting
= false>
116 struct variant_text_traits
{
117 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
119 static inline nsresult
asUTF8String(const StorageType
&, nsACString
&) {
122 static inline nsresult
asString(const StorageType
&, nsAString
&) {
127 template <typename DataType
, bool Adopting
= false>
128 struct variant_blob_traits
{
129 typedef typename variant_storage_traits
<DataType
, Adopting
>::StorageType
131 static inline nsresult
asArray(const StorageType
&, uint16_t *, uint32_t *,
144 struct variant_traits
<bool> {
145 static inline uint16_t type() { return nsIDataType::VTYPE_BOOL
; }
148 struct variant_boolean_traits
<bool> {
149 static inline nsresult
asBool(bool aValue
, bool *_result
) {
154 // NB: It might be worth also providing conversions to int types.
156 // NB: It'd be nice to implement asBool conversions for 0 and 1, too.
157 // That would let us clean up some conversions in Places, such as:
158 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#564-565
159 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#1057
160 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/nsNavHistory.cpp#3189
168 struct variant_traits
<int64_t> {
169 static inline uint16_t type() { return nsIDataType::VTYPE_INT64
; }
172 struct variant_integer_traits
<int64_t> {
173 static inline nsresult
asInt32(int64_t aValue
, int32_t *_result
) {
174 if (aValue
> INT32_MAX
|| aValue
< INT32_MIN
)
175 return NS_ERROR_CANNOT_CONVERT_DATA
;
177 *_result
= static_cast<int32_t>(aValue
);
180 static inline nsresult
asInt64(int64_t aValue
, int64_t *_result
) {
185 // xpcvariant just calls get double for integers...
187 struct variant_float_traits
<int64_t> {
188 static inline nsresult
asDouble(int64_t aValue
, double *_result
) {
189 *_result
= double(aValue
);
199 struct variant_traits
<double> {
200 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE
; }
203 struct variant_float_traits
<double> {
204 static inline nsresult
asDouble(double aValue
, double *_result
) {
215 struct variant_traits
<nsString
> {
216 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING
; }
219 struct variant_storage_traits
<nsString
> {
220 typedef const nsAString
&ConstructorType
;
221 typedef nsString StorageType
;
222 static inline void storage_conversion(ConstructorType aText
,
223 StorageType
*_outData
) {
226 static inline void destroy(const StorageType
&_outData
) {}
229 struct variant_text_traits
<nsString
> {
230 static inline nsresult
asUTF8String(const nsString
&aValue
,
231 nsACString
&_result
) {
232 CopyUTF16toUTF8(aValue
, _result
);
235 static inline nsresult
asString(const nsString
&aValue
, nsAString
&_result
) {
242 struct variant_traits
<nsCString
> {
243 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING
; }
246 struct variant_storage_traits
<nsCString
> {
247 typedef const nsACString
&ConstructorType
;
248 typedef nsCString StorageType
;
249 static inline void storage_conversion(ConstructorType aText
,
250 StorageType
*_outData
) {
253 static inline void destroy(const StorageType
&aData
) {}
256 struct variant_text_traits
<nsCString
> {
257 static inline nsresult
asUTF8String(const nsCString
&aValue
,
258 nsACString
&_result
) {
262 static inline nsresult
asString(const nsCString
&aValue
, nsAString
&_result
) {
263 CopyUTF8toUTF16(aValue
, _result
);
273 struct variant_traits
<uint8_t[]> {
274 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY
; }
277 struct variant_storage_traits
<uint8_t[], false> {
278 typedef std::pair
<const void *, int> ConstructorType
;
279 typedef FallibleTArray
<uint8_t> StorageType
;
280 static inline void storage_conversion(ConstructorType aBlob
,
281 StorageType
*_outData
) {
283 (void)_outData
->AppendElements(static_cast<const uint8_t *>(aBlob
.first
),
284 aBlob
.second
, fallible
);
286 static inline void destroy(const StorageType
&_outData
) {}
289 struct variant_storage_traits
<uint8_t[], true> {
290 typedef std::pair
<uint8_t *, int> ConstructorType
;
291 typedef std::pair
<uint8_t *, int> StorageType
;
292 static inline void storage_conversion(ConstructorType aBlob
,
293 StorageType
*_outData
) {
296 static inline void destroy(StorageType
&aData
) {
299 aData
.first
= nullptr;
304 struct variant_blob_traits
<uint8_t[], false> {
305 static inline nsresult
asArray(FallibleTArray
<uint8_t> &aData
,
306 uint16_t *_type
, uint32_t *_size
,
308 // For empty blobs, we return nullptr.
309 if (aData
.Length() == 0) {
311 *_type
= nsIDataType::VTYPE_UINT8
;
316 // Otherwise, we copy the array.
317 *_result
= moz_xmemdup(aData
.Elements(), aData
.Length() * sizeof(uint8_t));
320 *_type
= nsIDataType::VTYPE_UINT8
;
321 *_size
= aData
.Length();
327 struct variant_blob_traits
<uint8_t[], true> {
328 static inline nsresult
asArray(std::pair
<uint8_t *, int> &aData
,
329 uint16_t *_type
, uint32_t *_size
,
331 // For empty blobs, we return nullptr.
332 if (aData
.second
== 0) {
334 *_type
= nsIDataType::VTYPE_UINT8
;
339 // Otherwise, transfer the data out.
340 *_result
= aData
.first
;
341 aData
.first
= nullptr;
342 MOZ_ASSERT(*_result
); // We asked for it twice, better not use adopting!
345 *_type
= nsIDataType::VTYPE_UINT8
;
346 *_size
= aData
.second
;
355 class NullVariant
: public Variant_base
{
357 uint16_t GetDataType() override
{ return nsIDataType::VTYPE_EMPTY
; }
359 NS_IMETHOD
GetAsAUTF8String(nsACString
&_str
) override
{
360 // Return a void string.
361 _str
.SetIsVoid(true);
365 NS_IMETHOD
GetAsAString(nsAString
&_str
) override
{
366 // Return a void string.
367 _str
.SetIsVoid(true);
372 ////////////////////////////////////////////////////////////////////////////////
373 //// Template Implementation
375 template <typename DataType
, bool Adopting
= false>
376 class Variant final
: public Variant_base
{
377 ~Variant() { variant_storage_traits
<DataType
, Adopting
>::destroy(mData
); }
381 const typename variant_storage_traits
<DataType
, Adopting
>::ConstructorType
383 variant_storage_traits
<DataType
, Adopting
>::storage_conversion(aData
,
387 uint16_t GetDataType() override
{ return variant_traits
<DataType
>::type(); }
389 NS_IMETHOD
GetAsBool(bool *_boolean
) override
{
390 return variant_boolean_traits
<DataType
, Adopting
>::asBool(mData
, _boolean
);
393 NS_IMETHOD
GetAsInt32(int32_t *_integer
) override
{
394 return variant_integer_traits
<DataType
, Adopting
>::asInt32(mData
, _integer
);
397 NS_IMETHOD
GetAsInt64(int64_t *_integer
) override
{
398 return variant_integer_traits
<DataType
, Adopting
>::asInt64(mData
, _integer
);
401 NS_IMETHOD
GetAsDouble(double *_double
) override
{
402 return variant_float_traits
<DataType
, Adopting
>::asDouble(mData
, _double
);
405 NS_IMETHOD
GetAsAUTF8String(nsACString
&_str
) override
{
406 return variant_text_traits
<DataType
, Adopting
>::asUTF8String(mData
, _str
);
409 NS_IMETHOD
GetAsAString(nsAString
&_str
) override
{
410 return variant_text_traits
<DataType
, Adopting
>::asString(mData
, _str
);
413 NS_IMETHOD
GetAsArray(uint16_t *_type
, nsIID
*, uint32_t *_size
,
414 void **_data
) override
{
415 return variant_blob_traits
<DataType
, Adopting
>::asArray(mData
, _type
, _size
,
420 typename variant_storage_traits
<DataType
, Adopting
>::StorageType mData
;
423 ////////////////////////////////////////////////////////////////////////////////
424 //// Handy typedefs! Use these for the right mapping.
426 // Currently, BooleanVariant is only useful for kvstore.
427 // Bug 1494102 tracks implementing full boolean variant support for mozStorage.
428 typedef Variant
<bool> BooleanVariant
;
430 typedef Variant
<int64_t> IntegerVariant
;
431 typedef Variant
<double> FloatVariant
;
432 typedef Variant
<nsString
> TextVariant
;
433 typedef Variant
<nsCString
> UTF8TextVariant
;
434 typedef Variant
<uint8_t[], false> BlobVariant
;
435 typedef Variant
<uint8_t[], true> AdoptedBlobVariant
;
437 } // namespace storage
438 } // namespace mozilla
440 #include "Variant_inl.h"
442 #endif // mozilla_storage_Variant_h__