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 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Corporation
20 : * Portions created by the Initial Developer are Copyright (C) 2008
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Shawn Wilsher <me@shawnwilsher.com> (Original Author)
25 : * Drew Willcoxon <adw@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef mozilla_storage_Variant_h__
42 : #define mozilla_storage_Variant_h__
43 :
44 : #include <utility>
45 :
46 : #include "nsIVariant.h"
47 : #include "nsString.h"
48 : #include "nsTArray.h"
49 :
50 : /**
51 : * This class is used by the storage module whenever an nsIVariant needs to be
52 : * returned. We provide traits for the basic sqlite types to make use easier.
53 : * The following types map to the indicated sqlite type:
54 : * PRInt64 -> INTEGER (use IntegerVariant)
55 : * double -> FLOAT (use FloatVariant)
56 : * nsString -> TEXT (use TextVariant)
57 : * nsCString -> TEXT (use UTF8TextVariant)
58 : * PRUint8[] -> BLOB (use BlobVariant)
59 : * nsnull -> NULL (use NullVariant)
60 : */
61 :
62 : namespace mozilla {
63 : namespace storage {
64 :
65 : ////////////////////////////////////////////////////////////////////////////////
66 : //// Base Class
67 :
68 : class Variant_base : public nsIVariant
69 718341 : {
70 : public:
71 : NS_DECL_ISUPPORTS
72 : NS_DECL_NSIVARIANT
73 :
74 : protected:
75 1436682 : virtual ~Variant_base() { }
76 : };
77 :
78 : ////////////////////////////////////////////////////////////////////////////////
79 : //// Traits
80 :
81 : /**
82 : * Generics
83 : */
84 :
85 : template <typename DataType>
86 : struct variant_traits
87 : {
88 : static inline PRUint16 type() { return nsIDataType::VTYPE_EMPTY; }
89 : };
90 :
91 : template <typename DataType>
92 : struct variant_storage_traits
93 : {
94 : typedef DataType ConstructorType;
95 : typedef DataType StorageType;
96 0 : static inline StorageType storage_conversion(ConstructorType aData) { return aData; }
97 : };
98 :
99 : #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
100 :
101 : template <typename DataType>
102 : struct variant_integer_traits
103 : {
104 : typedef typename variant_storage_traits<DataType>::StorageType StorageType;
105 0 : static inline nsresult asInt32(StorageType, PRInt32 *) { NO_CONVERSION }
106 0 : static inline nsresult asInt64(StorageType, PRInt64 *) { NO_CONVERSION }
107 : };
108 :
109 : template <typename DataType>
110 : struct variant_float_traits
111 : {
112 : typedef typename variant_storage_traits<DataType>::StorageType StorageType;
113 0 : static inline nsresult asDouble(StorageType, double *) { NO_CONVERSION }
114 : };
115 :
116 : template <typename DataType>
117 : struct variant_text_traits
118 : {
119 : typedef typename variant_storage_traits<DataType>::StorageType StorageType;
120 0 : static inline nsresult asUTF8String(StorageType, nsACString &) { NO_CONVERSION }
121 0 : static inline nsresult asString(StorageType, nsAString &) { NO_CONVERSION }
122 : };
123 :
124 : template <typename DataType>
125 : struct variant_blob_traits
126 : {
127 : typedef typename variant_storage_traits<DataType>::StorageType StorageType;
128 0 : static inline nsresult asArray(StorageType, PRUint16 *, PRUint32 *, void **)
129 0 : { NO_CONVERSION }
130 : };
131 :
132 : #undef NO_CONVERSION
133 :
134 : /**
135 : * INTEGER types
136 : */
137 :
138 : template < >
139 : struct variant_traits<PRInt64>
140 : {
141 0 : static inline PRUint16 type() { return nsIDataType::VTYPE_INT64; }
142 : };
143 : template < >
144 : struct variant_integer_traits<PRInt64>
145 : {
146 0 : static inline nsresult asInt32(PRInt64 aValue,
147 : PRInt32 *_result)
148 : {
149 0 : if (aValue > PR_INT32_MAX || aValue < PR_INT32_MIN)
150 0 : return NS_ERROR_CANNOT_CONVERT_DATA;
151 :
152 0 : *_result = static_cast<PRInt32>(aValue);
153 0 : return NS_OK;
154 : }
155 0 : static inline nsresult asInt64(PRInt64 aValue,
156 : PRInt64 *_result)
157 : {
158 0 : *_result = aValue;
159 0 : return NS_OK;
160 : }
161 : };
162 : // xpcvariant just calls get double for integers...
163 : template < >
164 : struct variant_float_traits<PRInt64>
165 : {
166 0 : static inline nsresult asDouble(PRInt64 aValue,
167 : double *_result)
168 : {
169 0 : *_result = double(aValue);
170 0 : return NS_OK;
171 : }
172 : };
173 :
174 : /**
175 : * FLOAT types
176 : */
177 :
178 : template < >
179 : struct variant_traits<double>
180 : {
181 : static inline PRUint16 type() { return nsIDataType::VTYPE_DOUBLE; }
182 : };
183 : template < >
184 : struct variant_float_traits<double>
185 : {
186 : static inline nsresult asDouble(double aValue,
187 : double *_result)
188 : {
189 : *_result = aValue;
190 : return NS_OK;
191 : }
192 : };
193 :
194 : /**
195 : * TEXT types
196 : */
197 :
198 : template < >
199 : struct variant_traits<nsString>
200 : {
201 : static inline PRUint16 type() { return nsIDataType::VTYPE_ASTRING; }
202 : };
203 : template < >
204 : struct variant_storage_traits<nsString>
205 : {
206 : typedef const nsAString & ConstructorType;
207 : typedef nsString StorageType;
208 : static inline StorageType storage_conversion(ConstructorType aText)
209 : {
210 : return StorageType(aText);
211 : }
212 : };
213 : template < >
214 : struct variant_text_traits<nsString>
215 : {
216 : static inline nsresult asUTF8String(const nsString &aValue,
217 : nsACString &_result)
218 : {
219 : CopyUTF16toUTF8(aValue, _result);
220 : return NS_OK;
221 : }
222 : static inline nsresult asString(const nsString &aValue,
223 : nsAString &_result)
224 : {
225 : _result = aValue;
226 : return NS_OK;
227 : }
228 : };
229 :
230 : template < >
231 : struct variant_traits<nsCString>
232 : {
233 0 : static inline PRUint16 type() { return nsIDataType::VTYPE_UTF8STRING; }
234 : };
235 : template < >
236 : struct variant_storage_traits<nsCString>
237 : {
238 : typedef const nsACString & ConstructorType;
239 : typedef nsCString StorageType;
240 0 : static inline StorageType storage_conversion(ConstructorType aText)
241 : {
242 0 : return StorageType(aText);
243 : }
244 : };
245 : template < >
246 : struct variant_text_traits<nsCString>
247 : {
248 0 : static inline nsresult asUTF8String(const nsCString &aValue,
249 : nsACString &_result)
250 : {
251 0 : _result = aValue;
252 0 : return NS_OK;
253 : }
254 0 : static inline nsresult asString(const nsCString &aValue,
255 : nsAString &_result)
256 : {
257 0 : CopyUTF8toUTF16(aValue, _result);
258 0 : return NS_OK;
259 : }
260 : };
261 :
262 : /**
263 : * BLOB types
264 : */
265 :
266 : template < >
267 : struct variant_traits<PRUint8[]>
268 : {
269 8052 : static inline PRUint16 type() { return nsIDataType::VTYPE_ARRAY; }
270 : };
271 : template < >
272 : struct variant_storage_traits<PRUint8[]>
273 : {
274 : typedef std::pair<const void *, int> ConstructorType;
275 : typedef FallibleTArray<PRUint8> StorageType;
276 8075 : static inline StorageType storage_conversion(ConstructorType aBlob)
277 : {
278 8075 : StorageType data(aBlob.second);
279 : (void)data.AppendElements(static_cast<const PRUint8 *>(aBlob.first),
280 8075 : aBlob.second);
281 : return data;
282 : }
283 : };
284 : template < >
285 : struct variant_blob_traits<PRUint8[]>
286 : {
287 8051 : static inline nsresult asArray(FallibleTArray<PRUint8> &aData,
288 : PRUint16 *_type,
289 : PRUint32 *_size,
290 : void **_result)
291 : {
292 : // For empty blobs, we return nsnull.
293 8051 : if (aData.Length() == 0) {
294 29 : *_result = nsnull;
295 29 : *_type = nsIDataType::VTYPE_UINT8;
296 29 : *_size = 0;
297 29 : return NS_OK;
298 : }
299 :
300 : // Otherwise, we copy the array.
301 8022 : *_result = nsMemory::Clone(aData.Elements(), aData.Length() * sizeof(PRUint8));
302 8022 : NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
303 :
304 : // Set type and size
305 8022 : *_type = nsIDataType::VTYPE_UINT8;
306 8022 : *_size = aData.Length();
307 8022 : return NS_OK;
308 : }
309 : };
310 :
311 : /**
312 : * NULL type
313 : */
314 :
315 : class NullVariant : public Variant_base
316 : {
317 : public:
318 : NS_IMETHOD GetDataType(PRUint16 *_type)
319 : {
320 : NS_ENSURE_ARG_POINTER(_type);
321 : *_type = nsIDataType::VTYPE_EMPTY;
322 : return NS_OK;
323 : }
324 :
325 : NS_IMETHOD GetAsAUTF8String(nsACString &_str)
326 : {
327 : // Return a void string.
328 : _str.Truncate(0);
329 : _str.SetIsVoid(true);
330 : return NS_OK;
331 : }
332 :
333 : NS_IMETHOD GetAsAString(nsAString &_str)
334 : {
335 : // Return a void string.
336 : _str.Truncate(0);
337 : _str.SetIsVoid(true);
338 : return NS_OK;
339 : }
340 : };
341 :
342 : ////////////////////////////////////////////////////////////////////////////////
343 : //// Template Implementation
344 :
345 : template <typename DataType>
346 : class Variant : public Variant_base
347 32300 : {
348 : public:
349 8075 : Variant(typename variant_storage_traits<DataType>::ConstructorType aData)
350 8075 : : mData(variant_storage_traits<DataType>::storage_conversion(aData))
351 : {
352 8075 : }
353 :
354 8052 : NS_IMETHOD GetDataType(PRUint16 *_type)
355 : {
356 8052 : *_type = variant_traits<DataType>::type();
357 8052 : return NS_OK;
358 : }
359 0 : NS_IMETHOD GetAsInt32(PRInt32 *_integer)
360 : {
361 0 : return variant_integer_traits<DataType>::asInt32(mData, _integer);
362 : }
363 :
364 0 : NS_IMETHOD GetAsInt64(PRInt64 *_integer)
365 : {
366 0 : return variant_integer_traits<DataType>::asInt64(mData, _integer);
367 : }
368 :
369 0 : NS_IMETHOD GetAsDouble(double *_double)
370 : {
371 0 : return variant_float_traits<DataType>::asDouble(mData, _double);
372 : }
373 :
374 0 : NS_IMETHOD GetAsAUTF8String(nsACString &_str)
375 : {
376 0 : return variant_text_traits<DataType>::asUTF8String(mData, _str);
377 : }
378 :
379 0 : NS_IMETHOD GetAsAString(nsAString &_str)
380 : {
381 0 : return variant_text_traits<DataType>::asString(mData, _str);
382 : }
383 :
384 8051 : NS_IMETHOD GetAsArray(PRUint16 *_type,
385 : nsIID *,
386 : PRUint32 *_size,
387 : void **_data)
388 : {
389 8051 : return variant_blob_traits<DataType>::asArray(mData, _type, _size, _data);
390 : }
391 :
392 : private:
393 : typename variant_storage_traits<DataType>::StorageType mData;
394 : };
395 :
396 : ////////////////////////////////////////////////////////////////////////////////
397 : //// Handy typedefs! Use these for the right mapping.
398 :
399 : typedef Variant<PRInt64> IntegerVariant;
400 : typedef Variant<double> FloatVariant;
401 : typedef Variant<nsString> TextVariant;
402 : typedef Variant<nsCString> UTF8TextVariant;
403 : typedef Variant<PRUint8[]> BlobVariant;
404 :
405 : } // namespace storage
406 : } // namespace mozilla
407 :
408 : #include "Variant_inl.h"
409 :
410 : #endif // mozilla_storage_Variant_h__
|