Given the following definitions from How to borrow a field for serialization but create it during deserialization?:
#[derive(Serialize)]
struct SerializeThing<'a> {
small_header: (u64, u64, u64),
big_body: &'a str,
}
#[derive(Deserialize)]
struct DeserializeThing {
small_header: (u64, u64, u64),
big_body: String,
}
How do I implement the Borrow
trait so as to store the owned data naturally in (e.g.) HashMaps and query them by either them or by their borrowed counterparts? The closest thing that appears possible is as follows:
impl DeserializeThing {
fn as_serialize(&self) -> SerializeThing<'_> {
let DeserializeThing { small_header, big_body } = self;
let small_header = *small_header;
let big_body = big_body.as_str();
SerializeThing { small_header, big_body }
}
}
which is not quite sufficient.
You can't.
Borrow::borrow
must return a reference, and there is no way you can get a reference to a SerializeThing
from a reference to a DeserializeThing
as these types are simply not ABI compatible.
If performance is important and you can't pay for the construction of DeserializeThing
instances/allocation of strings, then you could use hashbrown::HashMap
instead of std::collections::HashMap
.
hashbrown
is the library that the standard library uses for its own HashMap
implementation, but it has some more useful methods.
One which would be useful for you now is the raw entry API (and mutable raw entry).
In particular, it allows you to get a map entry from its hash and a matching function:
pub fn from_hash<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'a > V)> where F: FnMut(&K) -> bool
Access an entry by hash.
Since you can implement Hash
for both DeserializeThing
and SerializeThing
to get the same the hashes for the same values, this API would be simple to use in your case.