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