1use std::ops::{Deref, DerefMut};
2use std::{marker, mem, ptr};
3
4use crate::mdb::error::mdb_result;
5use crate::mdb::ffi;
6use crate::*;
7
8pub struct RoCursor<'txn> {
9 cursor: *mut ffi::MDB_cursor,
10 _marker: marker::PhantomData<&'txn ()>,
11}
12
13impl<'txn> RoCursor<'txn> {
14 pub(crate) fn new(txn: &'txn RoTxn, dbi: ffi::MDB_dbi) -> Result<RoCursor<'txn>> {
15 let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
16 unsafe { mdb_result(ffi::mdb_cursor_open(txn.txn, dbi, &mut cursor))? }
17 Ok(RoCursor { cursor, _marker: marker::PhantomData })
18 }
19
20 pub fn current(&mut self) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
21 let mut key_val = mem::MaybeUninit::uninit();
22 let mut data_val = mem::MaybeUninit::uninit();
23
24 let result = unsafe {
26 mdb_result(ffi::mdb_cursor_get(
27 self.cursor,
28 key_val.as_mut_ptr(),
29 data_val.as_mut_ptr(),
30 ffi::cursor_op::MDB_GET_CURRENT,
31 ))
32 };
33
34 match result {
35 Ok(()) => {
36 let key = unsafe { crate::from_val(key_val.assume_init()) };
37 let data = unsafe { crate::from_val(data_val.assume_init()) };
38 Ok(Some((key, data)))
39 }
40 Err(e) if e.not_found() => Ok(None),
41 Err(e) => Err(e.into()),
42 }
43 }
44
45 pub fn move_on_first(&mut self, op: MoveOperation) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
46 let mut key_val = mem::MaybeUninit::uninit();
47 let mut data_val = mem::MaybeUninit::uninit();
48
49 let flag = match op {
50 MoveOperation::Any => ffi::cursor_op::MDB_FIRST,
51 MoveOperation::Dup => {
52 unsafe {
53 mdb_result(ffi::mdb_cursor_get(
54 self.cursor,
55 ptr::null_mut(),
56 &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() },
57 ffi::cursor_op::MDB_FIRST_DUP,
58 ))?
59 };
60 ffi::cursor_op::MDB_GET_CURRENT
61 }
62 MoveOperation::NoDup => ffi::cursor_op::MDB_FIRST,
63 };
64
65 let result = unsafe {
67 mdb_result(ffi::mdb_cursor_get(
68 self.cursor,
69 key_val.as_mut_ptr(),
70 data_val.as_mut_ptr(),
71 flag,
72 ))
73 };
74
75 match result {
76 Ok(()) => {
77 let key = unsafe { crate::from_val(key_val.assume_init()) };
78 let data = unsafe { crate::from_val(data_val.assume_init()) };
79 Ok(Some((key, data)))
80 }
81 Err(e) if e.not_found() => Ok(None),
82 Err(e) => Err(e.into()),
83 }
84 }
85
86 pub fn move_on_last(&mut self, op: MoveOperation) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
87 let mut key_val = mem::MaybeUninit::uninit();
88 let mut data_val = mem::MaybeUninit::uninit();
89
90 let flag = match op {
91 MoveOperation::Any => ffi::cursor_op::MDB_LAST,
92 MoveOperation::Dup => {
93 unsafe {
94 mdb_result(ffi::mdb_cursor_get(
95 self.cursor,
96 ptr::null_mut(),
97 &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() },
98 ffi::cursor_op::MDB_LAST_DUP,
99 ))?
100 };
101 ffi::cursor_op::MDB_GET_CURRENT
102 }
103 MoveOperation::NoDup => ffi::cursor_op::MDB_LAST,
104 };
105
106 let result = unsafe {
108 mdb_result(ffi::mdb_cursor_get(
109 self.cursor,
110 key_val.as_mut_ptr(),
111 data_val.as_mut_ptr(),
112 flag,
113 ))
114 };
115
116 match result {
117 Ok(()) => {
118 let key = unsafe { crate::from_val(key_val.assume_init()) };
119 let data = unsafe { crate::from_val(data_val.assume_init()) };
120 Ok(Some((key, data)))
121 }
122 Err(e) if e.not_found() => Ok(None),
123 Err(e) => Err(e.into()),
124 }
125 }
126
127 pub fn move_on_key(&mut self, key: &[u8]) -> Result<bool> {
128 let mut key_val = unsafe { crate::into_val(key) };
129
130 let result = unsafe {
132 mdb_result(ffi::mdb_cursor_get(
133 self.cursor,
134 &mut key_val,
135 &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() },
136 ffi::cursor_op::MDB_SET,
137 ))
138 };
139
140 match result {
141 Ok(()) => Ok(true),
142 Err(e) if e.not_found() => Ok(false),
143 Err(e) => Err(e.into()),
144 }
145 }
146
147 pub fn move_on_key_greater_than_or_equal_to(
148 &mut self,
149 key: &[u8],
150 ) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
151 let mut key_val = unsafe { crate::into_val(key) };
152 let mut data_val = mem::MaybeUninit::uninit();
153
154 let result = unsafe {
156 mdb_result(ffi::mdb_cursor_get(
157 self.cursor,
158 &mut key_val,
159 data_val.as_mut_ptr(),
160 ffi::cursor_op::MDB_SET_RANGE,
161 ))
162 };
163
164 match result {
165 Ok(()) => {
166 let key = unsafe { crate::from_val(key_val) };
167 let data = unsafe { crate::from_val(data_val.assume_init()) };
168 Ok(Some((key, data)))
169 }
170 Err(e) if e.not_found() => Ok(None),
171 Err(e) => Err(e.into()),
172 }
173 }
174
175 pub fn move_on_prev(&mut self, op: MoveOperation) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
176 let mut key_val = mem::MaybeUninit::uninit();
177 let mut data_val = mem::MaybeUninit::uninit();
178
179 let flag = match op {
180 MoveOperation::Any => ffi::cursor_op::MDB_PREV,
181 MoveOperation::Dup => ffi::cursor_op::MDB_PREV_DUP,
182 MoveOperation::NoDup => ffi::cursor_op::MDB_PREV_NODUP,
183 };
184
185 let result = unsafe {
187 mdb_result(ffi::mdb_cursor_get(
188 self.cursor,
189 key_val.as_mut_ptr(),
190 data_val.as_mut_ptr(),
191 flag,
192 ))
193 };
194
195 match result {
196 Ok(()) => {
197 let key = unsafe { crate::from_val(key_val.assume_init()) };
198 let data = unsafe { crate::from_val(data_val.assume_init()) };
199 Ok(Some((key, data)))
200 }
201 Err(e) if e.not_found() => Ok(None),
202 Err(e) => Err(e.into()),
203 }
204 }
205
206 pub fn move_on_next(&mut self, op: MoveOperation) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
207 let mut key_val = mem::MaybeUninit::uninit();
208 let mut data_val = mem::MaybeUninit::uninit();
209
210 let flag = match op {
211 MoveOperation::Any => ffi::cursor_op::MDB_NEXT,
212 MoveOperation::Dup => ffi::cursor_op::MDB_NEXT_DUP,
213 MoveOperation::NoDup => ffi::cursor_op::MDB_NEXT_NODUP,
214 };
215
216 let result = unsafe {
218 mdb_result(ffi::mdb_cursor_get(
219 self.cursor,
220 key_val.as_mut_ptr(),
221 data_val.as_mut_ptr(),
222 flag,
223 ))
224 };
225
226 match result {
227 Ok(()) => {
228 let key = unsafe { crate::from_val(key_val.assume_init()) };
229 let data = unsafe { crate::from_val(data_val.assume_init()) };
230 Ok(Some((key, data)))
231 }
232 Err(e) if e.not_found() => Ok(None),
233 Err(e) => Err(e.into()),
234 }
235 }
236}
237
238impl Drop for RoCursor<'_> {
239 fn drop(&mut self) {
240 unsafe { ffi::mdb_cursor_close(self.cursor) }
241 }
242}
243
244pub struct RwCursor<'txn> {
245 cursor: RoCursor<'txn>,
246}
247
248impl<'txn> RwCursor<'txn> {
249 pub(crate) fn new(txn: &'txn RwTxn, dbi: ffi::MDB_dbi) -> Result<RwCursor<'txn>> {
250 Ok(RwCursor { cursor: RoCursor::new(txn, dbi)? })
251 }
252
253 pub unsafe fn del_current(&mut self) -> Result<bool> {
267 let result = mdb_result(ffi::mdb_cursor_del(self.cursor.cursor, 0));
269
270 match result {
271 Ok(()) => Ok(true),
272 Err(e) if e.not_found() => Ok(false),
273 Err(e) => Err(e.into()),
274 }
275 }
276
277 pub unsafe fn put_current(&mut self, key: &[u8], data: &[u8]) -> Result<bool> {
301 let mut key_val = crate::into_val(key);
302 let mut data_val = crate::into_val(data);
303
304 let result = mdb_result(ffi::mdb_cursor_put(
306 self.cursor.cursor,
307 &mut key_val,
308 &mut data_val,
309 ffi::MDB_CURRENT,
310 ));
311
312 match result {
313 Ok(()) => Ok(true),
314 Err(e) if e.not_found() => Ok(false),
315 Err(e) => Err(e.into()),
316 }
317 }
318
319 pub unsafe fn put_current_reserved_with_flags<F>(
333 &mut self,
334 flags: PutFlags,
335 key: &[u8],
336 data_size: usize,
337 write_func: F,
338 ) -> Result<bool>
339 where
340 F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
341 {
342 let mut key_val = crate::into_val(key);
343 let mut reserved = ffi::reserve_size_val(data_size);
344 let flags = ffi::MDB_RESERVE | flags.bits();
345
346 let result =
347 mdb_result(ffi::mdb_cursor_put(self.cursor.cursor, &mut key_val, &mut reserved, flags));
348
349 let found = match result {
350 Ok(()) => true,
351 Err(e) if e.not_found() => false,
352 Err(e) => return Err(e.into()),
353 };
354
355 let mut reserved = ReservedSpace::from_val(reserved);
356 write_func(&mut reserved)?;
357
358 if reserved.remaining() == 0 {
359 Ok(found)
360 } else {
361 Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
362 }
363 }
364
365 pub unsafe fn put_current_with_flags(
384 &mut self,
385 flags: PutFlags,
386 key: &[u8],
387 data: &[u8],
388 ) -> Result<()> {
389 let mut key_val = crate::into_val(key);
390 let mut data_val = crate::into_val(data);
391
392 let result = mdb_result(ffi::mdb_cursor_put(
394 self.cursor.cursor,
395 &mut key_val,
396 &mut data_val,
397 flags.bits(),
398 ));
399
400 result.map_err(Into::into)
401 }
402}
403
404impl<'txn> Deref for RwCursor<'txn> {
405 type Target = RoCursor<'txn>;
406
407 fn deref(&self) -> &Self::Target {
408 &self.cursor
409 }
410}
411
412impl DerefMut for RwCursor<'_> {
413 fn deref_mut(&mut self) -> &mut Self::Target {
414 &mut self.cursor
415 }
416}
417
418#[derive(Debug, Clone, Copy)]
420pub enum MoveOperation {
421 Any,
423 Dup,
425 NoDup,
428}