michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_storage_Variant_h__ michael@0: #define mozilla_storage_Variant_h__ michael@0: michael@0: #include michael@0: michael@0: #include "nsIVariant.h" michael@0: #include "nsString.h" michael@0: #include "nsTArray.h" michael@0: michael@0: /** michael@0: * This class is used by the storage module whenever an nsIVariant needs to be michael@0: * returned. We provide traits for the basic sqlite types to make use easier. michael@0: * The following types map to the indicated sqlite type: michael@0: * int64_t -> INTEGER (use IntegerVariant) michael@0: * double -> FLOAT (use FloatVariant) michael@0: * nsString -> TEXT (use TextVariant) michael@0: * nsCString -> TEXT (use UTF8TextVariant) michael@0: * uint8_t[] -> BLOB (use BlobVariant) michael@0: * nullptr -> NULL (use NullVariant) michael@0: */ michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Base Class michael@0: michael@0: class Variant_base : public nsIVariant michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIVARIANT michael@0: michael@0: protected: michael@0: virtual ~Variant_base() { } michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Traits michael@0: michael@0: /** michael@0: * Generics michael@0: */ michael@0: michael@0: template michael@0: struct variant_traits michael@0: { michael@0: static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; } michael@0: }; michael@0: michael@0: template michael@0: struct variant_storage_traits michael@0: { michael@0: typedef DataType ConstructorType; michael@0: typedef DataType StorageType; michael@0: static inline void storage_conversion(const ConstructorType aData, StorageType* _storage) michael@0: { michael@0: *_storage = aData; michael@0: } michael@0: michael@0: static inline void destroy(const StorageType& _storage) michael@0: { } michael@0: }; michael@0: michael@0: #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA; michael@0: michael@0: template michael@0: struct variant_integer_traits michael@0: { michael@0: typedef typename variant_storage_traits::StorageType StorageType; michael@0: static inline nsresult asInt32(const StorageType &, int32_t *) { NO_CONVERSION } michael@0: static inline nsresult asInt64(const StorageType &, int64_t *) { NO_CONVERSION } michael@0: }; michael@0: michael@0: template michael@0: struct variant_float_traits michael@0: { michael@0: typedef typename variant_storage_traits::StorageType StorageType; michael@0: static inline nsresult asDouble(const StorageType &, double *) { NO_CONVERSION } michael@0: }; michael@0: michael@0: template michael@0: struct variant_text_traits michael@0: { michael@0: typedef typename variant_storage_traits::StorageType StorageType; michael@0: static inline nsresult asUTF8String(const StorageType &, nsACString &) { NO_CONVERSION } michael@0: static inline nsresult asString(const StorageType &, nsAString &) { NO_CONVERSION } michael@0: }; michael@0: michael@0: template michael@0: struct variant_blob_traits michael@0: { michael@0: typedef typename variant_storage_traits::StorageType StorageType; michael@0: static inline nsresult asArray(const StorageType &, uint16_t *, uint32_t *, void **) michael@0: { NO_CONVERSION } michael@0: }; michael@0: michael@0: #undef NO_CONVERSION michael@0: michael@0: /** michael@0: * INTEGER types michael@0: */ michael@0: michael@0: template < > michael@0: struct variant_traits michael@0: { michael@0: static inline uint16_t type() { return nsIDataType::VTYPE_INT64; } michael@0: }; michael@0: template < > michael@0: struct variant_integer_traits michael@0: { michael@0: static inline nsresult asInt32(int64_t aValue, michael@0: int32_t *_result) michael@0: { michael@0: if (aValue > INT32_MAX || aValue < INT32_MIN) michael@0: return NS_ERROR_CANNOT_CONVERT_DATA; michael@0: michael@0: *_result = static_cast(aValue); michael@0: return NS_OK; michael@0: } michael@0: static inline nsresult asInt64(int64_t aValue, michael@0: int64_t *_result) michael@0: { michael@0: *_result = aValue; michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: // xpcvariant just calls get double for integers... michael@0: template < > michael@0: struct variant_float_traits michael@0: { michael@0: static inline nsresult asDouble(int64_t aValue, michael@0: double *_result) michael@0: { michael@0: *_result = double(aValue); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * FLOAT types michael@0: */ michael@0: michael@0: template < > michael@0: struct variant_traits michael@0: { michael@0: static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; } michael@0: }; michael@0: template < > michael@0: struct variant_float_traits michael@0: { michael@0: static inline nsresult asDouble(double aValue, michael@0: double *_result) michael@0: { michael@0: *_result = aValue; michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * TEXT types michael@0: */ michael@0: michael@0: template < > michael@0: struct variant_traits michael@0: { michael@0: static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; } michael@0: }; michael@0: template < > michael@0: struct variant_storage_traits michael@0: { michael@0: typedef const nsAString & ConstructorType; michael@0: typedef nsString StorageType; michael@0: static inline void storage_conversion(ConstructorType aText, StorageType* _outData) michael@0: { michael@0: *_outData = aText; michael@0: } michael@0: static inline void destroy(const StorageType& _outData) michael@0: { } michael@0: }; michael@0: template < > michael@0: struct variant_text_traits michael@0: { michael@0: static inline nsresult asUTF8String(const nsString &aValue, michael@0: nsACString &_result) michael@0: { michael@0: CopyUTF16toUTF8(aValue, _result); michael@0: return NS_OK; michael@0: } michael@0: static inline nsresult asString(const nsString &aValue, michael@0: nsAString &_result) michael@0: { michael@0: _result = aValue; michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: template < > michael@0: struct variant_traits michael@0: { michael@0: static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; } michael@0: }; michael@0: template < > michael@0: struct variant_storage_traits michael@0: { michael@0: typedef const nsACString & ConstructorType; michael@0: typedef nsCString StorageType; michael@0: static inline void storage_conversion(ConstructorType aText, StorageType* _outData) michael@0: { michael@0: *_outData = aText; michael@0: } michael@0: static inline void destroy(const StorageType &aData) michael@0: { } michael@0: }; michael@0: template < > michael@0: struct variant_text_traits michael@0: { michael@0: static inline nsresult asUTF8String(const nsCString &aValue, michael@0: nsACString &_result) michael@0: { michael@0: _result = aValue; michael@0: return NS_OK; michael@0: } michael@0: static inline nsresult asString(const nsCString &aValue, michael@0: nsAString &_result) michael@0: { michael@0: CopyUTF8toUTF16(aValue, _result); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * BLOB types michael@0: */ michael@0: michael@0: template < > michael@0: struct variant_traits michael@0: { michael@0: static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; } michael@0: }; michael@0: template < > michael@0: struct variant_storage_traits michael@0: { michael@0: typedef std::pair ConstructorType; michael@0: typedef FallibleTArray StorageType; michael@0: static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData) michael@0: { michael@0: _outData->Clear(); michael@0: _outData->SetCapacity(aBlob.second); michael@0: (void)_outData->AppendElements(static_cast(aBlob.first), michael@0: aBlob.second); michael@0: } michael@0: static inline void destroy(const StorageType& _outData) michael@0: { } michael@0: }; michael@0: template < > michael@0: struct variant_storage_traits michael@0: { michael@0: typedef std::pair ConstructorType; michael@0: typedef std::pair StorageType; michael@0: static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData) michael@0: { michael@0: *_outData = aBlob; michael@0: } michael@0: static inline void destroy(StorageType &aData) michael@0: { michael@0: if (aData.first) { michael@0: NS_Free(aData.first); michael@0: aData.first = nullptr; michael@0: } michael@0: } michael@0: }; michael@0: template < > michael@0: struct variant_blob_traits michael@0: { michael@0: static inline nsresult asArray(FallibleTArray &aData, michael@0: uint16_t *_type, michael@0: uint32_t *_size, michael@0: void **_result) michael@0: { michael@0: // For empty blobs, we return nullptr. michael@0: if (aData.Length() == 0) { michael@0: *_result = nullptr; michael@0: *_type = nsIDataType::VTYPE_UINT8; michael@0: *_size = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Otherwise, we copy the array. michael@0: *_result = nsMemory::Clone(aData.Elements(), aData.Length() * sizeof(uint8_t)); michael@0: NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: // Set type and size michael@0: *_type = nsIDataType::VTYPE_UINT8; michael@0: *_size = aData.Length(); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: template < > michael@0: struct variant_blob_traits michael@0: { michael@0: static inline nsresult asArray(std::pair &aData, michael@0: uint16_t *_type, michael@0: uint32_t *_size, michael@0: void **_result) michael@0: { michael@0: // For empty blobs, we return nullptr. michael@0: if (aData.second == 0) { michael@0: *_result = nullptr; michael@0: *_type = nsIDataType::VTYPE_UINT8; michael@0: *_size = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Otherwise, transfer the data out. michael@0: *_result = aData.first; michael@0: aData.first = nullptr; michael@0: MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting! michael@0: michael@0: // Set type and size michael@0: *_type = nsIDataType::VTYPE_UINT8; michael@0: *_size = aData.second; michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * nullptr type michael@0: */ michael@0: michael@0: class NullVariant : public Variant_base michael@0: { michael@0: public: michael@0: NS_IMETHOD GetDataType(uint16_t *_type) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_type); michael@0: *_type = nsIDataType::VTYPE_EMPTY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHOD GetAsAUTF8String(nsACString &_str) michael@0: { michael@0: // Return a void string. michael@0: _str.Truncate(0); michael@0: _str.SetIsVoid(true); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHOD GetAsAString(nsAString &_str) michael@0: { michael@0: // Return a void string. michael@0: _str.Truncate(0); michael@0: _str.SetIsVoid(true); michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Template Implementation michael@0: michael@0: template michael@0: class Variant : public Variant_base michael@0: { michael@0: ~Variant() michael@0: { michael@0: variant_storage_traits::destroy(mData); michael@0: } michael@0: michael@0: public: michael@0: Variant(const typename variant_storage_traits::ConstructorType aData) michael@0: { michael@0: variant_storage_traits::storage_conversion(aData, &mData); michael@0: } michael@0: michael@0: NS_IMETHOD GetDataType(uint16_t *_type) michael@0: { michael@0: *_type = variant_traits::type(); michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHOD GetAsInt32(int32_t *_integer) michael@0: { michael@0: return variant_integer_traits::asInt32(mData, _integer); michael@0: } michael@0: michael@0: NS_IMETHOD GetAsInt64(int64_t *_integer) michael@0: { michael@0: return variant_integer_traits::asInt64(mData, _integer); michael@0: } michael@0: michael@0: NS_IMETHOD GetAsDouble(double *_double) michael@0: { michael@0: return variant_float_traits::asDouble(mData, _double); michael@0: } michael@0: michael@0: NS_IMETHOD GetAsAUTF8String(nsACString &_str) michael@0: { michael@0: return variant_text_traits::asUTF8String(mData, _str); michael@0: } michael@0: michael@0: NS_IMETHOD GetAsAString(nsAString &_str) michael@0: { michael@0: return variant_text_traits::asString(mData, _str); michael@0: } michael@0: michael@0: NS_IMETHOD GetAsArray(uint16_t *_type, michael@0: nsIID *, michael@0: uint32_t *_size, michael@0: void **_data) michael@0: { michael@0: return variant_blob_traits::asArray(mData, _type, _size, _data); michael@0: } michael@0: michael@0: private: michael@0: typename variant_storage_traits::StorageType mData; michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Handy typedefs! Use these for the right mapping. michael@0: michael@0: typedef Variant IntegerVariant; michael@0: typedef Variant FloatVariant; michael@0: typedef Variant TextVariant; michael@0: typedef Variant UTF8TextVariant; michael@0: typedef Variant BlobVariant; michael@0: typedef Variant AdoptedBlobVariant; michael@0: michael@0: } // namespace storage michael@0: } // namespace mozilla michael@0: michael@0: #include "Variant_inl.h" michael@0: michael@0: #endif // mozilla_storage_Variant_h__