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 profile_traits::mem::ReportsChan;
14use serde::{Deserialize, Serialize};
15use servo_url::origin::ImmutableOrigin;
16use uuid::Uuid;
17
18pub type DbError = String;
20pub type DbResult<T> = Result<T, DbError>;
23
24#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
26pub enum BackendError {
27 DbNotFound,
29 StoreNotFound,
31 QuotaExceeded,
33 Abort,
35
36 DbErr(DbError),
37}
38
39impl From<DbError> for BackendError {
40 fn from(value: DbError) -> Self {
41 BackendError::DbErr(value)
42 }
43}
44
45impl Display for BackendError {
46 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
47 match self {
48 BackendError::DbNotFound => write!(f, "DbNotFound"),
49 BackendError::StoreNotFound => write!(f, "StoreNotFound"),
50 BackendError::QuotaExceeded => write!(f, "QuotaExceeded"),
51 BackendError::Abort => write!(f, "Abort"),
52 BackendError::DbErr(err) => write!(f, "{err}"),
53 }
54 }
55}
56
57impl Error for BackendError {}
58
59pub type BackendResult<T> = Result<T, BackendError>;
60
61#[derive(Clone, Debug, Deserialize, Eq, PartialEq, MallocSizeOf, Serialize)]
62pub enum KeyPath {
63 String(String),
64 Sequence(Vec<String>),
65}
66
67#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
69pub enum IndexedDBTxnMode {
70 Readonly,
71 Readwrite,
72 Versionchange,
73}
74
75#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
77pub enum IndexedDBKeyType {
78 Number(f64),
79 String(String),
80 Binary(Vec<u8>),
81 Date(f64),
82 Array(Vec<IndexedDBKeyType>),
83 }
85
86impl PartialOrd for IndexedDBKeyType {
88 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
89 match (self, other) {
93 (
95 IndexedDBKeyType::Array(_),
96 IndexedDBKeyType::Binary(_) |
97 IndexedDBKeyType::Date(_) |
98 IndexedDBKeyType::Number(_) |
99 IndexedDBKeyType::String(_),
100 ) => Some(Ordering::Greater),
101 (
103 IndexedDBKeyType::Binary(_) |
104 IndexedDBKeyType::Date(_) |
105 IndexedDBKeyType::Number(_) |
106 IndexedDBKeyType::String(_),
107 IndexedDBKeyType::Array(_),
108 ) => Some(Ordering::Less),
109 (
111 IndexedDBKeyType::Binary(_),
112 IndexedDBKeyType::String(_) |
113 IndexedDBKeyType::Date(_) |
114 IndexedDBKeyType::Number(_),
115 ) => Some(Ordering::Greater),
116 (
118 IndexedDBKeyType::String(_) |
119 IndexedDBKeyType::Date(_) |
120 IndexedDBKeyType::Number(_),
121 IndexedDBKeyType::Binary(_),
122 ) => Some(Ordering::Less),
123 (
125 IndexedDBKeyType::String(_),
126 IndexedDBKeyType::Date(_) | IndexedDBKeyType::Number(_),
127 ) => Some(Ordering::Greater),
128 (
130 IndexedDBKeyType::Date(_) | IndexedDBKeyType::Number(_),
131 IndexedDBKeyType::String(_),
132 ) => Some(Ordering::Less),
133 (IndexedDBKeyType::Date(_), IndexedDBKeyType::Number(_)) => Some(Ordering::Greater),
135 (IndexedDBKeyType::Number(_), IndexedDBKeyType::Date(_)) => Some(Ordering::Less),
137 (IndexedDBKeyType::Number(a), IndexedDBKeyType::Number(b)) => a.partial_cmp(b),
140 (IndexedDBKeyType::String(a), IndexedDBKeyType::String(b)) => a.partial_cmp(b),
142 (IndexedDBKeyType::Binary(a), IndexedDBKeyType::Binary(b)) => a.partial_cmp(b),
144 (IndexedDBKeyType::Date(a), IndexedDBKeyType::Date(b)) => a.partial_cmp(b),
145 (IndexedDBKeyType::Array(a), IndexedDBKeyType::Array(b)) => a.partial_cmp(b),
147 }
149 }
150}
151
152impl PartialEq for IndexedDBKeyType {
153 fn eq(&self, other: &Self) -> bool {
154 let cmp = self.partial_cmp(other);
155 match cmp {
156 Some(Ordering::Equal) => true,
157 Some(Ordering::Less) | Some(Ordering::Greater) => false,
158 None => {
159 false
161 },
162 }
163 }
164}
165
166#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
168pub struct IndexedDBKeyRange {
169 pub lower: Option<IndexedDBKeyType>,
170 pub upper: Option<IndexedDBKeyType>,
171 pub lower_open: bool,
172 pub upper_open: bool,
173}
174
175impl From<IndexedDBKeyType> for IndexedDBKeyRange {
176 fn from(key: IndexedDBKeyType) -> Self {
177 IndexedDBKeyRange {
178 lower: Some(key.clone()),
179 upper: Some(key),
180 ..Default::default()
181 }
182 }
183}
184
185impl IndexedDBKeyRange {
186 pub fn only(key: IndexedDBKeyType) -> Self {
187 Self::from(key)
188 }
189
190 pub fn new(
191 lower: Option<IndexedDBKeyType>,
192 upper: Option<IndexedDBKeyType>,
193 lower_open: bool,
194 upper_open: bool,
195 ) -> Self {
196 IndexedDBKeyRange {
197 lower,
198 upper,
199 lower_open,
200 upper_open,
201 }
202 }
203
204 pub fn lower_bound(key: IndexedDBKeyType, open: bool) -> Self {
205 IndexedDBKeyRange {
206 lower: Some(key),
207 upper: None,
208 lower_open: open,
209 upper_open: false,
210 }
211 }
212
213 pub fn upper_bound(key: IndexedDBKeyType, open: bool) -> Self {
214 IndexedDBKeyRange {
215 lower: None,
216 upper: Some(key),
217 lower_open: false,
218 upper_open: open,
219 }
220 }
221
222 pub fn contains(&self, key: &IndexedDBKeyType) -> bool {
224 let lower_bound_condition = self
230 .lower
231 .as_ref()
232 .is_none_or(|lower| lower < key || (!self.lower_open && lower == key));
233 let upper_bound_condition = self
234 .upper
235 .as_ref()
236 .is_none_or(|upper| key < upper || (!self.upper_open && key == upper));
237 lower_bound_condition && upper_bound_condition
238 }
239
240 pub fn is_singleton(&self) -> bool {
241 self.lower.is_some() && self.lower == self.upper && !self.lower_open && !self.upper_open
242 }
243
244 pub fn as_singleton(&self) -> Option<&IndexedDBKeyType> {
245 if self.is_singleton() {
246 return Some(self.lower.as_ref().unwrap());
247 }
248 None
249 }
250}
251
252#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
254pub struct IndexedDBRecord {
255 pub key: IndexedDBKeyType,
256 pub primary_key: IndexedDBKeyType,
257 pub value: Vec<u8>,
258}
259
260#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
261pub struct IndexedDBIndex {
262 pub name: String,
263 pub key_path: KeyPath,
264 pub multi_entry: bool,
265 pub unique: bool,
266}
267
268#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
269pub struct IndexedDBObjectStore {
270 pub name: String,
271 pub key_path: Option<KeyPath>,
272 pub has_key_generator: bool,
273 pub key_generator_current_number: Option<i32>,
274 pub indexes: Vec<IndexedDBIndex>,
275}
276
277#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
278pub enum PutItemResult {
279 Key(IndexedDBKeyType),
280 CannotOverwrite,
281}
282
283#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
284pub enum AsyncReadOnlyOperation {
285 GetKey {
287 callback: GenericCallback<BackendResult<Option<IndexedDBKeyType>>>,
288 key_range: IndexedDBKeyRange,
289 },
290 GetItem {
291 callback: GenericCallback<BackendResult<Option<Vec<u8>>>>,
292 key_range: IndexedDBKeyRange,
293 },
294
295 GetAllKeys {
296 callback: GenericCallback<BackendResult<Vec<IndexedDBKeyType>>>,
297 key_range: IndexedDBKeyRange,
298 count: Option<u32>,
299 },
300 GetAllItems {
301 callback: GenericCallback<BackendResult<Vec<Vec<u8>>>>,
302 key_range: IndexedDBKeyRange,
303 count: Option<u32>,
304 },
305
306 Count {
307 callback: GenericCallback<BackendResult<u64>>,
308 key_range: IndexedDBKeyRange,
309 },
310 Iterate {
311 callback: GenericCallback<BackendResult<Vec<IndexedDBRecord>>>,
312 key_range: IndexedDBKeyRange,
313 },
314}
315
316impl AsyncReadOnlyOperation {
317 fn notify_error(&self, error: BackendError) {
318 let _ = match self {
319 Self::GetKey { callback, .. } => callback.send(Err(error)),
320 Self::GetItem { callback, .. } => callback.send(Err(error)),
321 Self::GetAllKeys { callback, .. } => callback.send(Err(error)),
322 Self::GetAllItems { callback, .. } => callback.send(Err(error)),
323 Self::Count { callback, .. } => callback.send(Err(error)),
324 Self::Iterate { callback, .. } => callback.send(Err(error)),
325 };
326 }
327}
328
329#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
330pub enum AsyncReadWriteOperation {
331 PutItem {
333 callback: GenericCallback<BackendResult<PutItemResult>>,
334 key: Option<IndexedDBKeyType>,
335 value: Vec<u8>,
336 should_overwrite: bool,
337 key_generator_current_number: Option<i32>,
339 },
340
341 RemoveItem {
343 callback: GenericCallback<BackendResult<()>>,
344 key_range: IndexedDBKeyRange,
345 },
346 Clear(GenericCallback<BackendResult<()>>),
348}
349
350impl AsyncReadWriteOperation {
351 fn notify_error(&self, error: BackendError) {
352 let _ = match self {
353 Self::PutItem { callback, .. } => callback.send(Err(error)),
354 Self::RemoveItem { callback, .. } => callback.send(Err(error)),
355 Self::Clear(callback) => callback.send(Err(error)),
356 };
357 }
358}
359
360#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
363pub enum AsyncOperation {
364 ReadOnly(AsyncReadOnlyOperation),
365 ReadWrite(AsyncReadWriteOperation),
366}
367
368impl AsyncOperation {
369 pub fn notify_error(&self, error: BackendError) {
370 match self {
371 Self::ReadOnly(operation) => operation.notify_error(error),
372 Self::ReadWrite(operation) => operation.notify_error(error),
373 }
374 }
375}
376
377#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
378pub enum CreateObjectResult {
379 Created,
380 AlreadyExists,
381}
382
383#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
384pub enum ConnectionMsg {
386 VersionError { name: String, id: Uuid },
388 AbortError { name: String, id: Uuid },
390 Connection {
393 name: String,
394 id: Uuid,
395 version: u64,
396 upgraded: bool,
397 object_store_names: Vec<String>,
400 },
401 Upgrade {
403 name: String,
404 id: Uuid,
405 version: u64,
406 old_version: u64,
407 transaction: u64,
408 object_store_names: Vec<String>,
411 },
412 VersionChange {
414 id: Uuid,
416 name: String,
418 version: u64,
419 old_version: u64,
420 },
421 Blocked {
423 name: String,
424 id: Uuid,
425 version: u64,
426 old_version: u64,
427 },
428 DatabaseError {
430 name: String,
431 id: Uuid,
432 error: BackendError,
433 },
434 TxnMaybeCommit { db_name: String, txn: u64 },
436}
437
438#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
439pub struct TxnCompleteMsg {
440 pub origin: ImmutableOrigin,
441 pub db_name: String,
442 pub txn: u64,
443 pub result: BackendResult<()>,
444}
445
446#[derive(Debug, Deserialize, Serialize)]
447pub struct DatabaseInfo {
448 pub name: String,
449 pub version: u64,
450}
451
452#[derive(Debug, Deserialize, Serialize)]
453pub enum SyncOperation {
454 GetDatabases(
456 GenericCallback<BackendResult<Vec<DatabaseInfo>>>,
457 ImmutableOrigin,
458 ),
459 UpgradeVersion(
461 GenericSender<BackendResult<u64>>,
463 ImmutableOrigin,
464 String, u64, u64, ),
468 GetObjectStore(
470 GenericSender<BackendResult<IndexedDBObjectStore>>,
471 ImmutableOrigin,
472 String, String, ),
475 Commit(
477 GenericCallback<TxnCompleteMsg>,
478 ImmutableOrigin,
479 String, u64, ),
482 Abort(
484 GenericCallback<TxnCompleteMsg>,
485 ImmutableOrigin,
486 String, u64, ),
489 UpgradeTransactionFinished {
491 origin: ImmutableOrigin,
492 db_name: String,
493 txn: u64,
494 committed: bool,
495 },
496 RequestHandled {
504 origin: ImmutableOrigin,
505 db_name: String,
506 txn: u64,
507 request_id: u64,
508 },
509 CreateTransaction {
510 sender: GenericSender<BackendResult<u64>>,
511 origin: ImmutableOrigin,
512 db_name: String,
513 mode: IndexedDBTxnMode,
514 scope: Vec<String>,
515 },
516 TxnMaybeCommit {
518 origin: ImmutableOrigin,
519 db_name: String,
520 txn: u64,
521 },
522 TransactionFinished {
523 origin: ImmutableOrigin,
524 db_name: String,
525 txn: u64,
526 },
527
528 CreateIndex(
530 ImmutableOrigin,
531 String, String, String, KeyPath, bool, bool, ),
538 DeleteIndex(
540 ImmutableOrigin,
541 String, String, String, ),
545
546 CreateObjectStore(
548 GenericSender<BackendResult<CreateObjectResult>>,
549 ImmutableOrigin,
550 String, String, Option<KeyPath>, bool,
554 ),
555
556 DeleteObjectStore(
557 GenericSender<BackendResult<()>>,
558 ImmutableOrigin,
559 String, String, ),
562
563 CloseDatabase(
564 ImmutableOrigin,
565 Uuid,
566 String, ),
568
569 OpenDatabase(
570 GenericCallback<ConnectionMsg>,
572 ImmutableOrigin,
574 String,
576 Option<u64>,
578 Uuid,
580 ),
581
582 DeleteDatabase(
584 GenericCallback<BackendResult<u64>>,
585 ImmutableOrigin,
586 String, Uuid,
588 ),
589
590 Version(
592 GenericSender<BackendResult<u64>>,
593 ImmutableOrigin,
594 String, ),
596
597 AbortPendingUpgrades {
599 pending_upgrades: HashMap<String, HashSet<Uuid>>,
600 origin: ImmutableOrigin,
601 },
602
603 AbortPendingUpgrade {
605 name: String,
606 id: Uuid,
607 origin: ImmutableOrigin,
608 },
609
610 NotifyEndOfVersionChange {
611 id: Uuid,
612 name: String,
613 old_version: u64,
614 origin: ImmutableOrigin,
615 },
616
617 Exit(GenericSender<()>),
619}
620
621#[derive(Debug, Deserialize, Serialize)]
622pub enum IndexedDBThreadMsg {
623 Sync(SyncOperation),
624 Async(
625 ImmutableOrigin,
626 String, String, u64, u64, IndexedDBTxnMode,
631 AsyncOperation,
632 ),
633 EngineTxnBatchComplete {
634 origin: ImmutableOrigin,
635 db_name: String,
636 txn: u64,
637 },
638
639 CollectMemoryReport(ReportsChan),
641}
642
643#[cfg(test)]
644mod test {
645 use super::*;
646
647 #[test]
648 fn test_as_singleton() {
649 let key = IndexedDBKeyType::Number(1.0);
650 let key2 = IndexedDBKeyType::Number(2.0);
651 let range = IndexedDBKeyRange::only(key.clone());
652 assert!(range.is_singleton());
653 assert!(range.as_singleton().is_some());
654 let range = IndexedDBKeyRange::new(Some(key), Some(key2.clone()), false, false);
655 assert!(!range.is_singleton());
656 assert!(range.as_singleton().is_none());
657 let full_range = IndexedDBKeyRange::new(None, None, false, false);
658 assert!(!full_range.is_singleton());
659 assert!(full_range.as_singleton().is_none());
660 }
661}