gen_key_hashes generate array with integers, so what kind of borrow are we talking about?
error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable
--> src/main.rs:44:5
|
43 | let old_key_hashes = foo.gen_key_hashes();
| -------------------- immutable borrow occurs here
44 | update_value(foo);
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
47 | println!("before: {:?}", old_key_hashes);
| -------------- immutable borrow later used here
use smallvec::{smallvec, Array, SmallVec};
use std::{
collections::hash_map::DefaultHasher,
fmt::Debug,
hash::{Hash, Hasher},
};
trait Foo<'a> {
type Key: Debug + Hash + 'a;
type KeysArray: Array<Item = Self::Key>;
type KeyHashesArray: Array<Item = u64>;
fn gen_keys(&'a self) -> SmallVec<Self::KeysArray>;
fn gen_key_hashes(&'a self) -> SmallVec<Self::KeyHashesArray> {
self.gen_keys().iter().map(calculate_hash).collect()
}
}
#[derive(Debug, Hash)]
enum BarKey<'a> {
Key(&'a str),
}
struct Bar {
key: String,
}
impl<'a> Foo<'a> for Bar {
type Key = BarKey<'a>;
type KeysArray = [Self::Key; 10];
type KeyHashesArray = [u64; 10];
fn gen_keys(&'a self) -> SmallVec<Self::KeysArray> {
smallvec![BarKey::Key(&self.key)]
}
}
fn test<V, ValueUpdate>(foo: &mut V, update_value: ValueUpdate)
where
V: for<'any> Foo<'any>,
ValueUpdate: FnOnce(&mut V),
{
let old_key_hashes = foo.gen_key_hashes();
update_value(foo);
let new_key_hashes = foo.gen_key_hashes();
println!("before: {:?}", old_key_hashes);
println!("after: {:?}", new_key_hashes);
}
fn main() {
let mut bar = Bar {
key: "key".to_owned(),
};
test(&mut bar, |value| {
value.key = "modified".to_owned();
});
}
pub fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
It looks like you're trying to make Self::Key and Self::KeysArray match the lifetime of the &self borrow, which isn't possible in stable Rust (at least, not without much finagling with helper traits). In nightly Rust, this is possible with the generic_associated_types feature, which will likely become stable by the end of June (Rust Playground):
#![feature(generic_associated_types)]
use smallvec::{smallvec, Array, SmallVec};
use std::{
collections::hash_map::DefaultHasher,
fmt::Debug,
hash::{Hash, Hasher},
};
trait Foo {
type Key<'a>: Debug + Hash
where
Self: 'a;
type KeysArray<'a>: Array<Item = Self::Key<'a>>
where
Self: 'a;
type KeyHashesArray: Array<Item = u64>;
fn gen_keys(&self) -> SmallVec<Self::KeysArray<'_>>;
fn gen_key_hashes(&self) -> SmallVec<Self::KeyHashesArray> {
self.gen_keys().iter().map(calculate_hash).collect()
}
}
#[derive(Debug, Hash)]
enum BarKey<'a> {
Key(&'a str),
}
struct Bar {
key: String,
}
impl Foo for Bar {
type Key<'a> = BarKey<'a>;
type KeysArray<'a> = [Self::Key<'a>; 10];
type KeyHashesArray = [u64; 10];
fn gen_keys(&self) -> SmallVec<Self::KeysArray<'_>> {
smallvec![BarKey::Key(&self.key)]
}
}
fn test<V, ValueUpdate>(foo: &mut V, update_value: ValueUpdate)
where
V: Foo,
ValueUpdate: FnOnce(&mut V),
{
let old_key_hashes = foo.gen_key_hashes();
update_value(foo);
let new_key_hashes = foo.gen_key_hashes();
println!("before: {:?}", old_key_hashes);
println!("after: {:?}", new_key_hashes);
}
fn main() {
let mut bar = Bar {
key: "key".to_owned(),
};
test(&mut bar, |value| {
value.key = "modified".to_owned();
});
}
pub fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
With _Outlives: ?Sized = &'a Self it gives is not general enough error. Without it, work fine. And I can't move KeyHashesArray into Gat trait, but still, something at least.
I already used idea with GAT emulation, but in that case I can't figure how to do it, your help was maximally useful =)