Hello, I recently try to use the crate sled which is a database. The database (Db) struct take a AsRef<[u8]> for keys and Into<IVec> for values. I implemented From<Value> for IVec by serialize Value into the RON format and convert the output string into &[u8].
I could use the same technique for my Key struct, but since it just a u64 wrapped, I would like to convert it into a &[u8] directly. Unfortunately, methods as to_be_bytes() return an [u8; 8] and when I try to convert it into an &[u8] the borrow checker tell me that I "cannot return reference to temporary value" because I "returns a reference to data owned by the current function".
Is there a way to do it ?
Here is my code :
use serde::Serialize;
use ron;
// Work
#[derive(Debug, Serialize)]
struct Value {
post: Option<String>,
tag: Option<String>,
run: bool,
update_post: bool,
}
impl From<Value > for IVec {
fn from(value: Value ) -> Self {
ron::ser::to_string(&value).unwrap().as_bytes().into()
}
}
// Don't work
struct Key(u64);
impl AsRef<[u8]> for Key {
fn as_ref(&self) -> &[u8] {
&self.0.to_be_bytes()
}
}
Error:
cannot return reference to temporary value
returns a reference to data owned by the current function
You probably want u64::as_ne_bytes, but unfortunately that's not stable yet. You could implement it yourself using unsafe code, though:
// required for soundness!
#[repr(transparent)]
struct Key(u64);
impl AsRef<[u8]> for Key {
fn as_ref(&self) -> &[u8] {
let ptr = self as *const Self as *const u8;
// SAFETY Self is repr(transparent) and u64 is 8 bytes wide,
// with alignment greater than that of u8
unsafe { std::slice::from_raw_parts(ptr, 8) }
}
}
If you do it this way then the serialized form of the Key will depend on whether the target architecture is big-endian or little-endian, which may or may not be a problem.
I don't think having native endian on databases is a good idea. Instead, you can comvert the u64 into [u8; 8] using .to_be_bytes() within functions like Key::new() and store it internally.
If you want sled's iterators to return data in order you need to use big-endian keys and the native endianness of all commonly used architectures is little-endian. So using native endianness might not be a good idea. I would suggest just returning the be key by value: