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<i64>,
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<i64>,
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 RenameIndex(
542 ImmutableOrigin,
543 String, String, String, String, ),
548 DeleteIndex(
550 ImmutableOrigin,
551 String, String, String, ),
555
556 CreateObjectStore(
558 GenericSender<BackendResult<CreateObjectResult>>,
559 ImmutableOrigin,
560 String, String, Option<KeyPath>, bool,
564 ),
565
566 DeleteObjectStore(
567 GenericSender<BackendResult<()>>,
568 ImmutableOrigin,
569 String, String, ),
572
573 CloseDatabase(
574 ImmutableOrigin,
575 Uuid,
576 String, ),
578
579 OpenDatabase(
580 GenericCallback<ConnectionMsg>,
582 ImmutableOrigin,
584 String,
586 Option<u64>,
588 Uuid,
590 StorageProxyMap,
592 ),
593
594 DeleteDatabase(
596 GenericCallback<BackendResult<u64>>,
597 ImmutableOrigin,
598 String,
600 StorageProxyMap,
602 Uuid,
603 ),
604
605 Version(
607 GenericSender<BackendResult<u64>>,
608 ImmutableOrigin,
609 String, ),
611
612 AbortPendingUpgrades {
614 pending_upgrades: HashMap<String, HashSet<Uuid>>,
615 origin: ImmutableOrigin,
616 proxy_map: StorageProxyMap,
617 },
618
619 NotifyEndOfVersionChange {
620 id: Uuid,
621 name: String,
622 old_version: u64,
623 origin: ImmutableOrigin,
624 },
625
626 Exit(GenericSender<()>),
628}
629
630#[derive(Debug, Deserialize, Serialize)]
631pub enum IndexedDBThreadMsg {
632 Sync(SyncOperation),
633 Async(
634 ImmutableOrigin,
635 String, String, u64, u64, IndexedDBTxnMode,
640 AsyncOperation,
641 ),
642 EngineTxnBatchComplete {
643 origin: ImmutableOrigin,
644 db_name: String,
645 txn: u64,
646 },
647
648 CollectMemoryReport(ReportsChan),
650}
651
652#[cfg(test)]
653mod test {
654 use super::*;
655
656 #[test]
657 fn test_as_singleton() {
658 let key = IndexedDBKeyType::Number(1.0);
659 let key2 = IndexedDBKeyType::Number(2.0);
660 let range = IndexedDBKeyRange::only(key.clone());
661 assert!(range.is_singleton());
662 assert!(range.as_singleton().is_some());
663 let range = IndexedDBKeyRange::new(Some(key), Some(key2.clone()), false, false);
664 assert!(!range.is_singleton());
665 assert!(range.as_singleton().is_none());
666 let full_range = IndexedDBKeyRange::new(None, None, false, false);
667 assert!(!full_range.is_singleton());
668 assert!(full_range.as_singleton().is_none());
669 }
670}