|
1 | 1 | use std::borrow::Cow; |
2 | 2 | use std::marker; |
3 | 3 |
|
4 | | -use types::LazyDecode; |
| 4 | +use types::{Lazy, LazyDecode}; |
5 | 5 |
|
6 | 6 | use crate::iteration_method::{IterationMethod, MoveBetweenKeys, MoveThroughDuplicateValues}; |
7 | 7 | use crate::*; |
@@ -437,6 +437,185 @@ impl<KC, DC, IM> fmt::Debug for RwIter<'_, KC, DC, IM> { |
437 | 437 | } |
438 | 438 | } |
439 | 439 |
|
| 440 | +pub struct RwIterItem<'a, 'txn, KC, DC, IM = MoveThroughDuplicateValues> { |
| 441 | + iter: &'a mut RwIter<'txn, KC, DC, IM>, |
| 442 | + key: &'txn [u8], |
| 443 | + data: &'txn [u8], |
| 444 | +} |
| 445 | + |
| 446 | +impl<'a, 'txn, KC, DC, IM> RwIterItem<'a, 'txn, KC, DC, IM> { |
| 447 | + /// Get the key at the current cursor, which is valid for at least as long |
| 448 | + /// as the `RwIterItem` exists. |
| 449 | + pub fn key<'b>(&'b self) -> Lazy<'b, KC> |
| 450 | + where |
| 451 | + KC: 'static, |
| 452 | + { |
| 453 | + LazyDecode::<KC>::bytes_decode(self.key).unwrap() |
| 454 | + } |
| 455 | + |
| 456 | + /// Get the data at the current cursor, which is valid for at least as long |
| 457 | + /// as the `RwIterItem` exists. |
| 458 | + pub fn data<'b>(&'b self) -> Lazy<'b, DC> |
| 459 | + where |
| 460 | + DC: 'static, |
| 461 | + { |
| 462 | + LazyDecode::<DC>::bytes_decode(self.data).unwrap() |
| 463 | + } |
| 464 | + |
| 465 | + /// Keep the entry the cursor is currently pointing to. |
| 466 | + /// Returns the key and data at the current cursor, which are valid until |
| 467 | + /// the end of the transaction. |
| 468 | + pub fn keep(self) -> (Lazy<'txn, KC>, Lazy<'txn, DC>) |
| 469 | + where |
| 470 | + KC: 'static, |
| 471 | + DC: 'static, |
| 472 | + { |
| 473 | + let key = LazyDecode::<KC>::bytes_decode(self.key).unwrap(); |
| 474 | + let data = LazyDecode::<DC>::bytes_decode(self.data).unwrap(); |
| 475 | + (key, data) |
| 476 | + } |
| 477 | + |
| 478 | + /// Delete the entry the cursor is currently pointing to. |
| 479 | + /// |
| 480 | + /// Returns `true`` if the entry was successfully deleted. |
| 481 | + pub fn delete(self) -> Result<bool> { |
| 482 | + // SAFETY: It is not possible to keep reference to the current value |
| 483 | + // after deleting, because this method takes `self` by value, and |
| 484 | + // the current key / value are only available for the lifetime of |
| 485 | + // `self`. |
| 486 | + unsafe { self.iter.del_current() } |
| 487 | + } |
| 488 | + |
| 489 | + /// Write a new value to the current entry. The entry is written with the specified flags. |
| 490 | + /// |
| 491 | + /// > This is intended to be used when the new data is the same size as the old. |
| 492 | + /// > Otherwise it will simply perform a delete of the old record followed by an insert. |
| 493 | + pub fn put_reserved_with_flags<F>( |
| 494 | + mut self, |
| 495 | + flags: PutFlags, |
| 496 | + data_size: usize, |
| 497 | + write_func: F, |
| 498 | + ) -> Result<Self> |
| 499 | + where |
| 500 | + F: FnOnce(&mut ReservedSpace<'_>) -> io::Result<()>, |
| 501 | + { |
| 502 | + let key_owned: Vec<u8> = self.key.to_owned(); |
| 503 | + // SAFETY: The key is owned, and `write_func` cannot use a reference |
| 504 | + // from this entry while modifying it, because this method takes `self` |
| 505 | + // by value, and the current key / value are only available for the |
| 506 | + // lifetime of `self`. |
| 507 | + if unsafe { |
| 508 | + self.iter.cursor.put_current_reserved_with_flags( |
| 509 | + flags, |
| 510 | + key_owned.as_slice(), |
| 511 | + data_size, |
| 512 | + write_func, |
| 513 | + ) |
| 514 | + }? { |
| 515 | + let (key, data) = self.iter.cursor.current()?.ok_or(Error::Mdb(MdbError::NotFound))?; |
| 516 | + self.key = key; |
| 517 | + self.data = data; |
| 518 | + Ok(self) |
| 519 | + } else { |
| 520 | + Err(Error::Mdb(MdbError::NotFound)) |
| 521 | + } |
| 522 | + } |
| 523 | + |
| 524 | + /// Insert a key-value pair in this database. |
| 525 | + /// The entry is written with the specified flags and data codec. |
| 526 | + pub fn put_with_options<'b, NDC>( |
| 527 | + mut self, |
| 528 | + flags: PutFlags, |
| 529 | + data: &'b NDC::EItem, |
| 530 | + ) -> Result<Self> |
| 531 | + where |
| 532 | + NDC: BytesEncode<'b>, |
| 533 | + { |
| 534 | + let key_owned: Vec<u8> = self.key.to_owned(); |
| 535 | + let data_bytes: Cow<[u8]> = NDC::bytes_encode(data).map_err(Error::Encoding)?; |
| 536 | + // SAFETY: The key is owned, and `data` cannot use a reference |
| 537 | + // from this entry while modifying it, because this method takes `self` |
| 538 | + // by value, and the current key / value are only available for the |
| 539 | + // lifetime of `self`. |
| 540 | + let () = unsafe { |
| 541 | + self.iter.cursor.put_current_with_flags(flags, key_owned.as_slice(), &data_bytes) |
| 542 | + }?; |
| 543 | + let (key, data) = self.iter.cursor.current()?.ok_or(Error::Mdb(MdbError::NotFound))?; |
| 544 | + self.key = key; |
| 545 | + self.data = data; |
| 546 | + Ok(self) |
| 547 | + } |
| 548 | + |
| 549 | + /// Write a new value to the current entry. |
| 550 | + /// |
| 551 | + /// > This is intended to be used when the new data is the same size as the old. |
| 552 | + /// > Otherwise it will simply perform a delete of the old record followed by an insert. |
| 553 | + pub fn put<'b>(mut self, data: &'b DC::EItem) -> Result<Self> |
| 554 | + where |
| 555 | + DC: BytesEncode<'b>, |
| 556 | + { |
| 557 | + let key_owned: Vec<u8> = self.key.to_owned(); |
| 558 | + let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?; |
| 559 | + // SAFETY: The key is owned, and `data` cannot use a reference |
| 560 | + // from this entry while modifying it, because this method takes `self` |
| 561 | + // by value, and the current key / value are only available for the |
| 562 | + // lifetime of `self`. |
| 563 | + if unsafe { self.iter.cursor.put_current(key_owned.as_slice(), &data_bytes) }? { |
| 564 | + let (key, data) = self.iter.cursor.current()?.ok_or(Error::Mdb(MdbError::NotFound))?; |
| 565 | + self.key = key; |
| 566 | + self.data = data; |
| 567 | + Ok(self) |
| 568 | + } else { |
| 569 | + Err(Error::Mdb(MdbError::NotFound)) |
| 570 | + } |
| 571 | + } |
| 572 | +} |
| 573 | + |
| 574 | +impl<'txn, KC, DC, IM> RwIter<'txn, KC, DC, IM> { |
| 575 | + /// Advance the iterator to the next item. |
| 576 | + pub fn next<'a>(&'a mut self) -> Option<Result<RwIterItem<'a, 'txn, KC, DC, IM>>> |
| 577 | + where |
| 578 | + IM: IterationMethod, |
| 579 | + { |
| 580 | + let result = if self.move_on_first { |
| 581 | + self.move_on_first = false; |
| 582 | + self.cursor.move_on_first(IM::MOVE_OPERATION) |
| 583 | + } else { |
| 584 | + self.cursor.move_on_next(IM::MOVE_OPERATION) |
| 585 | + }; |
| 586 | + |
| 587 | + match result { |
| 588 | + Ok(Some((key, data))) => Some(Ok(RwIterItem { iter: self, key, data })), |
| 589 | + Ok(None) => None, |
| 590 | + Err(e) => Some(Err(e)), |
| 591 | + } |
| 592 | + } |
| 593 | + |
| 594 | + /// Advance the iterator to the last item. |
| 595 | + pub fn last<'a>(&'a mut self) -> Option<Result<RwIterItem<'a, 'txn, KC, DC, IM>>> |
| 596 | + where |
| 597 | + IM: IterationMethod, |
| 598 | + { |
| 599 | + let result = if self.move_on_first { |
| 600 | + self.cursor.move_on_last(IM::MOVE_OPERATION) |
| 601 | + } else { |
| 602 | + match (self.cursor.current(), self.cursor.move_on_last(IM::MOVE_OPERATION)) { |
| 603 | + (Ok(Some((ckey, _))), Ok(Some((key, data)))) if ckey != key => { |
| 604 | + Ok(Some((key, data))) |
| 605 | + } |
| 606 | + (Ok(_), Ok(_)) => Ok(None), |
| 607 | + (Err(e), _) | (_, Err(e)) => Err(e), |
| 608 | + } |
| 609 | + }; |
| 610 | + |
| 611 | + match result { |
| 612 | + Ok(Some((key, data))) => Some(Ok(RwIterItem { iter: self, key, data })), |
| 613 | + Ok(None) => None, |
| 614 | + Err(e) => Some(Err(e)), |
| 615 | + } |
| 616 | + } |
| 617 | +} |
| 618 | + |
440 | 619 | /// A reverse read-only iterator structure. |
441 | 620 | pub struct RoRevIter<'txn, KC, DC, IM = MoveThroughDuplicateValues> { |
442 | 621 | cursor: RoCursor<'txn>, |
|
0 commit comments