From 98c1031c8abc9cf34da1e2f51c0200f3a5cd8202 Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Sat, 17 Aug 2024 15:53:42 +0200 Subject: [PATCH] add new trait to encode values to bytes still lots of TODOs --- heed-traits/src/lib.rs | 63 ++++++++++++++++- heed-types/src/bytes.rs | 39 +++++++++-- heed-types/src/integer.rs | 42 ++++++++---- heed-types/src/serde_bincode.rs | 16 +++-- heed-types/src/serde_json.rs | 16 +++-- heed-types/src/serde_rmp.rs | 16 +++-- heed-types/src/str.rs | 21 +++--- heed-types/src/unit.rs | 16 +++-- heed/src/database.rs | 118 ++++++++++++++++++-------------- heed/src/iterator/iter.rs | 15 ++-- 10 files changed, 245 insertions(+), 117 deletions(-) diff --git a/heed-traits/src/lib.rs b/heed-traits/src/lib.rs index af8c2102..340be438 100644 --- a/heed-traits/src/lib.rs +++ b/heed-traits/src/lib.rs @@ -12,12 +12,18 @@ use std::borrow::Cow; use std::cmp::{Ord, Ordering}; use std::error::Error as StdError; +use std::fmt; /// A boxed `Send + Sync + 'static` error. pub type BoxedError = Box; /// A trait that represents an encoding structure. -pub trait BytesEncode<'a> { +#[deprecated = "replaced by `ToBytes` to allow for more optimization"] +#[allow(deprecated)] // deprecated BoxedErrorWrapper is used in a bound +pub trait BytesEncode<'a>: + // TODO are these bound needed? + ToBytes<'a, SelfType = Self::EItem, ReturnBytes = Cow<'a, [u8]>, Error = BoxedErrorWrapper> +{ /// The type to encode. type EItem: ?Sized + 'a; @@ -25,6 +31,61 @@ pub trait BytesEncode<'a> { fn bytes_encode(item: &'a Self::EItem) -> Result, BoxedError>; } +/// A trait that represents an encoding structure. +pub trait ToBytes<'a> { + /// The type to encode to bytes. + type SelfType: ?Sized + 'a; + + /// The type containing the encoded bytes. + type ReturnBytes: Into> + AsRef<[u8]> + 'a; + + /// The error type to return when decoding goes wrong. + type Error: StdError + Send + Sync + 'static; + + /// Encode the given item as bytes. + fn to_bytes(item: &'a Self::SelfType) -> Result; +} + +#[allow(deprecated)] +impl<'a, T: BytesEncode<'a>> ToBytes<'a> for T { + type SelfType = >::EItem; + + type ReturnBytes = Cow<'a, [u8]>; + + type Error = BoxedErrorWrapper; + + fn to_bytes(item: &'a Self::SelfType) -> Result { + Self::bytes_encode(item).map_err(BoxedErrorWrapper) + } +} + +/// Wraps the [`BoxedError`] type alias because for complicated reasons it does not implement +/// [`Error`][StdError]. This wrapper forwards [`Debug`][fmt::Debug], [`Display`][fmt::Display] +/// and [`Error`][StdError] through the wrapper and the [`Box`]. +#[deprecated = "this wrapper was added for backwards compatibility of BytesEncode only"] +pub struct BoxedErrorWrapper(BoxedError); + +#[allow(deprecated)] +impl fmt::Debug for BoxedErrorWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(&self.0, f) + } +} + +#[allow(deprecated)] +impl fmt::Display for BoxedErrorWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(&self.0, f) + } +} + +#[allow(deprecated)] +impl StdError for BoxedErrorWrapper { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.0.source() + } +} + /// A trait that represents a decoding structure. pub trait BytesDecode<'a> { /// The type to decode. diff --git a/heed-types/src/bytes.rs b/heed-types/src/bytes.rs index ae602ba0..a707b825 100644 --- a/heed-types/src/bytes.rs +++ b/heed-types/src/bytes.rs @@ -1,6 +1,6 @@ -use std::borrow::Cow; +use std::convert::Infallible; -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; /// Describes a byte slice `[u8]` that is totally borrowed and doesn't depend on /// any [memory alignment]. @@ -8,11 +8,15 @@ use heed_traits::{BoxedError, BytesDecode, BytesEncode}; /// [memory alignment]: std::mem::align_of() pub enum Bytes {} -impl<'a> BytesEncode<'a> for Bytes { - type EItem = [u8]; +impl<'a> ToBytes<'a> for Bytes { + type SelfType = [u8]; - fn bytes_encode(item: &'a Self::EItem) -> Result, BoxedError> { - Ok(Cow::Borrowed(item)) + type ReturnBytes = &'a [u8]; + + type Error = Infallible; + + fn to_bytes(item: &'a Self::SelfType) -> Result { + Ok(item) } } @@ -23,3 +27,26 @@ impl<'a> BytesDecode<'a> for Bytes { Ok(bytes) } } + +/// Like [`Bytes`], but always contains exactly `N` (the generic parameter) bytes. +pub enum FixedSizeBytes {} + +impl<'a, const N: usize> ToBytes<'a> for FixedSizeBytes { + type SelfType = [u8; N]; + + type ReturnBytes = [u8; N]; // TODO &'a [u8; N] or [u8; N] + + type Error = Infallible; + + fn to_bytes(item: &'a Self::SelfType) -> Result { + Ok(*item) + } +} + +impl<'a, const N: usize> BytesDecode<'a> for FixedSizeBytes { + type DItem = [u8; N]; // TODO &'a [u8; N] or [u8; N] + + fn bytes_decode(bytes: &'a [u8]) -> Result { + bytes.try_into().map_err(Into::into) + } +} diff --git a/heed-types/src/integer.rs b/heed-types/src/integer.rs index 71435103..79751acb 100644 --- a/heed-types/src/integer.rs +++ b/heed-types/src/integer.rs @@ -1,18 +1,22 @@ -use std::borrow::Cow; +use std::convert::Infallible; use std::marker::PhantomData; use std::mem::size_of; use byteorder::{ByteOrder, ReadBytesExt}; -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; /// Encodable version of [`u8`]. pub struct U8; -impl BytesEncode<'_> for U8 { - type EItem = u8; +impl ToBytes<'_> for U8 { + type SelfType = u8; - fn bytes_encode(item: &Self::EItem) -> Result, BoxedError> { - Ok(Cow::from([*item].to_vec())) + type ReturnBytes = [u8; 1]; + + type Error = Infallible; + + fn to_bytes(item: &Self::SelfType) -> Result { + Ok([*item]) } } @@ -27,11 +31,15 @@ impl BytesDecode<'_> for U8 { /// Encodable version of [`i8`]. pub struct I8; -impl BytesEncode<'_> for I8 { - type EItem = i8; +impl ToBytes<'_> for I8 { + type SelfType = i8; + + type ReturnBytes = [u8; 1]; - fn bytes_encode(item: &Self::EItem) -> Result, BoxedError> { - Ok(Cow::from([*item as u8].to_vec())) + type Error = Infallible; + + fn to_bytes(item: &Self::SelfType) -> Result { + Ok([*item as u8]) } } @@ -51,13 +59,17 @@ macro_rules! define_type { pub struct $name(PhantomData); - impl BytesEncode<'_> for $name { - type EItem = $native; + impl ToBytes<'_> for $name { + type SelfType = $native; + + type ReturnBytes = [u8; size_of::<$native>()]; + + type Error = Infallible; - fn bytes_encode(item: &Self::EItem) -> Result, BoxedError> { - let mut buf = vec![0; size_of::()]; + fn to_bytes(item: &Self::SelfType) -> Result { + let mut buf = [0; size_of::<$native>()]; O::$write_method(&mut buf, *item); - Ok(Cow::from(buf)) + Ok(buf) } } diff --git a/heed-types/src/serde_bincode.rs b/heed-types/src/serde_bincode.rs index 37fefe01..63e85a3a 100644 --- a/heed-types/src/serde_bincode.rs +++ b/heed-types/src/serde_bincode.rs @@ -1,6 +1,4 @@ -use std::borrow::Cow; - -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; use serde::{Deserialize, Serialize}; /// Describes a type that is [`Serialize`]/[`Deserialize`] and uses `bincode` to do so. @@ -8,14 +6,18 @@ use serde::{Deserialize, Serialize}; /// It can borrow bytes from the original slice. pub struct SerdeBincode(std::marker::PhantomData); -impl<'a, T: 'a> BytesEncode<'a> for SerdeBincode +impl<'a, T: 'a> ToBytes<'a> for SerdeBincode where T: Serialize, { - type EItem = T; + type SelfType = T; + + type ReturnBytes = Vec; + + type Error = bincode::Error; - fn bytes_encode(item: &'a Self::EItem) -> Result, BoxedError> { - bincode::serialize(item).map(Cow::Owned).map_err(Into::into) + fn to_bytes(item: &'a Self::SelfType) -> Result { + bincode::serialize(item) } } diff --git a/heed-types/src/serde_json.rs b/heed-types/src/serde_json.rs index f1f1c3be..13045a4a 100644 --- a/heed-types/src/serde_json.rs +++ b/heed-types/src/serde_json.rs @@ -1,6 +1,4 @@ -use std::borrow::Cow; - -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; use serde::{Deserialize, Serialize}; /// Describes a type that is [`Serialize`]/[`Deserialize`] and uses `serde_json` to do so. @@ -8,14 +6,18 @@ use serde::{Deserialize, Serialize}; /// It can borrow bytes from the original slice. pub struct SerdeJson(std::marker::PhantomData); -impl<'a, T: 'a> BytesEncode<'a> for SerdeJson +impl<'a, T: 'a> ToBytes<'a> for SerdeJson where T: Serialize, { - type EItem = T; + type SelfType = T; + + type ReturnBytes = Vec; + + type Error = serde_json::Error; - fn bytes_encode(item: &Self::EItem) -> Result, BoxedError> { - serde_json::to_vec(item).map(Cow::Owned).map_err(Into::into) + fn to_bytes(item: &'a Self::SelfType) -> Result { + serde_json::to_vec(item) } } diff --git a/heed-types/src/serde_rmp.rs b/heed-types/src/serde_rmp.rs index f33c7467..418ead93 100644 --- a/heed-types/src/serde_rmp.rs +++ b/heed-types/src/serde_rmp.rs @@ -1,6 +1,4 @@ -use std::borrow::Cow; - -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; use serde::{Deserialize, Serialize}; /// Describes a type that is [`Serialize`]/[`Deserialize`] and uses `rmp_serde` to do so. @@ -8,14 +6,18 @@ use serde::{Deserialize, Serialize}; /// It can borrow bytes from the original slice. pub struct SerdeRmp(std::marker::PhantomData); -impl<'a, T: 'a> BytesEncode<'a> for SerdeRmp +impl<'a, T: 'a> ToBytes<'a> for SerdeRmp where T: Serialize, { - type EItem = T; + type SelfType = T; + + type ReturnBytes = Vec; + + type Error = rmp_serde::encode::Error; - fn bytes_encode(item: &Self::EItem) -> Result, BoxedError> { - rmp_serde::to_vec(item).map(Cow::Owned).map_err(Into::into) + fn to_bytes(item: &'a Self::SelfType) -> Result { + rmp_serde::to_vec(item) } } diff --git a/heed-types/src/str.rs b/heed-types/src/str.rs index 220306d9..0a0dd30d 100644 --- a/heed-types/src/str.rs +++ b/heed-types/src/str.rs @@ -1,16 +1,19 @@ -use std::borrow::Cow; -use std::str; +use std::convert::Infallible; -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; -/// Describes a [`prim@str`]. +/// Describes a [`str`]. pub enum Str {} -impl BytesEncode<'_> for Str { - type EItem = str; +impl<'a> ToBytes<'a> for Str { + type SelfType = str; - fn bytes_encode(item: &Self::EItem) -> Result, BoxedError> { - Ok(Cow::Borrowed(item.as_bytes())) + type ReturnBytes = &'a [u8]; + + type Error = Infallible; + + fn to_bytes(item: &'a Self::SelfType) -> Result { + Ok(item.as_bytes()) } } @@ -18,6 +21,6 @@ impl<'a> BytesDecode<'a> for Str { type DItem = &'a str; fn bytes_decode(bytes: &'a [u8]) -> Result { - str::from_utf8(bytes).map_err(Into::into) + std::str::from_utf8(bytes).map_err(Into::into) } } diff --git a/heed-types/src/unit.rs b/heed-types/src/unit.rs index 4fbb9e2c..69f13fa0 100644 --- a/heed-types/src/unit.rs +++ b/heed-types/src/unit.rs @@ -1,16 +1,20 @@ -use std::borrow::Cow; +use std::convert::Infallible; use std::{error, fmt}; -use heed_traits::{BoxedError, BytesDecode, BytesEncode}; +use heed_traits::{BoxedError, BytesDecode, ToBytes}; /// Describes the unit `()` type. pub enum Unit {} -impl BytesEncode<'_> for Unit { - type EItem = (); +impl ToBytes<'_> for Unit { + type SelfType = (); - fn bytes_encode(_item: &Self::EItem) -> Result, BoxedError> { - Ok(Cow::Borrowed(&[])) + type ReturnBytes = [u8; 0]; + + type Error = Infallible; + + fn to_bytes(_item: &'_ Self::SelfType) -> Result { + Ok([]) } } diff --git a/heed/src/database.rs b/heed/src/database.rs index 3817103f..b0f65e9e 100644 --- a/heed/src/database.rs +++ b/heed/src/database.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::ops::{Bound, RangeBounds}; use std::{any, fmt, marker, mem, ptr}; -use heed_traits::{Comparator, LexicographicComparator}; +use heed_traits::{Comparator, LexicographicComparator, ToBytes}; use types::{DecodeIgnore, LazyDecode}; use crate::cursor::MoveOperation; @@ -339,16 +339,20 @@ impl Database { /// wtxn.commit()?; /// # Ok(()) } /// ``` - pub fn get<'a, 'txn>(&self, txn: &'txn RoTxn, key: &'a KC::EItem) -> Result> + pub fn get<'a, 'txn>( + &self, + txn: &'txn RoTxn, + key: &'a KC::SelfType, + ) -> Result> where - KC: BytesEncode<'a>, + KC: ToBytes<'a>, DC: BytesDecode<'txn>, { assert_eq_env_db_txn!(self, txn); - let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?; + let key_bytes = KC::to_bytes(key).map_err(|err| Error::Encoding(Box::new(err)))?; - let mut key_val = unsafe { crate::into_val(&key_bytes) }; + let mut key_val = unsafe { crate::into_val(key_bytes.as_ref()) }; let mut data_val = mem::MaybeUninit::uninit(); let result = unsafe { @@ -1225,31 +1229,32 @@ impl Database { range: &'a R, ) -> Result> where - KC: BytesEncode<'a>, - R: RangeBounds, + KC: ToBytes<'a>, + R: RangeBounds, { assert_eq_env_db_txn!(self, txn); + // TODO optimize, this might do unnecessary allocations on types that are already 'static let start_bound = match range.start_bound() { Bound::Included(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Included(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Included(bytes.into()) } Bound::Excluded(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Excluded(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Excluded(bytes.into()) } Bound::Unbounded => Bound::Unbounded, }; let end_bound = match range.end_bound() { Bound::Included(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Included(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Included(bytes.into()) } Bound::Excluded(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Excluded(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Excluded(bytes.into()) } Bound::Unbounded => Bound::Unbounded, }; @@ -1317,31 +1322,32 @@ impl Database { range: &'a R, ) -> Result> where - KC: BytesEncode<'a>, - R: RangeBounds, + KC: ToBytes<'a>, + R: RangeBounds, { assert_eq_env_db_txn!(self, txn); + // TODO optimize, this might do unnecessary allocations on types that are already 'static let start_bound = match range.start_bound() { Bound::Included(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Included(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Included(bytes.into()) } Bound::Excluded(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Excluded(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Excluded(bytes.into()) } Bound::Unbounded => Bound::Unbounded, }; let end_bound = match range.end_bound() { Bound::Included(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Included(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Included(bytes.into()) } Bound::Excluded(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Excluded(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Excluded(bytes.into()) } Bound::Unbounded => Bound::Unbounded, }; @@ -1399,31 +1405,32 @@ impl Database { range: &'a R, ) -> Result> where - KC: BytesEncode<'a>, - R: RangeBounds, + KC: ToBytes<'a>, + R: RangeBounds, { assert_eq_env_db_txn!(self, txn); + // TODO optimize, this might do unnecessary allocations on types that are already 'static let start_bound = match range.start_bound() { Bound::Included(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Included(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Included(bytes.into()) } Bound::Excluded(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Excluded(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Excluded(bytes.into()) } Bound::Unbounded => Bound::Unbounded, }; let end_bound = match range.end_bound() { Bound::Included(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Included(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Included(bytes.into()) } Bound::Excluded(bound) => { - let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?; - Bound::Excluded(bytes.into_owned()) + let bytes = KC::to_bytes(bound).map_err(|err| Error::Encoding(Box::new(err)))?; + Bound::Excluded(bytes.into()) } Bound::Unbounded => Bound::Unbounded, }; @@ -1571,16 +1578,17 @@ impl Database { pub fn prefix_iter<'a, 'txn>( &self, txn: &'txn RoTxn, - prefix: &'a KC::EItem, + prefix: &'a KC::SelfType, ) -> Result> where - KC: BytesEncode<'a>, + KC: ToBytes<'a>, C: LexicographicComparator, { assert_eq_env_db_txn!(self, txn); - let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?; - let prefix_bytes = prefix_bytes.into_owned(); + let prefix_bytes = KC::to_bytes(prefix).map_err(|err| Error::Encoding(Box::new(err)))?; + // TODO optimize, this might do unnecessary allocations on types that are already 'static + let prefix_bytes = prefix_bytes.into(); RoCursor::new(txn, self.dbi).map(|cursor| RoPrefix::new(cursor, prefix_bytes)) } @@ -1703,16 +1711,17 @@ impl Database { pub fn rev_prefix_iter<'a, 'txn>( &self, txn: &'txn RoTxn, - prefix: &'a KC::EItem, + prefix: &'a KC::SelfType, ) -> Result> where - KC: BytesEncode<'a>, + KC: ToBytes<'a>, C: LexicographicComparator, { assert_eq_env_db_txn!(self, txn); - let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?; - let prefix_bytes = prefix_bytes.into_owned(); + let prefix_bytes = KC::to_bytes(prefix).map_err(|err| Error::Encoding(Box::new(err)))?; + // TODO optimize, this might do unnecessary allocations on types that are already 'static + let prefix_bytes = prefix_bytes.into(); RoCursor::new(txn, self.dbi).map(|cursor| RoRevPrefix::new(cursor, prefix_bytes)) } @@ -1822,18 +1831,23 @@ impl Database { /// wtxn.commit()?; /// # Ok(()) } /// ``` - pub fn put<'a>(&self, txn: &mut RwTxn, key: &'a KC::EItem, data: &'a DC::EItem) -> Result<()> + pub fn put<'a>( + &self, + txn: &mut RwTxn, + key: &'a KC::SelfType, + data: &'a DC::SelfType, + ) -> Result<()> where - KC: BytesEncode<'a>, - DC: BytesEncode<'a>, + KC: ToBytes<'a>, + DC: ToBytes<'a>, { assert_eq_env_db_txn!(self, txn); - let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?; - let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?; + let key_bytes = KC::to_bytes(key).map_err(|err| Error::Encoding(Box::new(err)))?; + let data_bytes = DC::to_bytes(data).map_err(|err| Error::Encoding(Box::new(err)))?; - let mut key_val = unsafe { crate::into_val(&key_bytes) }; - let mut data_val = unsafe { crate::into_val(&data_bytes) }; + let mut key_val = unsafe { crate::into_val(key_bytes.as_ref()) }; + let mut data_val = unsafe { crate::into_val(data_bytes.as_ref()) }; let flags = 0; unsafe { @@ -2471,8 +2485,8 @@ impl Database { /// ``` pub fn delete_range<'a, 'txn, R>(&self, txn: &'txn mut RwTxn, range: &'a R) -> Result where - KC: BytesEncode<'a> + BytesDecode<'txn>, - R: RangeBounds, + KC: ToBytes<'a> + BytesDecode<'txn>, + R: RangeBounds, { assert_eq_env_db_txn!(self, txn); diff --git a/heed/src/iterator/iter.rs b/heed/src/iterator/iter.rs index 87f67662..7d76a9d6 100644 --- a/heed/src/iterator/iter.rs +++ b/heed/src/iterator/iter.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::marker; +use heed_traits::ToBytes; use types::LazyDecode; use crate::iteration_method::{IterationMethod, MoveBetweenKeys, MoveThroughDuplicateValues}; @@ -325,16 +326,16 @@ impl<'txn, KC, DC, IM> RwIter<'txn, KC, DC, IM> { pub unsafe fn put_current_with_options<'a, NDC>( &mut self, flags: PutFlags, - key: &'a KC::EItem, - data: &'a NDC::EItem, + key: &'a KC::SelfType, + data: &'a NDC::SelfType, ) -> Result<()> where - KC: BytesEncode<'a>, - NDC: BytesEncode<'a>, + KC: ToBytes<'a>, + NDC: ToBytes<'a>, { - let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?; - let data_bytes: Cow<[u8]> = NDC::bytes_encode(data).map_err(Error::Encoding)?; - self.cursor.put_current_with_flags(flags, &key_bytes, &data_bytes) + let key_bytes = KC::to_bytes(key).map_err(|err| Error::Encoding(Box::new(err)))?; + let data_bytes = NDC::to_bytes(data).map_err(|err| Error::Encoding(Box::new(err)))?; + self.cursor.put_current_with_flags(flags, key_bytes.as_ref(), data_bytes.as_ref()) } /// Move on the first value of keys, ignoring duplicate values.