Bug 1472338: part 2) Change `clipboard.readText()` to read from the clipboard asynchr...
[gecko.git] / dom / indexedDB / Key.h
blob21c819e904ddd29111bbc0dd84ae337c0bc28da3
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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_dom_indexeddb_key_h__
8 #define mozilla_dom_indexeddb_key_h__
10 #include "mozilla/dom/indexedDB/IDBResult.h"
12 #include "js/RootingAPI.h"
13 #include "js/TypeDecls.h"
14 #include "nsString.h"
16 class mozIStorageStatement;
17 class mozIStorageValueArray;
19 namespace IPC {
21 template <typename>
22 struct ParamTraits;
24 } // namespace IPC
26 namespace mozilla {
27 namespace dom {
28 namespace indexedDB {
30 class Key {
31 friend struct IPC::ParamTraits<Key>;
33 nsCString mBuffer;
35 public:
36 enum {
37 eTerminator = 0,
38 eFloat = 0x10,
39 eDate = 0x20,
40 eString = 0x30,
41 eBinary = 0x40,
42 eArray = 0x50,
43 eMaxType = eArray
46 static const uint8_t kMaxArrayCollapse = uint8_t(3);
47 static const uint8_t kMaxRecursionDepth = uint8_t(64);
49 Key() { Unset(); }
51 explicit Key(nsCString aBuffer) : mBuffer(std::move(aBuffer)) {}
53 Key& operator=(int64_t aInt) {
54 SetFromInteger(aInt);
55 return *this;
58 bool operator==(const Key& aOther) const {
59 MOZ_ASSERT(!mBuffer.IsVoid());
60 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
62 return mBuffer.Equals(aOther.mBuffer);
65 bool operator!=(const Key& aOther) const {
66 MOZ_ASSERT(!mBuffer.IsVoid());
67 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
69 return !mBuffer.Equals(aOther.mBuffer);
72 bool operator<(const Key& aOther) const {
73 MOZ_ASSERT(!mBuffer.IsVoid());
74 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
76 return Compare(mBuffer, aOther.mBuffer) < 0;
79 bool operator>(const Key& aOther) const {
80 MOZ_ASSERT(!mBuffer.IsVoid());
81 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
83 return Compare(mBuffer, aOther.mBuffer) > 0;
86 bool operator<=(const Key& aOther) const {
87 MOZ_ASSERT(!mBuffer.IsVoid());
88 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
90 return Compare(mBuffer, aOther.mBuffer) <= 0;
93 bool operator>=(const Key& aOther) const {
94 MOZ_ASSERT(!mBuffer.IsVoid());
95 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
97 return Compare(mBuffer, aOther.mBuffer) >= 0;
100 void Unset() { mBuffer.SetIsVoid(true); }
102 bool IsUnset() const { return mBuffer.IsVoid(); }
104 bool IsFloat() const { return !IsUnset() && *BufferStart() == eFloat; }
106 bool IsDate() const { return !IsUnset() && *BufferStart() == eDate; }
108 bool IsString() const { return !IsUnset() && *BufferStart() == eString; }
110 bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary; }
112 bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray; }
114 double ToFloat() const {
115 MOZ_ASSERT(IsFloat());
116 const EncodedDataType* pos = BufferStart();
117 double res = DecodeNumber(pos, BufferEnd());
118 MOZ_ASSERT(pos >= BufferEnd());
119 return res;
122 double ToDateMsec() const {
123 MOZ_ASSERT(IsDate());
124 const EncodedDataType* pos = BufferStart();
125 double res = DecodeNumber(pos, BufferEnd());
126 MOZ_ASSERT(pos >= BufferEnd());
127 return res;
130 nsAutoString ToString() const {
131 MOZ_ASSERT(IsString());
132 const EncodedDataType* pos = BufferStart();
133 auto res = DecodeString(pos, BufferEnd());
134 MOZ_ASSERT(pos >= BufferEnd());
135 return res;
138 Result<Ok, nsresult> SetFromString(const nsAString& aString);
140 void SetFromInteger(int64_t aInt) {
141 mBuffer.Truncate();
142 EncodeNumber(double(aInt), eFloat);
143 TrimBuffer();
146 // This function implements the standard algorithm "convert a value to a key".
147 // A key return value is indicated by returning `true` whereas `false` means
148 // either invalid (if `aRv.Failed()` is `false`) or an exception (otherwise).
149 IDBResult<Ok, IDBSpecialValue::Invalid> SetFromJSVal(
150 JSContext* aCx, JS::Handle<JS::Value> aVal);
152 nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const;
154 nsresult ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const;
156 // See SetFromJSVal() for the meaning of values returned by this function.
157 IDBResult<Ok, IDBSpecialValue::Invalid> AppendItem(
158 JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
160 Result<Key, nsresult> ToLocaleAwareKey(const nsCString& aLocale) const;
162 void FinishArray() { TrimBuffer(); }
164 const nsCString& GetBuffer() const { return mBuffer; }
166 nsresult BindToStatement(mozIStorageStatement* aStatement,
167 const nsACString& aParamName) const;
169 nsresult SetFromStatement(mozIStorageStatement* aStatement, uint32_t aIndex);
171 nsresult SetFromValueArray(mozIStorageValueArray* aValues, uint32_t aIndex);
173 static int16_t CompareKeys(const Key& aFirst, const Key& aSecond) {
174 int32_t result = Compare(aFirst.mBuffer, aSecond.mBuffer);
176 if (result < 0) {
177 return -1;
180 if (result > 0) {
181 return 1;
184 return 0;
187 private:
188 class MOZ_STACK_CLASS ArrayValueEncoder;
190 using EncodedDataType = unsigned char;
192 const EncodedDataType* BufferStart() const {
193 // TODO it would be nicer if mBuffer was also using EncodedDataType
194 return reinterpret_cast<const EncodedDataType*>(mBuffer.BeginReading());
197 const EncodedDataType* BufferEnd() const {
198 return reinterpret_cast<const EncodedDataType*>(mBuffer.EndReading());
201 // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
202 // step.
203 void TrimBuffer() {
204 const char* end = mBuffer.EndReading() - 1;
205 while (!*end) {
206 --end;
209 mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
212 // Encoding functions. These append the encoded value to the end of mBuffer
213 IDBResult<Ok, IDBSpecialValue::Invalid> EncodeJSVal(
214 JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset);
216 Result<Ok, nsresult> EncodeString(const nsAString& aString,
217 uint8_t aTypeOffset);
219 template <typename T>
220 Result<Ok, nsresult> EncodeString(Span<const T> aInput, uint8_t aTypeOffset);
222 template <typename T>
223 Result<Ok, nsresult> EncodeAsString(Span<const T> aInput, uint8_t aType);
225 Result<Ok, nsresult> EncodeLocaleString(const nsAString& aString,
226 uint8_t aTypeOffset,
227 const nsCString& aLocale);
229 void EncodeNumber(double aFloat, uint8_t aType);
231 Result<Ok, nsresult> EncodeBinary(JSObject* aObject, bool aIsViewObject,
232 uint8_t aTypeOffset);
234 // Decoding functions. aPos points into mBuffer and is adjusted to point
235 // past the consumed value. (Note: this may be beyond aEnd).
236 static nsresult DecodeJSVal(const EncodedDataType*& aPos,
237 const EncodedDataType* aEnd, JSContext* aCx,
238 JS::MutableHandle<JS::Value> aVal);
240 static nsAutoString DecodeString(const EncodedDataType*& aPos,
241 const EncodedDataType* aEnd);
243 static double DecodeNumber(const EncodedDataType*& aPos,
244 const EncodedDataType* aEnd);
246 static JSObject* DecodeBinary(const EncodedDataType*& aPos,
247 const EncodedDataType* aEnd, JSContext* aCx);
249 // Returns the size of the decoded data for stringy (string or binary),
250 // excluding a null terminator.
251 // On return, aOutSectionEnd points to the last byte behind the current
252 // encoded section, i.e. either aEnd, or the eTerminator.
253 // T is the base type for the decoded data.
254 template <typename T>
255 static uint32_t CalcDecodedStringySize(
256 const EncodedDataType* aBegin, const EncodedDataType* aEnd,
257 const EncodedDataType** aOutEncodedSectionEnd);
259 static uint32_t LengthOfEncodedBinary(const EncodedDataType* aPos,
260 const EncodedDataType* aEnd);
262 template <typename T>
263 static void DecodeAsStringy(const EncodedDataType* aEncodedSectionBegin,
264 const EncodedDataType* aEncodedSectionEnd,
265 uint32_t aDecodedLength, T* aOut);
267 template <EncodedDataType TypeMask, typename T, typename AcquireBuffer,
268 typename AcquireEmpty>
269 static void DecodeStringy(const EncodedDataType*& aPos,
270 const EncodedDataType* aEnd,
271 const AcquireBuffer& acquireBuffer,
272 const AcquireEmpty& acquireEmpty);
274 IDBResult<Ok, IDBSpecialValue::Invalid> EncodeJSValInternal(
275 JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset,
276 uint16_t aRecursionDepth);
278 static nsresult DecodeJSValInternal(const EncodedDataType*& aPos,
279 const EncodedDataType* aEnd,
280 JSContext* aCx, uint8_t aTypeOffset,
281 JS::MutableHandle<JS::Value> aVal,
282 uint16_t aRecursionDepth);
284 template <typename T>
285 nsresult SetFromSource(T* aSource, uint32_t aIndex);
288 } // namespace indexedDB
289 } // namespace dom
290 } // namespace mozilla
292 #endif // mozilla_dom_indexeddb_key_h__