1use std::cmp::{Ordering, PartialEq, PartialOrd};
6use std::collections::{HashMap, HashSet};
7use std::error::Error;
8use std::fmt::{Debug, Display, Formatter};
9
10use base::generic_channel::GenericSender;
11use malloc_size_of_derive::MallocSizeOf;
12use profile_traits::generic_callback::GenericCallback;
13use serde::{Deserialize, Serialize};
14use servo_url::origin::ImmutableOrigin;
15use uuid::Uuid;
16
17pub type DbError = String;
19pub type DbResult<T> = Result<T, DbError>;
22
23#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
25pub enum BackendError {
26 DbNotFound,
28 StoreNotFound,
30 QuotaExceeded,
32
33 DbErr(DbError),
34}
35
36impl From<DbError> for BackendError {
37 fn from(value: DbError) -> Self {
38 BackendError::DbErr(value)
39 }
40}
41
42impl Display for BackendError {
43 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44 match self {
45 BackendError::DbNotFound => write!(f, "DbNotFound"),
46 BackendError::StoreNotFound => write!(f, "StoreNotFound"),
47 BackendError::QuotaExceeded => write!(f, "QuotaExceeded"),
48 BackendError::DbErr(err) => write!(f, "{err}"),
49 }
50 }
51}
52
53impl Error for BackendError {}
54
55pub type BackendResult<T> = Result<T, BackendError>;
56
57#[derive(Clone, Debug, Deserialize, Eq, PartialEq, MallocSizeOf, Serialize)]
58pub enum KeyPath {
59 String(String),
60 Sequence(Vec<String>),
61}
62
63#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
65pub enum IndexedDBTxnMode {
66 Readonly,
67 Readwrite,
68 Versionchange,
69}
70
71#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
73pub enum IndexedDBKeyType {
74 Number(f64),
75 String(String),
76 Binary(Vec<u8>),
77 Date(f64),
78 Array(Vec<IndexedDBKeyType>),
79 }
81
82impl PartialOrd for IndexedDBKeyType {
84 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
85 match (self, other) {
89 (
91 IndexedDBKeyType::Array(_),
92 IndexedDBKeyType::Binary(_) |
93 IndexedDBKeyType::Date(_) |
94 IndexedDBKeyType::Number(_) |
95 IndexedDBKeyType::String(_),
96 ) => Some(Ordering::Greater),
97 (
99 IndexedDBKeyType::Binary(_) |
100 IndexedDBKeyType::Date(_) |
101 IndexedDBKeyType::Number(_) |
102 IndexedDBKeyType::String(_),
103 IndexedDBKeyType::Array(_),
104 ) => Some(Ordering::Less),
105 (
107 IndexedDBKeyType::Binary(_),
108 IndexedDBKeyType::String(_) |
109 IndexedDBKeyType::Date(_) |
110 IndexedDBKeyType::Number(_),
111 ) => Some(Ordering::Greater),
112 (
114 IndexedDBKeyType::String(_) |
115 IndexedDBKeyType::Date(_) |
116 IndexedDBKeyType::Number(_),
117 IndexedDBKeyType::Binary(_),
118 ) => Some(Ordering::Less),
119 (
121 IndexedDBKeyType::String(_),
122 IndexedDBKeyType::Date(_) | IndexedDBKeyType::Number(_),
123 ) => Some(Ordering::Greater),
124 (
126 IndexedDBKeyType::Date(_) | IndexedDBKeyType::Number(_),
127 IndexedDBKeyType::String(_),
128 ) => Some(Ordering::Less),
129 (IndexedDBKeyType::Date(_), IndexedDBKeyType::Number(_)) => Some(Ordering::Greater),
131 (IndexedDBKeyType::Number(_), IndexedDBKeyType::Date(_)) => Some(Ordering::Less),
133 (IndexedDBKeyType::Number(a), IndexedDBKeyType::Number(b)) => a.partial_cmp(b),
136 (IndexedDBKeyType::String(a), IndexedDBKeyType::String(b)) => a.partial_cmp(b),
138 (IndexedDBKeyType::Binary(a), IndexedDBKeyType::Binary(b)) => a.partial_cmp(b),
140 (IndexedDBKeyType::Date(a), IndexedDBKeyType::Date(b)) => a.partial_cmp(b),
141 (IndexedDBKeyType::Array(a), IndexedDBKeyType::Array(b)) => a.partial_cmp(b),
143 }
145 }
146}
147
148impl PartialEq for IndexedDBKeyType {
149 fn eq(&self, other: &Self) -> bool {
150 let cmp = self.partial_cmp(other);
151 match cmp {
152 Some(Ordering::Equal) => true,
153 Some(Ordering::Less) | Some(Ordering::Greater) => false,
154 None => {
155 false
157 },
158 }
159 }
160}
161
162#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
164pub struct IndexedDBKeyRange {
165 pub lower: Option<IndexedDBKeyType>,
166 pub upper: Option<IndexedDBKeyType>,
167 pub lower_open: bool,
168 pub upper_open: bool,
169}
170
171impl From<IndexedDBKeyType> for IndexedDBKeyRange {
172 fn from(key: IndexedDBKeyType) -> Self {
173 IndexedDBKeyRange {
174 lower: Some(key.clone()),
175 upper: Some(key),
176 ..Default::default()
177 }
178 }
179}
180
181impl IndexedDBKeyRange {
182 pub fn only(key: IndexedDBKeyType) -> Self {
183 Self::from(key)
184 }
185
186 pub fn new(
187 lower: Option<IndexedDBKeyType>,
188 upper: Option<IndexedDBKeyType>,
189 lower_open: bool,
190 upper_open: bool,
191 ) -> Self {
192 IndexedDBKeyRange {
193 lower,
194 upper,
195 lower_open,
196 upper_open,
197 }
198 }
199
200 pub fn lower_bound(key: IndexedDBKeyType, open: bool) -> Self {
201 IndexedDBKeyRange {
202 lower: Some(key),
203 upper: None,
204 lower_open: open,
205 upper_open: false,
206 }
207 }
208
209 pub fn upper_bound(key: IndexedDBKeyType, open: bool) -> Self {
210 IndexedDBKeyRange {
211 lower: None,
212 upper: Some(key),
213 lower_open: false,
214 upper_open: open,
215 }
216 }
217
218 pub fn contains(&self, key: &IndexedDBKeyType) -> bool {
220 let lower_bound_condition = self
226 .lower
227 .as_ref()
228 .is_none_or(|lower| lower < key || (!self.lower_open && lower == key));
229 let upper_bound_condition = self
230 .upper
231 .as_ref()
232 .is_none_or(|upper| key < upper || (!self.upper_open && key == upper));
233 lower_bound_condition && upper_bound_condition
234 }
235
236 pub fn is_singleton(&self) -> bool {
237 self.lower.is_some() && self.lower == self.upper && !self.lower_open && !self.upper_open
238 }
239
240 pub fn as_singleton(&self) -> Option<&IndexedDBKeyType> {
241 if self.is_singleton() {
242 return Some(self.lower.as_ref().unwrap());
243 }
244 None
245 }
246}
247
248#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
250pub struct IndexedDBRecord {
251 pub key: IndexedDBKeyType,
252 pub primary_key: IndexedDBKeyType,
253 pub value: Vec<u8>,
254}
255
256#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
257pub struct IndexedDBIndex {
258 pub name: String,
259 pub key_path: KeyPath,
260 pub multi_entry: bool,
261 pub unique: bool,
262}
263
264#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
265pub struct IndexedDBObjectStore {
266 pub name: String,
267 pub key_path: Option<KeyPath>,
268 pub has_key_generator: bool,
269 pub indexes: Vec<IndexedDBIndex>,
270}
271
272#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
273pub enum PutItemResult {
274 Success,
275 CannotOverwrite,
276}
277
278#[derive(Debug, Deserialize, Serialize)]
279pub enum AsyncReadOnlyOperation {
280 GetKey {
282 callback: GenericCallback<BackendResult<Option<IndexedDBKeyType>>>,
283 key_range: IndexedDBKeyRange,
284 },
285 GetItem {
286 callback: GenericCallback<BackendResult<Option<Vec<u8>>>>,
287 key_range: IndexedDBKeyRange,
288 },
289
290 GetAllKeys {
291 callback: GenericCallback<BackendResult<Vec<IndexedDBKeyType>>>,
292 key_range: IndexedDBKeyRange,
293 count: Option<u32>,
294 },
295 GetAllItems {
296 callback: GenericCallback<BackendResult<Vec<Vec<u8>>>>,
297 key_range: IndexedDBKeyRange,
298 count: Option<u32>,
299 },
300
301 Count {
302 callback: GenericCallback<BackendResult<u64>>,
303 key_range: IndexedDBKeyRange,
304 },
305 Iterate {
306 callback: GenericCallback<BackendResult<Vec<IndexedDBRecord>>>,
307 key_range: IndexedDBKeyRange,
308 },
309}
310
311impl AsyncReadOnlyOperation {
312 fn notify_error(&self, error: BackendError) {
313 let _ = match self {
314 Self::GetKey { callback, .. } => callback.send(Err(error)),
315 Self::GetItem { callback, .. } => callback.send(Err(error)),
316 Self::GetAllKeys { callback, .. } => callback.send(Err(error)),
317 Self::GetAllItems { callback, .. } => callback.send(Err(error)),
318 Self::Count { callback, .. } => callback.send(Err(error)),
319 Self::Iterate { callback, .. } => callback.send(Err(error)),
320 };
321 }
322}
323
324#[derive(Debug, Deserialize, Serialize)]
325pub enum AsyncReadWriteOperation {
326 PutItem {
328 callback: GenericCallback<BackendResult<PutItemResult>>,
329 key: Option<IndexedDBKeyType>,
330 value: Vec<u8>,
331 should_overwrite: bool,
332 },
333
334 RemoveItem {
336 callback: GenericCallback<BackendResult<()>>,
337 key_range: IndexedDBKeyRange,
338 },
339 Clear(GenericCallback<BackendResult<()>>),
341}
342
343impl AsyncReadWriteOperation {
344 fn notify_error(&self, error: BackendError) {
345 let _ = match self {
346 Self::PutItem { callback, .. } => callback.send(Err(error)),
347 Self::RemoveItem { callback, .. } => callback.send(Err(error)),
348 Self::Clear(callback) => callback.send(Err(error)),
349 };
350 }
351}
352
353#[derive(Debug, Deserialize, Serialize)]
356pub enum AsyncOperation {
357 ReadOnly(AsyncReadOnlyOperation),
358 ReadWrite(AsyncReadWriteOperation),
359}
360
361impl AsyncOperation {
362 pub fn notify_error(&self, error: BackendError) {
363 match self {
364 Self::ReadOnly(operation) => operation.notify_error(error),
365 Self::ReadWrite(operation) => operation.notify_error(error),
366 }
367 }
368}
369
370#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
371pub enum CreateObjectResult {
372 Created,
373 AlreadyExists,
374}
375
376#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
377pub enum ConnectionMsg {
379 VersionError { name: String, id: Uuid },
381 AbortError { name: String, id: Uuid },
383 Connection {
386 name: String,
387 id: Uuid,
388 version: u64,
389 upgraded: bool,
390 },
391 Upgrade {
393 name: String,
394 id: Uuid,
395 version: u64,
396 old_version: u64,
397 transaction: u64,
398 },
399 VersionChange {
401 id: Uuid,
403 name: String,
405 version: u64,
406 old_version: u64,
407 },
408 Blocked {
410 name: String,
411 id: Uuid,
412 version: u64,
413 old_version: u64,
414 },
415 DatabaseError {
417 name: String,
418 id: Uuid,
419 error: BackendError,
420 },
421}
422
423#[derive(Debug, Deserialize, Serialize)]
424pub struct DatabaseInfo {
425 pub name: String,
426 pub version: u64,
427}
428
429#[derive(Debug, Deserialize, Serialize)]
430pub enum SyncOperation {
431 GetDatabases(
433 GenericCallback<BackendResult<Vec<DatabaseInfo>>>,
434 ImmutableOrigin,
435 ),
436 UpgradeVersion(
438 GenericSender<BackendResult<u64>>,
440 ImmutableOrigin,
441 String, u64, u64, ),
445 GetObjectStore(
447 GenericSender<BackendResult<IndexedDBObjectStore>>,
448 ImmutableOrigin,
449 String, String, ),
452
453 Commit(
455 GenericSender<BackendResult<()>>,
456 ImmutableOrigin,
457 String, u64, ),
460
461 CreateIndex(
463 ImmutableOrigin,
464 String, String, String, KeyPath, bool, bool, ),
471 DeleteIndex(
473 ImmutableOrigin,
474 String, String, String, ),
478
479 CreateObjectStore(
481 GenericSender<BackendResult<CreateObjectResult>>,
482 ImmutableOrigin,
483 String, String, Option<KeyPath>, bool,
487 ),
488
489 DeleteObjectStore(
490 GenericSender<BackendResult<()>>,
491 ImmutableOrigin,
492 String, String, ),
495
496 CloseDatabase(
497 ImmutableOrigin,
498 Uuid,
499 String, ),
501
502 OpenDatabase(
503 GenericCallback<ConnectionMsg>,
505 ImmutableOrigin,
507 String,
509 Option<u64>,
511 Uuid,
513 ),
514
515 DeleteDatabase(
517 GenericCallback<BackendResult<u64>>,
518 ImmutableOrigin,
519 String, Uuid,
521 ),
522
523 RegisterNewTxn(
526 GenericSender<u64>,
528 ImmutableOrigin,
529 String, ),
531
532 StartTransaction(
535 GenericSender<BackendResult<()>>,
536 ImmutableOrigin,
537 String, u64, ),
540
541 Version(
543 GenericSender<BackendResult<u64>>,
544 ImmutableOrigin,
545 String, ),
547
548 AbortPendingUpgrades {
550 pending_upgrades: HashMap<String, HashSet<Uuid>>,
551 origin: ImmutableOrigin,
552 },
553
554 AbortPendingUpgrade {
556 name: String,
557 id: Uuid,
558 origin: ImmutableOrigin,
559 },
560
561 NotifyEndOfVersionChange {
562 id: Uuid,
563 name: String,
564 old_version: u64,
565 origin: ImmutableOrigin,
566 },
567
568 Exit(GenericSender<()>),
570}
571
572#[derive(Debug, Deserialize, Serialize)]
573pub enum IndexedDBThreadMsg {
574 Sync(SyncOperation),
575 Async(
576 ImmutableOrigin,
577 String, String, u64, IndexedDBTxnMode,
581 AsyncOperation,
582 ),
583 OpenTransactionInactive {
584 name: String,
585 origin: ImmutableOrigin,
586 },
587}
588
589#[cfg(test)]
590mod test {
591 use super::*;
592
593 #[test]
594 fn test_as_singleton() {
595 let key = IndexedDBKeyType::Number(1.0);
596 let key2 = IndexedDBKeyType::Number(2.0);
597 let range = IndexedDBKeyRange::only(key.clone());
598 assert!(range.is_singleton());
599 assert!(range.as_singleton().is_some());
600 let range = IndexedDBKeyRange::new(Some(key), Some(key2.clone()), false, false);
601 assert!(!range.is_singleton());
602 assert!(range.as_singleton().is_none());
603 let full_range = IndexedDBKeyRange::new(None, None, false, false);
604 assert!(!full_range.is_singleton());
605 assert!(full_range.as_singleton().is_none());
606 }
607}