1use 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 transaction: Dom<IDBTransaction>,
42 #[no_trace]
44 range: IndexedDBKeyRange,
45 source: ObjectStoreOrIndex,
47 direction: IDBCursorDirection,
49 #[no_trace]
51 position: DomRefCell<Option<IndexedDBKeyType>>,
52 #[no_trace]
54 key: DomRefCell<Option<IndexedDBKeyType>>,
55 #[ignore_malloc_size_of = "mozjs"]
57 value: Heap<JSVal>,
58 got_value: Cell<bool>,
60 #[no_trace]
62 object_store_position: DomRefCell<Option<IndexedDBKeyType>>,
63 key_only: bool,
65
66 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 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 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 fn Direction(&self) -> IDBCursorDirection {
151 self.direction
152 }
153
154 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 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 fn Request(&self) -> DomRoot<IDBRequest> {
172 self.request
173 .get()
174 .expect("IDBCursor.request should be set when cursor is opened")
175 }
176}