Bug 1831122 [wpt PR 39823] - Update wpt metadata, a=testonly
[gecko.git] / dom / indexedDB / Key.h
blobd19bc94e53368aeaa1bacff8c9e86a3b35660d8d
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 class mozIStorageStatement;
13 class mozIStorageValueArray;
15 namespace IPC {
17 template <typename>
18 struct ParamTraits;
20 } // namespace IPC
22 namespace mozilla::dom::indexedDB {
24 class Key {
25 friend struct IPC::ParamTraits<Key>;
27 nsCString mBuffer;
29 public:
30 enum {
31 eTerminator = 0,
32 eFloat = 0x10,
33 eDate = 0x20,
34 eString = 0x30,
35 eBinary = 0x40,
36 eArray = 0x50,
37 eMaxType = eArray
40 static const uint8_t kMaxArrayCollapse = uint8_t(3);
41 static const uint8_t kMaxRecursionDepth = uint8_t(64);
43 Key() { Unset(); }
45 explicit Key(nsCString aBuffer) : mBuffer(std::move(aBuffer)) {}
47 bool operator==(const Key& aOther) const {
48 MOZ_ASSERT(!mBuffer.IsVoid());
49 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
51 return mBuffer.Equals(aOther.mBuffer);
54 bool operator!=(const Key& aOther) const {
55 MOZ_ASSERT(!mBuffer.IsVoid());
56 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
58 return !mBuffer.Equals(aOther.mBuffer);
61 bool operator<(const Key& aOther) const {
62 MOZ_ASSERT(!mBuffer.IsVoid());
63 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
65 return Compare(mBuffer, aOther.mBuffer) < 0;
68 bool operator>(const Key& aOther) const {
69 MOZ_ASSERT(!mBuffer.IsVoid());
70 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
72 return Compare(mBuffer, aOther.mBuffer) > 0;
75 bool operator<=(const Key& aOther) const {
76 MOZ_ASSERT(!mBuffer.IsVoid());
77 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
79 return Compare(mBuffer, aOther.mBuffer) <= 0;
82 bool operator>=(const Key& aOther) const {
83 MOZ_ASSERT(!mBuffer.IsVoid());
84 MOZ_ASSERT(!aOther.mBuffer.IsVoid());
86 return Compare(mBuffer, aOther.mBuffer) >= 0;
89 void Unset() { mBuffer.SetIsVoid(true); }
91 bool IsUnset() const { return mBuffer.IsVoid(); }
93 bool IsFloat() const { return !IsUnset() && *BufferStart() == eFloat; }
95 bool IsDate() const { return !IsUnset() && *BufferStart() == eDate; }
97 bool IsString() const { return !IsUnset() && *BufferStart() == eString; }
99 bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary; }
101 bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray; }
103 double ToFloat() const {
104 MOZ_ASSERT(IsFloat());
105 const EncodedDataType* pos = BufferStart();
106 double res = DecodeNumber(pos, BufferEnd());
107 MOZ_ASSERT(pos >= BufferEnd());
108 return res;
111 double ToDateMsec() const {
112 MOZ_ASSERT(IsDate());
113 const EncodedDataType* pos = BufferStart();
114 double res = DecodeNumber(pos, BufferEnd());
115 MOZ_ASSERT(pos >= BufferEnd());
116 return res;
119 nsAutoString ToString() const {
120 MOZ_ASSERT(IsString());
121 const EncodedDataType* pos = BufferStart();
122 auto res = DecodeString(pos, BufferEnd());
123 MOZ_ASSERT(pos >= BufferEnd());
124 return res;
127 Result<Ok, nsresult> SetFromString(const nsAString& aString);
129 Result<Ok, nsresult> SetFromInteger(int64_t aInt) {
130 mBuffer.Truncate();
131 auto ret = EncodeNumber(double(aInt), eFloat);
132 TrimBuffer();
133 return ret;
136 // This function implements the standard algorithm "convert a value to a key".
137 // A key return value is indicated by returning `true` whereas `false` means
138 // either invalid (if `aRv.Failed()` is `false`) or an exception (otherwise).
139 IDBResult<Ok, IDBSpecialValue::Invalid> SetFromJSVal(
140 JSContext* aCx, JS::Handle<JS::Value> aVal);
142 nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const;
144 nsresult ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const;
146 // See SetFromJSVal() for the meaning of values returned by this function.
147 IDBResult<Ok, IDBSpecialValue::Invalid> AppendItem(
148 JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
150 Result<Key, nsresult> ToLocaleAwareKey(const nsCString& aLocale) const;
152 void FinishArray() { TrimBuffer(); }
154 const nsCString& GetBuffer() const { return mBuffer; }
156 nsresult BindToStatement(mozIStorageStatement* aStatement,
157 const nsACString& aParamName) const;
159 nsresult SetFromStatement(mozIStorageStatement* aStatement, uint32_t aIndex);
161 nsresult SetFromValueArray(mozIStorageValueArray* aValues, uint32_t aIndex);
163 static int16_t CompareKeys(const Key& aFirst, const Key& aSecond) {
164 int32_t result = Compare(aFirst.mBuffer, aSecond.mBuffer);
166 if (result < 0) {
167 return -1;
170 if (result > 0) {
171 return 1;
174 return 0;
177 private:
178 class MOZ_STACK_CLASS ArrayValueEncoder;
180 using EncodedDataType = unsigned char;
182 const EncodedDataType* BufferStart() const {
183 // TODO it would be nicer if mBuffer was also using EncodedDataType
184 return reinterpret_cast<const EncodedDataType*>(mBuffer.BeginReading());
187 const EncodedDataType* BufferEnd() const {
188 return reinterpret_cast<const EncodedDataType*>(mBuffer.EndReading());
191 // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
192 // step.
193 void TrimBuffer() {
194 const char* end = mBuffer.EndReading() - 1;
195 while (!*end) {
196 --end;
199 mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
202 // Encoding functions. These append the encoded value to the end of mBuffer
203 IDBResult<Ok, IDBSpecialValue::Invalid> EncodeJSVal(
204 JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset);
206 Result<Ok, nsresult> EncodeString(const nsAString& aString,
207 uint8_t aTypeOffset);
209 template <typename T>
210 Result<Ok, nsresult> EncodeString(Span<const T> aInput, uint8_t aTypeOffset);
212 template <typename T>
213 Result<Ok, nsresult> EncodeAsString(Span<const T> aInput, uint8_t aType);
215 Result<Ok, nsresult> EncodeLocaleString(const nsAString& aString,
216 uint8_t aTypeOffset,
217 const nsCString& aLocale);
219 Result<Ok, nsresult> EncodeNumber(double aFloat, uint8_t aType);
221 Result<Ok, nsresult> EncodeBinary(JSObject* aObject, bool aIsViewObject,
222 uint8_t aTypeOffset);
224 // Decoding functions. aPos points into mBuffer and is adjusted to point
225 // past the consumed value. (Note: this may be beyond aEnd).
226 static nsresult DecodeJSVal(const EncodedDataType*& aPos,
227 const EncodedDataType* aEnd, JSContext* aCx,
228 JS::MutableHandle<JS::Value> aVal);
230 static nsAutoString DecodeString(const EncodedDataType*& aPos,
231 const EncodedDataType* aEnd);
233 static double DecodeNumber(const EncodedDataType*& aPos,
234 const EncodedDataType* aEnd);
236 static JSObject* DecodeBinary(const EncodedDataType*& aPos,
237 const EncodedDataType* aEnd, JSContext* aCx);
239 // Returns the size of the decoded data for stringy (string or binary),
240 // excluding a null terminator.
241 // On return, aOutSectionEnd points to the last byte behind the current
242 // encoded section, i.e. either aEnd, or the eTerminator.
243 // T is the base type for the decoded data.
244 template <typename T>
245 static uint32_t CalcDecodedStringySize(
246 const EncodedDataType* aBegin, const EncodedDataType* aEnd,
247 const EncodedDataType** aOutEncodedSectionEnd);
249 static uint32_t LengthOfEncodedBinary(const EncodedDataType* aPos,
250 const EncodedDataType* aEnd);
252 template <typename T>
253 static void DecodeAsStringy(const EncodedDataType* aEncodedSectionBegin,
254 const EncodedDataType* aEncodedSectionEnd,
255 uint32_t aDecodedLength, T* aOut);
257 template <EncodedDataType TypeMask, typename T, typename AcquireBuffer,
258 typename AcquireEmpty>
259 static void DecodeStringy(const EncodedDataType*& aPos,
260 const EncodedDataType* aEnd,
261 const AcquireBuffer& acquireBuffer,
262 const AcquireEmpty& acquireEmpty);
264 IDBResult<Ok, IDBSpecialValue::Invalid> EncodeJSValInternal(
265 JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset,
266 uint16_t aRecursionDepth);
268 static nsresult DecodeJSValInternal(const EncodedDataType*& aPos,
269 const EncodedDataType* aEnd,
270 JSContext* aCx, uint8_t aTypeOffset,
271 JS::MutableHandle<JS::Value> aVal,
272 uint16_t aRecursionDepth);
274 template <typename T>
275 nsresult SetFromSource(T* aSource, uint32_t aIndex);
278 } // namespace mozilla::dom::indexedDB
280 #endif // mozilla_dom_indexeddb_key_h__