|
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/. */ |
|
6 |
|
7 #ifndef mozilla_storage_Variant_h__ |
|
8 #define mozilla_storage_Variant_h__ |
|
9 |
|
10 #include <utility> |
|
11 |
|
12 #include "nsIVariant.h" |
|
13 #include "nsString.h" |
|
14 #include "nsTArray.h" |
|
15 |
|
16 /** |
|
17 * This class is used by the storage module whenever an nsIVariant needs to be |
|
18 * returned. We provide traits for the basic sqlite types to make use easier. |
|
19 * The following types map to the indicated sqlite type: |
|
20 * int64_t -> INTEGER (use IntegerVariant) |
|
21 * double -> FLOAT (use FloatVariant) |
|
22 * nsString -> TEXT (use TextVariant) |
|
23 * nsCString -> TEXT (use UTF8TextVariant) |
|
24 * uint8_t[] -> BLOB (use BlobVariant) |
|
25 * nullptr -> NULL (use NullVariant) |
|
26 */ |
|
27 |
|
28 namespace mozilla { |
|
29 namespace storage { |
|
30 |
|
31 //////////////////////////////////////////////////////////////////////////////// |
|
32 //// Base Class |
|
33 |
|
34 class Variant_base : public nsIVariant |
|
35 { |
|
36 public: |
|
37 NS_DECL_THREADSAFE_ISUPPORTS |
|
38 NS_DECL_NSIVARIANT |
|
39 |
|
40 protected: |
|
41 virtual ~Variant_base() { } |
|
42 }; |
|
43 |
|
44 //////////////////////////////////////////////////////////////////////////////// |
|
45 //// Traits |
|
46 |
|
47 /** |
|
48 * Generics |
|
49 */ |
|
50 |
|
51 template <typename DataType> |
|
52 struct variant_traits |
|
53 { |
|
54 static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; } |
|
55 }; |
|
56 |
|
57 template <typename DataType, bool Adopting=false> |
|
58 struct variant_storage_traits |
|
59 { |
|
60 typedef DataType ConstructorType; |
|
61 typedef DataType StorageType; |
|
62 static inline void storage_conversion(const ConstructorType aData, StorageType* _storage) |
|
63 { |
|
64 *_storage = aData; |
|
65 } |
|
66 |
|
67 static inline void destroy(const StorageType& _storage) |
|
68 { } |
|
69 }; |
|
70 |
|
71 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA; |
|
72 |
|
73 template <typename DataType, bool Adopting=false> |
|
74 struct variant_integer_traits |
|
75 { |
|
76 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; |
|
77 static inline nsresult asInt32(const StorageType &, int32_t *) { NO_CONVERSION } |
|
78 static inline nsresult asInt64(const StorageType &, int64_t *) { NO_CONVERSION } |
|
79 }; |
|
80 |
|
81 template <typename DataType, bool Adopting=false> |
|
82 struct variant_float_traits |
|
83 { |
|
84 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; |
|
85 static inline nsresult asDouble(const StorageType &, double *) { NO_CONVERSION } |
|
86 }; |
|
87 |
|
88 template <typename DataType, bool Adopting=false> |
|
89 struct variant_text_traits |
|
90 { |
|
91 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; |
|
92 static inline nsresult asUTF8String(const StorageType &, nsACString &) { NO_CONVERSION } |
|
93 static inline nsresult asString(const StorageType &, nsAString &) { NO_CONVERSION } |
|
94 }; |
|
95 |
|
96 template <typename DataType, bool Adopting=false> |
|
97 struct variant_blob_traits |
|
98 { |
|
99 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; |
|
100 static inline nsresult asArray(const StorageType &, uint16_t *, uint32_t *, void **) |
|
101 { NO_CONVERSION } |
|
102 }; |
|
103 |
|
104 #undef NO_CONVERSION |
|
105 |
|
106 /** |
|
107 * INTEGER types |
|
108 */ |
|
109 |
|
110 template < > |
|
111 struct variant_traits<int64_t> |
|
112 { |
|
113 static inline uint16_t type() { return nsIDataType::VTYPE_INT64; } |
|
114 }; |
|
115 template < > |
|
116 struct variant_integer_traits<int64_t> |
|
117 { |
|
118 static inline nsresult asInt32(int64_t aValue, |
|
119 int32_t *_result) |
|
120 { |
|
121 if (aValue > INT32_MAX || aValue < INT32_MIN) |
|
122 return NS_ERROR_CANNOT_CONVERT_DATA; |
|
123 |
|
124 *_result = static_cast<int32_t>(aValue); |
|
125 return NS_OK; |
|
126 } |
|
127 static inline nsresult asInt64(int64_t aValue, |
|
128 int64_t *_result) |
|
129 { |
|
130 *_result = aValue; |
|
131 return NS_OK; |
|
132 } |
|
133 }; |
|
134 // xpcvariant just calls get double for integers... |
|
135 template < > |
|
136 struct variant_float_traits<int64_t> |
|
137 { |
|
138 static inline nsresult asDouble(int64_t aValue, |
|
139 double *_result) |
|
140 { |
|
141 *_result = double(aValue); |
|
142 return NS_OK; |
|
143 } |
|
144 }; |
|
145 |
|
146 /** |
|
147 * FLOAT types |
|
148 */ |
|
149 |
|
150 template < > |
|
151 struct variant_traits<double> |
|
152 { |
|
153 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; } |
|
154 }; |
|
155 template < > |
|
156 struct variant_float_traits<double> |
|
157 { |
|
158 static inline nsresult asDouble(double aValue, |
|
159 double *_result) |
|
160 { |
|
161 *_result = aValue; |
|
162 return NS_OK; |
|
163 } |
|
164 }; |
|
165 |
|
166 /** |
|
167 * TEXT types |
|
168 */ |
|
169 |
|
170 template < > |
|
171 struct variant_traits<nsString> |
|
172 { |
|
173 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; } |
|
174 }; |
|
175 template < > |
|
176 struct variant_storage_traits<nsString> |
|
177 { |
|
178 typedef const nsAString & ConstructorType; |
|
179 typedef nsString StorageType; |
|
180 static inline void storage_conversion(ConstructorType aText, StorageType* _outData) |
|
181 { |
|
182 *_outData = aText; |
|
183 } |
|
184 static inline void destroy(const StorageType& _outData) |
|
185 { } |
|
186 }; |
|
187 template < > |
|
188 struct variant_text_traits<nsString> |
|
189 { |
|
190 static inline nsresult asUTF8String(const nsString &aValue, |
|
191 nsACString &_result) |
|
192 { |
|
193 CopyUTF16toUTF8(aValue, _result); |
|
194 return NS_OK; |
|
195 } |
|
196 static inline nsresult asString(const nsString &aValue, |
|
197 nsAString &_result) |
|
198 { |
|
199 _result = aValue; |
|
200 return NS_OK; |
|
201 } |
|
202 }; |
|
203 |
|
204 template < > |
|
205 struct variant_traits<nsCString> |
|
206 { |
|
207 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; } |
|
208 }; |
|
209 template < > |
|
210 struct variant_storage_traits<nsCString> |
|
211 { |
|
212 typedef const nsACString & ConstructorType; |
|
213 typedef nsCString StorageType; |
|
214 static inline void storage_conversion(ConstructorType aText, StorageType* _outData) |
|
215 { |
|
216 *_outData = aText; |
|
217 } |
|
218 static inline void destroy(const StorageType &aData) |
|
219 { } |
|
220 }; |
|
221 template < > |
|
222 struct variant_text_traits<nsCString> |
|
223 { |
|
224 static inline nsresult asUTF8String(const nsCString &aValue, |
|
225 nsACString &_result) |
|
226 { |
|
227 _result = aValue; |
|
228 return NS_OK; |
|
229 } |
|
230 static inline nsresult asString(const nsCString &aValue, |
|
231 nsAString &_result) |
|
232 { |
|
233 CopyUTF8toUTF16(aValue, _result); |
|
234 return NS_OK; |
|
235 } |
|
236 }; |
|
237 |
|
238 /** |
|
239 * BLOB types |
|
240 */ |
|
241 |
|
242 template < > |
|
243 struct variant_traits<uint8_t[]> |
|
244 { |
|
245 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; } |
|
246 }; |
|
247 template < > |
|
248 struct variant_storage_traits<uint8_t[], false> |
|
249 { |
|
250 typedef std::pair<const void *, int> ConstructorType; |
|
251 typedef FallibleTArray<uint8_t> StorageType; |
|
252 static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData) |
|
253 { |
|
254 _outData->Clear(); |
|
255 _outData->SetCapacity(aBlob.second); |
|
256 (void)_outData->AppendElements(static_cast<const uint8_t *>(aBlob.first), |
|
257 aBlob.second); |
|
258 } |
|
259 static inline void destroy(const StorageType& _outData) |
|
260 { } |
|
261 }; |
|
262 template < > |
|
263 struct variant_storage_traits<uint8_t[], true> |
|
264 { |
|
265 typedef std::pair<uint8_t *, int> ConstructorType; |
|
266 typedef std::pair<uint8_t *, int> StorageType; |
|
267 static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData) |
|
268 { |
|
269 *_outData = aBlob; |
|
270 } |
|
271 static inline void destroy(StorageType &aData) |
|
272 { |
|
273 if (aData.first) { |
|
274 NS_Free(aData.first); |
|
275 aData.first = nullptr; |
|
276 } |
|
277 } |
|
278 }; |
|
279 template < > |
|
280 struct variant_blob_traits<uint8_t[], false> |
|
281 { |
|
282 static inline nsresult asArray(FallibleTArray<uint8_t> &aData, |
|
283 uint16_t *_type, |
|
284 uint32_t *_size, |
|
285 void **_result) |
|
286 { |
|
287 // For empty blobs, we return nullptr. |
|
288 if (aData.Length() == 0) { |
|
289 *_result = nullptr; |
|
290 *_type = nsIDataType::VTYPE_UINT8; |
|
291 *_size = 0; |
|
292 return NS_OK; |
|
293 } |
|
294 |
|
295 // Otherwise, we copy the array. |
|
296 *_result = nsMemory::Clone(aData.Elements(), aData.Length() * sizeof(uint8_t)); |
|
297 NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY); |
|
298 |
|
299 // Set type and size |
|
300 *_type = nsIDataType::VTYPE_UINT8; |
|
301 *_size = aData.Length(); |
|
302 return NS_OK; |
|
303 } |
|
304 }; |
|
305 |
|
306 template < > |
|
307 struct variant_blob_traits<uint8_t[], true> |
|
308 { |
|
309 static inline nsresult asArray(std::pair<uint8_t *, int> &aData, |
|
310 uint16_t *_type, |
|
311 uint32_t *_size, |
|
312 void **_result) |
|
313 { |
|
314 // For empty blobs, we return nullptr. |
|
315 if (aData.second == 0) { |
|
316 *_result = nullptr; |
|
317 *_type = nsIDataType::VTYPE_UINT8; |
|
318 *_size = 0; |
|
319 return NS_OK; |
|
320 } |
|
321 |
|
322 // Otherwise, transfer the data out. |
|
323 *_result = aData.first; |
|
324 aData.first = nullptr; |
|
325 MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting! |
|
326 |
|
327 // Set type and size |
|
328 *_type = nsIDataType::VTYPE_UINT8; |
|
329 *_size = aData.second; |
|
330 return NS_OK; |
|
331 } |
|
332 }; |
|
333 |
|
334 /** |
|
335 * nullptr type |
|
336 */ |
|
337 |
|
338 class NullVariant : public Variant_base |
|
339 { |
|
340 public: |
|
341 NS_IMETHOD GetDataType(uint16_t *_type) |
|
342 { |
|
343 NS_ENSURE_ARG_POINTER(_type); |
|
344 *_type = nsIDataType::VTYPE_EMPTY; |
|
345 return NS_OK; |
|
346 } |
|
347 |
|
348 NS_IMETHOD GetAsAUTF8String(nsACString &_str) |
|
349 { |
|
350 // Return a void string. |
|
351 _str.Truncate(0); |
|
352 _str.SetIsVoid(true); |
|
353 return NS_OK; |
|
354 } |
|
355 |
|
356 NS_IMETHOD GetAsAString(nsAString &_str) |
|
357 { |
|
358 // Return a void string. |
|
359 _str.Truncate(0); |
|
360 _str.SetIsVoid(true); |
|
361 return NS_OK; |
|
362 } |
|
363 }; |
|
364 |
|
365 //////////////////////////////////////////////////////////////////////////////// |
|
366 //// Template Implementation |
|
367 |
|
368 template <typename DataType, bool Adopting=false> |
|
369 class Variant : public Variant_base |
|
370 { |
|
371 ~Variant() |
|
372 { |
|
373 variant_storage_traits<DataType, Adopting>::destroy(mData); |
|
374 } |
|
375 |
|
376 public: |
|
377 Variant(const typename variant_storage_traits<DataType, Adopting>::ConstructorType aData) |
|
378 { |
|
379 variant_storage_traits<DataType, Adopting>::storage_conversion(aData, &mData); |
|
380 } |
|
381 |
|
382 NS_IMETHOD GetDataType(uint16_t *_type) |
|
383 { |
|
384 *_type = variant_traits<DataType>::type(); |
|
385 return NS_OK; |
|
386 } |
|
387 NS_IMETHOD GetAsInt32(int32_t *_integer) |
|
388 { |
|
389 return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer); |
|
390 } |
|
391 |
|
392 NS_IMETHOD GetAsInt64(int64_t *_integer) |
|
393 { |
|
394 return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer); |
|
395 } |
|
396 |
|
397 NS_IMETHOD GetAsDouble(double *_double) |
|
398 { |
|
399 return variant_float_traits<DataType, Adopting>::asDouble(mData, _double); |
|
400 } |
|
401 |
|
402 NS_IMETHOD GetAsAUTF8String(nsACString &_str) |
|
403 { |
|
404 return variant_text_traits<DataType, Adopting>::asUTF8String(mData, _str); |
|
405 } |
|
406 |
|
407 NS_IMETHOD GetAsAString(nsAString &_str) |
|
408 { |
|
409 return variant_text_traits<DataType, Adopting>::asString(mData, _str); |
|
410 } |
|
411 |
|
412 NS_IMETHOD GetAsArray(uint16_t *_type, |
|
413 nsIID *, |
|
414 uint32_t *_size, |
|
415 void **_data) |
|
416 { |
|
417 return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size, _data); |
|
418 } |
|
419 |
|
420 private: |
|
421 typename variant_storage_traits<DataType, Adopting>::StorageType mData; |
|
422 }; |
|
423 |
|
424 //////////////////////////////////////////////////////////////////////////////// |
|
425 //// Handy typedefs! Use these for the right mapping. |
|
426 |
|
427 typedef Variant<int64_t> IntegerVariant; |
|
428 typedef Variant<double> FloatVariant; |
|
429 typedef Variant<nsString> TextVariant; |
|
430 typedef Variant<nsCString> UTF8TextVariant; |
|
431 typedef Variant<uint8_t[], false> BlobVariant; |
|
432 typedef Variant<uint8_t[], true> AdoptedBlobVariant; |
|
433 |
|
434 } // namespace storage |
|
435 } // namespace mozilla |
|
436 |
|
437 #include "Variant_inl.h" |
|
438 |
|
439 #endif // mozilla_storage_Variant_h__ |