script/dom/
idbcursor.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::jsapi::Heap;
9use js::jsval::{JSVal, UndefinedValue};
10use js::rust::MutableHandleValue;
11use net_traits::indexeddb_thread::{IndexedDBKeyRange, IndexedDBKeyType};
12
13use crate::dom::bindings::cell::DomRefCell;
14use crate::dom::bindings::codegen::Bindings::IDBCursorBinding::{
15    IDBCursorDirection, IDBCursorMethods,
16};
17use crate::dom::bindings::codegen::UnionTypes::IDBObjectStoreOrIDBIndex;
18use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
19use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
20use crate::dom::globalscope::GlobalScope;
21use crate::dom::idbindex::IDBIndex;
22use crate::dom::idbobjectstore::IDBObjectStore;
23use crate::dom::idbrequest::IDBRequest;
24use crate::dom::idbtransaction::IDBTransaction;
25use crate::indexed_db::key_type_to_jsval;
26use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
27
28#[derive(JSTraceable, MallocSizeOf)]
29#[expect(unused)]
30#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
31pub(crate) enum ObjectStoreOrIndex {
32    ObjectStore(Dom<IDBObjectStore>),
33    Index(Dom<IDBIndex>),
34}
35
36#[dom_struct]
37pub(crate) struct IDBCursor {
38    reflector_: Reflector,
39
40    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-transaction>
41    transaction: Dom<IDBTransaction>,
42    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-range>
43    #[no_trace]
44    range: IndexedDBKeyRange,
45    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-source>
46    source: ObjectStoreOrIndex,
47    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-direction>
48    direction: IDBCursorDirection,
49    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-position>
50    #[no_trace]
51    position: DomRefCell<Option<IndexedDBKeyType>>,
52    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-key>
53    #[no_trace]
54    key: DomRefCell<Option<IndexedDBKeyType>>,
55    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-value>
56    #[ignore_malloc_size_of = "mozjs"]
57    value: Heap<JSVal>,
58    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-got-value-flag>
59    got_value: Cell<bool>,
60    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-object-store-position>
61    #[no_trace]
62    object_store_position: DomRefCell<Option<IndexedDBKeyType>>,
63    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-key-only-flag>
64    key_only: bool,
65
66    /// <https://w3c.github.io/IndexedDB/#cursor-request>
67    request: MutNullableDom<IDBRequest>,
68}
69
70impl IDBCursor {
71    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
72    pub(crate) fn new_inherited(
73        transaction: &IDBTransaction,
74        direction: IDBCursorDirection,
75        got_value: bool,
76        source: ObjectStoreOrIndex,
77        range: IndexedDBKeyRange,
78        key_only: bool,
79    ) -> IDBCursor {
80        IDBCursor {
81            reflector_: Reflector::new(),
82            transaction: Dom::from_ref(transaction),
83            range,
84            source,
85            direction,
86            position: DomRefCell::new(None),
87            key: DomRefCell::new(None),
88            value: Heap::default(),
89            got_value: Cell::new(got_value),
90            object_store_position: DomRefCell::new(None),
91            key_only,
92            request: Default::default(),
93        }
94    }
95
96    #[expect(unused)]
97    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
98    #[allow(clippy::too_many_arguments)]
99    pub(crate) fn new(
100        global: &GlobalScope,
101        transaction: &IDBTransaction,
102        direction: IDBCursorDirection,
103        got_value: bool,
104        source: ObjectStoreOrIndex,
105        range: IndexedDBKeyRange,
106        key_only: bool,
107        can_gc: CanGc,
108    ) -> DomRoot<IDBCursor> {
109        reflect_dom_object(
110            Box::new(IDBCursor::new_inherited(
111                transaction,
112                direction,
113                got_value,
114                source,
115                range,
116                key_only,
117            )),
118            global,
119            can_gc,
120        )
121    }
122
123    pub(crate) fn value(&self, mut out: MutableHandleValue) {
124        out.set(self.value.get());
125    }
126
127    /// <https://www.w3.org/TR/IndexedDB-2/#cursor-effective-key>
128    pub(crate) fn effective_key(&self) -> Option<IndexedDBKeyType> {
129        match &self.source {
130            ObjectStoreOrIndex::ObjectStore(_) => self.position.borrow().clone(),
131            ObjectStoreOrIndex::Index(_) => self.object_store_position.borrow().clone(),
132        }
133    }
134}
135
136impl IDBCursorMethods<crate::DomTypeHolder> for IDBCursor {
137    /// <https://www.w3.org/TR/IndexedDB-2/#dom-idbcursor-source>
138    fn Source(&self) -> IDBObjectStoreOrIDBIndex {
139        match &self.source {
140            ObjectStoreOrIndex::ObjectStore(source) => {
141                IDBObjectStoreOrIDBIndex::IDBObjectStore(source.as_rooted())
142            },
143            ObjectStoreOrIndex::Index(source) => {
144                IDBObjectStoreOrIDBIndex::IDBIndex(source.as_rooted())
145            },
146        }
147    }
148
149    /// <https://www.w3.org/TR/IndexedDB-2/#dom-idbcursor-direction>
150    fn Direction(&self) -> IDBCursorDirection {
151        self.direction
152    }
153
154    /// <https://www.w3.org/TR/IndexedDB-2/#dom-idbcursor-key>
155    fn Key(&self, cx: SafeJSContext, mut value: MutableHandleValue) {
156        match self.key.borrow().as_ref() {
157            Some(key) => key_type_to_jsval(cx, key, value),
158            None => value.set(UndefinedValue()),
159        }
160    }
161
162    /// <https://www.w3.org/TR/IndexedDB-2/#dom-idbcursor-primarykey>
163    fn PrimaryKey(&self, cx: SafeJSContext, mut value: MutableHandleValue) {
164        match self.effective_key() {
165            Some(effective_key) => key_type_to_jsval(cx, &effective_key, value),
166            None => value.set(UndefinedValue()),
167        }
168    }
169
170    /// <https://w3c.github.io/IndexedDB/#dom-idbcursor-request>
171    fn Request(&self) -> DomRoot<IDBRequest> {
172        self.request
173            .get()
174            .expect("IDBCursor.request should be set when cursor is opened")
175    }
176}