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)]
363pub enum AsyncSchemaOperation {
364 CreateIndex {
366 callback: GenericCallback<BackendError>,
367 index_name: String,
368 key_path: KeyPath,
369 unique: bool,
370 multi_entry: bool,
371 },
372 RenameIndex {
374 callback: GenericCallback<BackendError>,
375 index_name: String,
376 new_name: String,
377 },
378 DeleteIndex {
380 callback: GenericCallback<BackendError>,
381 index_name: String,
382 },
383 CreateObjectStore {
385 callback: GenericCallback<BackendError>,
386 key_path: Option<KeyPath>,
387 auto_increment: bool,
388 },
389 DeleteObjectStore {
391 callback: GenericCallback<BackendError>,
392 },
393}
394
395impl AsyncSchemaOperation {
396 pub fn notify_error(&self, error: BackendError) {
397 match self {
398 AsyncSchemaOperation::CreateIndex { .. } |
399 AsyncSchemaOperation::RenameIndex { .. } |
400 AsyncSchemaOperation::DeleteIndex { .. } => {},
401 AsyncSchemaOperation::CreateObjectStore { callback, .. } => {
402 let _ = callback.send(error);
403 },
404 AsyncSchemaOperation::DeleteObjectStore { callback, .. } => {
405 let _ = callback.send(error);
406 },
407 };
408 }
409}
410
411#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
414pub enum AsyncOperation {
415 ReadOnly(AsyncReadOnlyOperation),
416 ReadWrite(AsyncReadWriteOperation),
417 Schema(AsyncSchemaOperation),
418}
419
420impl AsyncOperation {
421 pub fn notify_error(&self, error: BackendError) {
422 match self {
423 Self::ReadOnly(operation) => operation.notify_error(error),
424 Self::ReadWrite(operation) => operation.notify_error(error),
425 Self::Schema(operation) => operation.notify_error(error),
426 }
427 }
428}
429
430#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
431pub enum CreateObjectResult {
432 Created,
433 AlreadyExists,
434}
435
436#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
437pub enum ConnectionMsg {
439 VersionError { name: String, id: Uuid },
441 AbortError { name: String, id: Uuid },
443 Connection {
446 name: String,
447 id: Uuid,
448 version: u64,
449 upgraded: bool,
450 object_store_names: Vec<String>,
453 },
454 Upgrade {
456 name: String,
457 id: Uuid,
458 version: u64,
459 old_version: u64,
460 transaction: u64,
461 object_store_names: Vec<String>,
464 },
465 VersionChange {
467 id: Uuid,
469 name: String,
471 version: u64,
472 old_version: u64,
473 },
474 Blocked {
476 name: String,
477 id: Uuid,
478 version: u64,
479 old_version: u64,
480 },
481 DatabaseError {
483 name: String,
484 id: Uuid,
485 error: BackendError,
486 },
487 TxnMaybeCommit { db_name: String, txn: u64 },
489}
490
491#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
492pub struct TxnCompleteMsg {
493 pub origin: ImmutableOrigin,
494 pub db_name: String,
495 pub txn: u64,
496 pub result: BackendResult<()>,
497}
498
499#[derive(Debug, Deserialize, Serialize)]
500pub struct DatabaseInfo {
501 pub name: String,
502 pub version: u64,
503}
504
505#[derive(Debug, Deserialize, Serialize)]
506pub enum SyncOperation {
507 GetDatabases(
509 GenericCallback<BackendResult<Vec<DatabaseInfo>>>,
510 ImmutableOrigin,
511 ),
512 UpgradeVersion(
514 GenericSender<BackendResult<u64>>,
516 ImmutableOrigin,
517 String, u64, u64, ),
521 GetObjectStore(
523 GenericSender<BackendResult<IndexedDBObjectStore>>,
524 ImmutableOrigin,
525 String, String, ),
528 Commit(
530 GenericCallback<TxnCompleteMsg>,
531 ImmutableOrigin,
532 String, u64, ),
535 Abort(
537 GenericCallback<TxnCompleteMsg>,
538 ImmutableOrigin,
539 String, u64, ),
542 UpgradeTransactionFinished {
544 origin: ImmutableOrigin,
545 db_name: String,
546 txn: u64,
547 committed: bool,
548 },
549 RequestHandled {
557 origin: ImmutableOrigin,
558 db_name: String,
559 txn: u64,
560 request_id: u64,
561 },
562 CreateTransaction {
563 sender: GenericSender<BackendResult<u64>>,
564 origin: ImmutableOrigin,
565 db_name: String,
566 mode: IndexedDBTxnMode,
567 scope: Vec<String>,
568 },
569 TxnMaybeCommit {
571 origin: ImmutableOrigin,
572 db_name: String,
573 txn: u64,
574 },
575 TransactionFinished {
576 origin: ImmutableOrigin,
577 db_name: String,
578 txn: u64,
579 },
580
581 CloseDatabase(
582 ImmutableOrigin,
583 Uuid,
584 String, ),
586
587 OpenDatabase(
588 GenericCallback<ConnectionMsg>,
590 ImmutableOrigin,
592 String,
594 Option<u64>,
596 Uuid,
598 StorageProxyMap,
600 ),
601
602 DeleteDatabase(
604 GenericCallback<BackendResult<u64>>,
605 ImmutableOrigin,
606 String,
608 StorageProxyMap,
610 Uuid,
611 ),
612
613 Version(
615 GenericSender<BackendResult<u64>>,
616 ImmutableOrigin,
617 String, ),
619
620 AbortPendingUpgrades {
622 pending_upgrades: HashMap<String, HashSet<Uuid>>,
623 origin: ImmutableOrigin,
624 proxy_map: StorageProxyMap,
625 },
626
627 NotifyEndOfVersionChange {
628 id: Uuid,
629 name: String,
630 old_version: u64,
631 origin: ImmutableOrigin,
632 },
633
634 Exit(GenericSender<()>),
636}
637
638#[derive(Debug, Deserialize, Serialize)]
639pub enum IndexedDBThreadMsg {
640 Sync(SyncOperation),
641 Async(
642 ImmutableOrigin,
643 String, String, u64, u64, IndexedDBTxnMode,
648 AsyncOperation,
649 ),
650 AsyncSchemaOperation {
651 origin: ImmutableOrigin,
652 database_name: String,
653 store_name: String,
654 operation: AsyncSchemaOperation,
655 transaction_serial_number: u64,
656 },
657 EngineTxnBatchComplete {
658 origin: ImmutableOrigin,
659 db_name: String,
660 txn: u64,
661 },
662
663 CollectMemoryReport(ReportsChan),
665}
666
667#[cfg(test)]
668mod test {
669 use super::*;
670
671 #[test]
672 fn test_as_singleton() {
673 let key = IndexedDBKeyType::Number(1.0);
674 let key2 = IndexedDBKeyType::Number(2.0);
675 let range = IndexedDBKeyRange::only(key.clone());
676 assert!(range.is_singleton());
677 assert!(range.as_singleton().is_some());
678 let range = IndexedDBKeyRange::new(Some(key), Some(key2.clone()), false, false);
679 assert!(!range.is_singleton());
680 assert!(range.as_singleton().is_none());
681 let full_range = IndexedDBKeyRange::new(None, None, false, false);
682 assert!(!full_range.is_singleton());
683 assert!(full_range.as_singleton().is_none());
684 }
685}