1use crate::{
2 error::{mdbx_result, Error, Result},
3 flags::*,
4 mdbx_try_optional,
5 transaction::{TransactionKind, RW},
6 TableObject, Transaction,
7};
8use ffi::{
9 MDBX_cursor_op, MDBX_FIRST, MDBX_FIRST_DUP, MDBX_GET_BOTH, MDBX_GET_BOTH_RANGE,
10 MDBX_GET_CURRENT, MDBX_GET_MULTIPLE, MDBX_LAST, MDBX_LAST_DUP, MDBX_NEXT, MDBX_NEXT_DUP,
11 MDBX_NEXT_MULTIPLE, MDBX_NEXT_NODUP, MDBX_PREV, MDBX_PREV_DUP, MDBX_PREV_MULTIPLE,
12 MDBX_PREV_NODUP, MDBX_SET, MDBX_SET_KEY, MDBX_SET_LOWERBOUND, MDBX_SET_RANGE,
13};
14use std::{borrow::Cow, ffi::c_void, fmt, marker::PhantomData, mem, ptr};
15
16pub struct Cursor<K>
18where
19 K: TransactionKind,
20{
21 txn: Transaction<K>,
22 cursor: *mut ffi::MDBX_cursor,
23}
24
25impl<K> Cursor<K>
26where
27 K: TransactionKind,
28{
29 pub(crate) fn new(txn: Transaction<K>, dbi: ffi::MDBX_dbi) -> Result<Self> {
30 let mut cursor: *mut ffi::MDBX_cursor = ptr::null_mut();
31 unsafe {
32 txn.txn_execute(|txn_ptr| {
33 mdbx_result(ffi::mdbx_cursor_open(txn_ptr, dbi, &mut cursor))
34 })??;
35 }
36 Ok(Self { txn, cursor })
37 }
38
39 fn new_at_position(other: &Self) -> Result<Self> {
40 unsafe {
41 let cursor = ffi::mdbx_cursor_create(ptr::null_mut());
42
43 let res = ffi::mdbx_cursor_copy(other.cursor(), cursor);
44
45 let s = Self { txn: other.txn.clone(), cursor };
46
47 mdbx_result(res)?;
48
49 Ok(s)
50 }
51 }
52
53 pub const fn cursor(&self) -> *mut ffi::MDBX_cursor {
58 self.cursor
59 }
60
61 pub fn iter_slices<'a>(self) -> IntoIter<K, Cow<'a, [u8]>, Cow<'a, [u8]>> {
63 self.into_iter()
64 }
65
66 #[expect(clippy::should_implement_trait)]
68 pub fn into_iter<Key, Value>(self) -> IntoIter<K, Key, Value>
69 where
70 Key: TableObject,
71 Value: TableObject,
72 {
73 IntoIter::new(self, MDBX_NEXT, MDBX_NEXT)
74 }
75
76 fn get<Key, Value>(
79 &self,
80 key: Option<&[u8]>,
81 data: Option<&[u8]>,
82 op: MDBX_cursor_op,
83 ) -> Result<(Option<Key>, Value, bool)>
84 where
85 Key: TableObject,
86 Value: TableObject,
87 {
88 unsafe {
89 let mut key_val = slice_to_val(key);
90 let mut data_val = slice_to_val(data);
91 let key_ptr = key_val.iov_base;
92 let data_ptr = data_val.iov_base;
93 self.txn.txn_execute(|txn| {
94 let v = mdbx_result(ffi::mdbx_cursor_get(
95 self.cursor,
96 &mut key_val,
97 &mut data_val,
98 op,
99 ))?;
100 assert_ne!(data_ptr, data_val.iov_base);
101 let key_out = {
102 if ptr::eq(key_ptr, key_val.iov_base) {
104 None
105 } else {
106 Some(Key::decode_val::<K>(txn, key_val)?)
107 }
108 };
109 let data_out = Value::decode_val::<K>(txn, data_val)?;
110 Ok((key_out, data_out, v))
111 })?
112 }
113 }
114
115 fn get_value<Value>(
116 &mut self,
117 key: Option<&[u8]>,
118 data: Option<&[u8]>,
119 op: MDBX_cursor_op,
120 ) -> Result<Option<Value>>
121 where
122 Value: TableObject,
123 {
124 let (_, v, _) = mdbx_try_optional!(self.get::<(), Value>(key, data, op));
125
126 Ok(Some(v))
127 }
128
129 fn get_full<Key, Value>(
130 &mut self,
131 key: Option<&[u8]>,
132 data: Option<&[u8]>,
133 op: MDBX_cursor_op,
134 ) -> Result<Option<(Key, Value)>>
135 where
136 Key: TableObject,
137 Value: TableObject,
138 {
139 let (k, v, _) = mdbx_try_optional!(self.get(key, data, op));
140
141 Ok(Some((k.unwrap(), v)))
142 }
143
144 pub fn first<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
146 where
147 Key: TableObject,
148 Value: TableObject,
149 {
150 self.get_full(None, None, MDBX_FIRST)
151 }
152
153 pub fn first_dup<Value>(&mut self) -> Result<Option<Value>>
155 where
156 Value: TableObject,
157 {
158 self.get_value(None, None, MDBX_FIRST_DUP)
159 }
160
161 pub fn get_both<Value>(&mut self, k: &[u8], v: &[u8]) -> Result<Option<Value>>
163 where
164 Value: TableObject,
165 {
166 self.get_value(Some(k), Some(v), MDBX_GET_BOTH)
167 }
168
169 pub fn get_both_range<Value>(&mut self, k: &[u8], v: &[u8]) -> Result<Option<Value>>
172 where
173 Value: TableObject,
174 {
175 self.get_value(Some(k), Some(v), MDBX_GET_BOTH_RANGE)
176 }
177
178 pub fn get_current<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
180 where
181 Key: TableObject,
182 Value: TableObject,
183 {
184 self.get_full(None, None, MDBX_GET_CURRENT)
185 }
186
187 pub fn get_multiple<Value>(&mut self) -> Result<Option<Value>>
190 where
191 Value: TableObject,
192 {
193 self.get_value(None, None, MDBX_GET_MULTIPLE)
194 }
195
196 pub fn last<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
198 where
199 Key: TableObject,
200 Value: TableObject,
201 {
202 self.get_full(None, None, MDBX_LAST)
203 }
204
205 pub fn last_dup<Value>(&mut self) -> Result<Option<Value>>
207 where
208 Value: TableObject,
209 {
210 self.get_value(None, None, MDBX_LAST_DUP)
211 }
212
213 #[expect(clippy::should_implement_trait)]
215 pub fn next<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
216 where
217 Key: TableObject,
218 Value: TableObject,
219 {
220 self.get_full(None, None, MDBX_NEXT)
221 }
222
223 pub fn next_dup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
225 where
226 Key: TableObject,
227 Value: TableObject,
228 {
229 self.get_full(None, None, MDBX_NEXT_DUP)
230 }
231
232 pub fn next_multiple<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
235 where
236 Key: TableObject,
237 Value: TableObject,
238 {
239 self.get_full(None, None, MDBX_NEXT_MULTIPLE)
240 }
241
242 pub fn next_nodup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
244 where
245 Key: TableObject,
246 Value: TableObject,
247 {
248 self.get_full(None, None, MDBX_NEXT_NODUP)
249 }
250
251 pub fn prev<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
253 where
254 Key: TableObject,
255 Value: TableObject,
256 {
257 self.get_full(None, None, MDBX_PREV)
258 }
259
260 pub fn prev_dup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
262 where
263 Key: TableObject,
264 Value: TableObject,
265 {
266 self.get_full(None, None, MDBX_PREV_DUP)
267 }
268
269 pub fn prev_nodup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
271 where
272 Key: TableObject,
273 Value: TableObject,
274 {
275 self.get_full(None, None, MDBX_PREV_NODUP)
276 }
277
278 pub fn set<Value>(&mut self, key: &[u8]) -> Result<Option<Value>>
280 where
281 Value: TableObject,
282 {
283 self.get_value(Some(key), None, MDBX_SET)
284 }
285
286 pub fn set_key<Key, Value>(&mut self, key: &[u8]) -> Result<Option<(Key, Value)>>
288 where
289 Key: TableObject,
290 Value: TableObject,
291 {
292 self.get_full(Some(key), None, MDBX_SET_KEY)
293 }
294
295 pub fn set_range<Key, Value>(&mut self, key: &[u8]) -> Result<Option<(Key, Value)>>
297 where
298 Key: TableObject,
299 Value: TableObject,
300 {
301 self.get_full(Some(key), None, MDBX_SET_RANGE)
302 }
303
304 pub fn prev_multiple<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
307 where
308 Key: TableObject,
309 Value: TableObject,
310 {
311 self.get_full(None, None, MDBX_PREV_MULTIPLE)
312 }
313
314 pub fn set_lowerbound<Key, Value>(&mut self, key: &[u8]) -> Result<Option<(bool, Key, Value)>>
324 where
325 Key: TableObject,
326 Value: TableObject,
327 {
328 let (k, v, found) = mdbx_try_optional!(self.get(Some(key), None, MDBX_SET_LOWERBOUND));
329
330 Ok(Some((found, k.unwrap(), v)))
331 }
332
333 pub fn iter<Key, Value>(&mut self) -> Iter<'_, K, Key, Value>
342 where
343 Key: TableObject,
344 Value: TableObject,
345 {
346 Iter::new(self, ffi::MDBX_NEXT, ffi::MDBX_NEXT)
347 }
348
349 pub fn iter_start<Key, Value>(&mut self) -> Iter<'_, K, Key, Value>
355 where
356 Key: TableObject,
357 Value: TableObject,
358 {
359 Iter::new(self, ffi::MDBX_FIRST, ffi::MDBX_NEXT)
360 }
361
362 pub fn iter_from<Key, Value>(&mut self, key: &[u8]) -> Iter<'_, K, Key, Value>
368 where
369 Key: TableObject,
370 Value: TableObject,
371 {
372 let res: Result<Option<((), ())>> = self.set_range(key);
373 if let Err(error) = res {
374 return Iter::Err(Some(error))
375 };
376 Iter::new(self, ffi::MDBX_GET_CURRENT, ffi::MDBX_NEXT)
377 }
378
379 pub fn iter_dup<Key, Value>(&mut self) -> IterDup<'_, K, Key, Value>
383 where
384 Key: TableObject,
385 Value: TableObject,
386 {
387 IterDup::new(self, ffi::MDBX_NEXT)
388 }
389
390 pub fn iter_dup_start<Key, Value>(&mut self) -> IterDup<'_, K, Key, Value>
393 where
394 Key: TableObject,
395 Value: TableObject,
396 {
397 IterDup::new(self, ffi::MDBX_FIRST)
398 }
399
400 pub fn iter_dup_from<Key, Value>(&mut self, key: &[u8]) -> IterDup<'_, K, Key, Value>
403 where
404 Key: TableObject,
405 Value: TableObject,
406 {
407 let res: Result<Option<((), ())>> = self.set_range(key);
408 if let Err(error) = res {
409 return IterDup::Err(Some(error))
410 };
411 IterDup::new(self, ffi::MDBX_GET_CURRENT)
412 }
413
414 pub fn iter_dup_of<Key, Value>(&mut self, key: &[u8]) -> Iter<'_, K, Key, Value>
416 where
417 Key: TableObject,
418 Value: TableObject,
419 {
420 let res: Result<Option<()>> = self.set(key);
421 match res {
422 Ok(Some(_)) => (),
423 Ok(None) => {
424 let _: Result<Option<((), ())>> = self.last();
425 return Iter::new(self, ffi::MDBX_NEXT, ffi::MDBX_NEXT)
426 }
427 Err(error) => return Iter::Err(Some(error)),
428 };
429 Iter::new(self, ffi::MDBX_GET_CURRENT, ffi::MDBX_NEXT_DUP)
430 }
431}
432
433impl Cursor<RW> {
434 pub fn put(&mut self, key: &[u8], data: &[u8], flags: WriteFlags) -> Result<()> {
437 let key_val: ffi::MDBX_val =
438 ffi::MDBX_val { iov_len: key.len(), iov_base: key.as_ptr() as *mut c_void };
439 let mut data_val: ffi::MDBX_val =
440 ffi::MDBX_val { iov_len: data.len(), iov_base: data.as_ptr() as *mut c_void };
441 mdbx_result(unsafe {
442 self.txn.txn_execute(|_| {
443 ffi::mdbx_cursor_put(self.cursor, &key_val, &mut data_val, flags.bits())
444 })?
445 })?;
446
447 Ok(())
448 }
449
450 pub fn del(&mut self, flags: WriteFlags) -> Result<()> {
457 mdbx_result(unsafe {
458 self.txn.txn_execute(|_| ffi::mdbx_cursor_del(self.cursor, flags.bits()))?
459 })?;
460
461 Ok(())
462 }
463}
464
465impl<K> Clone for Cursor<K>
466where
467 K: TransactionKind,
468{
469 fn clone(&self) -> Self {
470 self.txn.txn_execute(|_| Self::new_at_position(self).unwrap()).unwrap()
471 }
472}
473
474impl<K> fmt::Debug for Cursor<K>
475where
476 K: TransactionKind,
477{
478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479 f.debug_struct("Cursor").finish_non_exhaustive()
480 }
481}
482
483impl<K> Drop for Cursor<K>
484where
485 K: TransactionKind,
486{
487 fn drop(&mut self) {
488 let _ = self
491 .txn
492 .txn_execute_renew_on_timeout(|_| unsafe { ffi::mdbx_cursor_close(self.cursor) });
493 }
494}
495
496const unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDBX_val {
497 match slice {
498 Some(slice) => {
499 ffi::MDBX_val { iov_len: slice.len(), iov_base: slice.as_ptr() as *mut c_void }
500 }
501 None => ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() },
502 }
503}
504
505unsafe impl<K> Send for Cursor<K> where K: TransactionKind {}
506unsafe impl<K> Sync for Cursor<K> where K: TransactionKind {}
507
508#[derive(Debug)]
510pub enum IntoIter<K, Key, Value>
511where
512 K: TransactionKind,
513 Key: TableObject,
514 Value: TableObject,
515{
516 Err(Option<Error>),
522
523 Ok {
528 cursor: Cursor<K>,
530
531 op: ffi::MDBX_cursor_op,
533
534 next_op: ffi::MDBX_cursor_op,
536
537 _marker: PhantomData<(Key, Value)>,
538 },
539}
540
541impl<K, Key, Value> IntoIter<K, Key, Value>
542where
543 K: TransactionKind,
544 Key: TableObject,
545 Value: TableObject,
546{
547 fn new(cursor: Cursor<K>, op: ffi::MDBX_cursor_op, next_op: ffi::MDBX_cursor_op) -> Self {
549 Self::Ok { cursor, op, next_op, _marker: Default::default() }
550 }
551}
552
553impl<K, Key, Value> Iterator for IntoIter<K, Key, Value>
554where
555 K: TransactionKind,
556 Key: TableObject,
557 Value: TableObject,
558{
559 type Item = Result<(Key, Value)>;
560
561 fn next(&mut self) -> Option<Self::Item> {
562 match self {
563 Self::Ok { cursor, op, next_op, .. } => {
564 let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
565 let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
566 let op = mem::replace(op, *next_op);
567 unsafe {
568 let result = cursor.txn.txn_execute(|txn| {
569 match ffi::mdbx_cursor_get(cursor.cursor(), &mut key, &mut data, op) {
570 ffi::MDBX_SUCCESS => {
571 let key = match Key::decode_val::<K>(txn, key) {
572 Ok(v) => v,
573 Err(e) => return Some(Err(e)),
574 };
575 let data = match Value::decode_val::<K>(txn, data) {
576 Ok(v) => v,
577 Err(e) => return Some(Err(e)),
578 };
579 Some(Ok((key, data)))
580 }
581 ffi::MDBX_NOTFOUND | ffi::MDBX_ENODATA => None,
585 error => Some(Err(Error::from_err_code(error))),
586 }
587 });
588 match result {
589 Ok(result) => result,
590 Err(err) => Some(Err(err)),
591 }
592 }
593 }
594 Self::Err(err) => err.take().map(Err),
595 }
596 }
597}
598
599#[derive(Debug)]
601pub enum Iter<'cur, K, Key, Value>
602where
603 K: TransactionKind,
604 Key: TableObject,
605 Value: TableObject,
606{
607 Err(Option<Error>),
613
614 Ok {
619 cursor: &'cur mut Cursor<K>,
621
622 op: ffi::MDBX_cursor_op,
624
625 next_op: ffi::MDBX_cursor_op,
627
628 _marker: PhantomData<fn(&'cur (), K, Key, Value)>,
629 },
630}
631
632impl<'cur, K, Key, Value> Iter<'cur, K, Key, Value>
633where
634 K: TransactionKind,
635 Key: TableObject,
636 Value: TableObject,
637{
638 fn new(
640 cursor: &'cur mut Cursor<K>,
641 op: ffi::MDBX_cursor_op,
642 next_op: ffi::MDBX_cursor_op,
643 ) -> Self {
644 Iter::Ok { cursor, op, next_op, _marker: Default::default() }
645 }
646}
647
648impl<K, Key, Value> Iterator for Iter<'_, K, Key, Value>
649where
650 K: TransactionKind,
651 Key: TableObject,
652 Value: TableObject,
653{
654 type Item = Result<(Key, Value)>;
655
656 fn next(&mut self) -> Option<Self::Item> {
657 match self {
658 Iter::Ok { cursor, op, next_op, .. } => {
659 let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
660 let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
661 let op = mem::replace(op, *next_op);
662 unsafe {
663 let result = cursor.txn.txn_execute(|txn| {
664 match ffi::mdbx_cursor_get(cursor.cursor(), &mut key, &mut data, op) {
665 ffi::MDBX_SUCCESS => {
666 let key = match Key::decode_val::<K>(txn, key) {
667 Ok(v) => v,
668 Err(e) => return Some(Err(e)),
669 };
670 let data = match Value::decode_val::<K>(txn, data) {
671 Ok(v) => v,
672 Err(e) => return Some(Err(e)),
673 };
674 Some(Ok((key, data)))
675 }
676 ffi::MDBX_NOTFOUND | ffi::MDBX_ENODATA => None,
680 error => Some(Err(Error::from_err_code(error))),
681 }
682 });
683 match result {
684 Ok(result) => result,
685 Err(err) => Some(Err(err)),
686 }
687 }
688 }
689 Iter::Err(err) => err.take().map(Err),
690 }
691 }
692}
693
694pub enum IterDup<'cur, K, Key, Value>
699where
700 K: TransactionKind,
701 Key: TableObject,
702 Value: TableObject,
703{
704 Err(Option<Error>),
710
711 Ok {
716 cursor: &'cur mut Cursor<K>,
718
719 op: MDBX_cursor_op,
721
722 _marker: PhantomData<fn(&'cur (Key, Value))>,
723 },
724}
725
726impl<'cur, K, Key, Value> IterDup<'cur, K, Key, Value>
727where
728 K: TransactionKind,
729 Key: TableObject,
730 Value: TableObject,
731{
732 fn new(cursor: &'cur mut Cursor<K>, op: MDBX_cursor_op) -> Self {
734 IterDup::Ok { cursor, op, _marker: Default::default() }
735 }
736}
737
738impl<K, Key, Value> fmt::Debug for IterDup<'_, K, Key, Value>
739where
740 K: TransactionKind,
741 Key: TableObject,
742 Value: TableObject,
743{
744 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745 f.debug_struct("IterDup").finish()
746 }
747}
748
749impl<K, Key, Value> Iterator for IterDup<'_, K, Key, Value>
750where
751 K: TransactionKind,
752 Key: TableObject,
753 Value: TableObject,
754{
755 type Item = IntoIter<K, Key, Value>;
756
757 fn next(&mut self) -> Option<Self::Item> {
758 match self {
759 IterDup::Ok { cursor, op, .. } => {
760 let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
761 let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
762 let op = mem::replace(op, ffi::MDBX_NEXT_NODUP);
763
764 let result = cursor.txn.txn_execute(|_| {
765 let err_code =
766 unsafe { ffi::mdbx_cursor_get(cursor.cursor(), &mut key, &mut data, op) };
767
768 (err_code == ffi::MDBX_SUCCESS).then(|| {
769 IntoIter::new(
770 Cursor::new_at_position(&**cursor).unwrap(),
771 ffi::MDBX_GET_CURRENT,
772 ffi::MDBX_NEXT_DUP,
773 )
774 })
775 });
776
777 match result {
778 Ok(result) => result,
779 Err(err) => Some(IntoIter::Err(Some(err))),
780 }
781 }
782 IterDup::Err(err) => err.take().map(|e| IntoIter::Err(Some(e))),
783 }
784 }
785}