Extend HashMap with contents of another HashMap [duplicate] - hashmap

So I'm a bit stuck, trying to merge two HashMaps.
It's easy to do it inline:
fn inline() {
let mut first_context = HashMap::new();
first_context.insert("Hello", "World");
let mut second_context = HashMap::new();
second_context.insert("Hey", "There");
let mut new_context = HashMap::new();
for (key, value) in first_context.iter() {
new_context.insert(*key, *value);
}
for (key, value) in second_context.iter() {
new_context.insert(*key, *value);
}
println!("Inline:\t\t{}", new_context);
println!("Inline:\t\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
It's easy enough to make a function:
fn abstracted() {
fn merge<'a>(first_context: &HashMap<&'a str, &'a str>, second_context: &HashMap<&'a str, &'a str>) -> HashMap<&'a str, &'a str> {
let mut new_context = HashMap::new();
for (key, value) in first_context.iter() {
new_context.insert(*key, *value);
}
for (key, value) in second_context.iter() {
new_context.insert(*key, *value);
}
new_context
}
let mut first_context = HashMap::new();
first_context.insert("Hello", "World");
let mut second_context = HashMap::new();
second_context.insert("Hey", "There");
println!("Abstracted:\t{}", merge(&first_context, &second_context));
println!("Abstracted:\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
However, I can't seem to get the generic version to work:
fn generic() {
fn merge<'a, K: Hash + Eq, V>(first_context: &HashMap<&'a K, &'a V>, second_context: &HashMap<&'a K, &'a V>) -> HashMap<&'a K, &'a V> {
let mut new_context = HashMap::new();
for (key, value) in first_context.iter() {
new_context.insert(*key, *value);
}
for (key, value) in second_context.iter() {
new_context.insert(*key, *value);
}
new_context
}
let mut first_context = HashMap::new();
first_context.insert("Hello", "World");
let mut second_context = HashMap::new();
second_context.insert("Hey", "There");
println!("Generic:\t{}", merge(&first_context, &second_context));
println!("Generic:\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
The above code on play.rust-lang.org.
Compiling it:
error: the trait `core::kinds::Sized` is not implemented for the type `str`
I get that the compiler is confused about the size of the generic value, but I'm not sure why "str" doesn't have a strict memory size? I know its a String slice and not a type, but still this should work, no? Is this a bug?
I thought this would be a relatively trivial function. If someone has a good solution, I'd love to learn. Actually ideally, I'd love to see a solution with a trait Mergeable and write a decorator for HashMap<&K, &V>, such that I can call let new_context = first_context.merge(&second_context); but this can be a different question.

A more up to date answer from this tweet:
use std::collections::HashMap;
// Mutating one map
fn merge1(map1: &mut HashMap<(), ()>, map2: HashMap<(), ()>) {
map1.extend(map2);
}
// Without mutation
fn merge2(map1: HashMap<(), ()>, map2: HashMap<(), ()>) -> HashMap<(), ()> {
map1.into_iter().chain(map2).collect()
}
// If you only have a reference to the map to be merged in
fn merge_from_ref(map: &mut HashMap<(), ()>, map_ref: &HashMap<(), ()>) {
map.extend(map_ref.into_iter().map(|(k, v)| (k.clone(), v.clone())));
}
Rust Playground Link

This version does work:
use std::collections::HashMap;
use std::hash::Hash;
fn main() {
fn merge<K: Hash + Eq + Copy, V: Copy>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V> {
let mut new_context = HashMap::new();
for (key, value) in first_context.iter() {
new_context.insert(*key, *value);
}
for (key, value) in second_context.iter() {
new_context.insert(*key, *value);
}
new_context
}
let mut first_context = HashMap::new();
first_context.insert("Hello", "World");
let mut second_context = HashMap::new();
second_context.insert("Hey", "There");
println!("Generic:\t{}", merge(&first_context, &second_context));
println!("Generic:\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
The difference is in the signature of merge(). Here is yours:
fn merge<'a, K: Hash + Eq, V>(first_context: &HashMap<&'a K, &'a V>, second_context: &HashMap<&'a K, &'a V>) -> HashMap<&'a K, &'a V>
Here is mine:
fn merge<K: Hash + Eq + Copy, V: Copy>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V>
For some reason you are trying to abstract HashMap<&str, &str> to HashMap<&K, &V>, but this is not really correct: while &str is a borrowed pointer, it is special - it points to dynamically sized type str. Size of str is not known to the compiler, so you can use it only through a pointer. Consequently, neither Hash nor Eq are implemented for str, they are implemented for &str instead. Hence I've changed HashMap<&'a K, &'a V> to HashMap<K, V>.
The second problem is that in general you can't write your function if it takes only references to maps. Your non-generic merge function works only because &str is a reference and references are implicitly copyable. In general case, however, both keys and values can be non-copyable, and merging them into the single map will require moving these maps into the function. Adding Copy bound allows that.
You can also add Clone bound instead of Copy and use explicit clone() call:
fn merge<K: Hash + Eq + Clone, V: Clone>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V> {
// ...
for (key, value) in first_context.iter() {
new_context.insert(key.clone(), value.clone());
}
// ...
}
The most general way, however, is moving maps into the function:
fn merge<K: Hash + Eq, V>(first_context: HashMap<K, V>, second_context: HashMap<K, V>) -> HashMap<K, V> {
// ...
for (key, value) in first_context.into_iter() {
new_context.insert(key, value);
}
// ...
}
Note into_iter() method which consumes the map, but returns an iterator of tuples with actual values instead of references.

Related

Lifetime conflicts when implementing IntoIterator to iterate over an inner collection [duplicate]

I am trying to create an mutable iterator for a vector of type: Vec<Vec<(K, V)>>
The iterator code:
pub struct IterMut<'a, K: 'a, V: 'a> {
iter: &'a mut Vec<Vec<(K, V)>>,
ix: usize,
inner_ix: usize,
}
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
while self.iter.len() < self.ix {
while self.iter[self.ix].len() < self.inner_ix {
self.inner_ix += 1;
let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
return Some((&k, &mut v));
}
self.ix += 1;
}
return None;
}
}
The error I get is:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:16:42
|
16 | let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
| ^^^^^^^^^^^^^^^^^^
|
help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<(&'a K, &'a mut V)>
--> src/main.rs:11:5
|
11 | fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
| ^
Apparently I have lifetime problems, but I don't know how to tell the compiler that this should work.
Is this how you should implement the mutable iterator or is there a better way?
When debugging cryptic error messages, I've found it easier to try and isolate the issue as much as possible.
The first step is to break the expression into its essential constituents, let's start by splitting the indexing steps:
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
while self.iter.len() < self.ix {
while self.iter[self.ix].len() < self.inner_ix {
self.inner_ix += 1;
let outer: &'a mut Vec<_> = self.iter;
let inner: &'a mut Vec<_> = &mut outer[self.ix];
let (ref k, ref mut v) = inner[self.inner_ix];
return Some((&k, &mut v));
}
self.ix += 1;
}
return None;
}
The Index trait assumes that the lifetime of its output is linked to that of its receiver, so to get a 'a lifetime we need the receiver to have a &'a lifetime, and it propagates upward, leading to the above code.
However there's an issue here: let outer: &'a mut Vec<_> = self.iter; will not compile because mutable references are not Copy.
So, how does one get a mutable reference from a mutable reference (which must be possible since IndexMut gets a mutable reference)?
One uses re-borrowing: let outer: &'a mut Vec<_> = &mut *self.iter;.
And, oh:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> <anon>:16:45
|
16 | let outer: &'a mut Vec<_> = &mut *self.iter;
| ^^^^^^^^^^^^^^^
|
The reborrowed reference is not valid for 'a, it's valid only for the (unnamed) lifetime of self!
Why Rust? Why?
Because doing otherwise would be unsafe.
&mut T is guaranteed NOT to be aliasing, however your method could create aliasing references (if you forgot to advance the index):
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix];
return Some((&k, &mut v));
}
And even if you don't, there's not guarantee that you don't have a rewind method that would allow "stepping back".
TL;DR: You were about to step on a landmine, you were steered toward Stack Overflow instead ;)
Alright, but how do you implement the iterator!.
Well, using iterators, of course. As Shepmaster (briefly) answers, there is the equivalent in the standard library already in the guise of FlatMap. The trick is to use existing iterators for the nitty-gritty details!
Something like:
use std::slice::IterMut;
pub struct MyIterMut<'a, K: 'a, V: 'a> {
outer: IterMut<'a, Vec<(K, V)>>,
inner: IterMut<'a, (K, V)>,
}
Then you consume from inner as long as it provides items, and when empty you refill it from outer.
impl<'a, K, V> MyIterMut<'a, K, V> {
fn new(v: &'a mut Vec<Vec<(K, V)>>) -> MyIterMut<'a, K, V> {
let mut outer = v.iter_mut();
let inner = outer.next()
.map(|v| v.iter_mut())
.unwrap_or_else(|| (&mut []).iter_mut());
MyIterMut { outer: outer, inner: inner }
}
}
impl<'a, K, V> Iterator for MyIterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
loop {
match self.inner.next() {
Some(r) => return Some((&r.0, &mut r.1)),
None => (),
}
match self.outer.next() {
Some(v) => self.inner = v.iter_mut(),
None => return None,
}
}
}
}
A quick test case:
fn main() {
let mut v = vec![
vec![(1, "1"), (2, "2")],
vec![],
vec![(3, "3")]
];
let iter = MyIterMut::new(&mut v);
let c: Vec<_> = iter.collect();
println!("{:?}", c);
}
Prints:
[(1, "1"), (2, "2"), (3, "3")]
as expected, so it's not completely broken, but I wish I did not have to rely on the &[] is 'static trick (ie, that std::slice::IterMut implemented Default).
You've provided no reason that you are reimplementing the standard Iterator::flat_map, so I'd just use that and another map to remove the mutability you don't need:
fn main() {
let mut a: Vec<Vec<(u8, u8)>> = Default::default();
let c = a.iter_mut()
.flat_map(|x| x.iter_mut())
.map(|&mut (ref a, ref mut b)| (a, b))
.count();
println!("{}", c);
}
Once you have that, you can just return the iterator in one of the many ways.
#[derive(Debug, Default)]
struct Thing<K, V>(Vec<Vec<(K, V)>>);
impl<K, V> Thing<K, V> {
fn iter_mut<'a>(&'a mut self) -> Box<Iterator<Item = (&'a K, &'a mut V)> + 'a> {
Box::new(self.0
.iter_mut()
.flat_map(|x| x.iter_mut())
.map(|&mut (ref a, ref mut b)| (a, b)))
}
}
fn main() {
let mut a = Thing::<u8, u8>::default();
let c = a.iter_mut().count();
println!("{}", c);
}

Get the Vec of owned values from a HashMap

An algorithm I wrote builds a temporary HashMap. Once it's finished, I'm only interested in the values of the hashmap, so I'd like to transfer ownership of the values from the HashMap<K, V> to a Vec<V>.
With a simplified example hashmap:
fn main() {
use std::collections::HashMap;
let mut h: HashMap<_, _> = HashMap::new();
h.insert(1, "foo".to_owned());
}
I can do:
let vals: Vec<&String> = h.values().collect(); - which is short and sweet, but the hashmap still owns the values;
let vals: Vec<String> = h.values().cloned().collect() (as in this question) - the result is what I need, but I was taught to avoid the extra clones;
let vals: Vec<String> = h.into_iter().map(|(_k, v)| v).collect(); - does what I need without a clone, but is a bit ugly.
The actual values are a mid-sized struct ({String, Vec<String>}, under a KB total).
Should I default to avoiding clone in this case or is it premature optimization? Is there an idiomatic way to do this that I'm missing?
.into_iter().map(|(_, v)| v) is the idiomatic way to do it. That not ugly at all.
If you want you could do:
use std::collections::hash_map;
use std::collections::HashMap;
use std::iter::{ExactSizeIterator, FusedIterator};
struct IntoValues<K, V> {
iter: hash_map::IntoIter<K, V>,
}
impl<K, V> IntoValues<K, V> {
fn new(map: HashMap<K, V>) -> Self {
Self {
iter: map.into_iter(),
}
}
}
impl<K, V> Iterator for IntoValues<K, V> {
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(_, v)| v)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<K, V> ExactSizeIterator for IntoValues<K, V> {}
impl<K, V> FusedIterator for IntoValues<K, V> {}
trait HashMapTool {
type IntoValues;
type Item;
fn into_values(self) -> Self::IntoValues;
}
impl<K, V> HashMapTool for HashMap<K, V> {
type Item = V;
type IntoValues = IntoValues<K, V>;
fn into_values(self) -> Self::IntoValues {
IntoValues::new(self)
}
}
fn main() {
let mut h: HashMap<_, _> = HashMap::new();
h.insert(1, "foo".to_owned());
let _vals: Vec<_> = h.into_values().collect();
}
Note that as of Rust 1.54.0, the into_values method has been implemented for HashMap and BTreeMap in the standard library.
fn main() {
let mut h: HashMap<i32, String> = HashMap::new();
h.insert(1, "foo".to_owned());
let _vals: Vec<String> = h.into_values().collect();
}
https://github.com/rust-lang/rust/blob/master/RELEASES.md#stabilized-apis-6

Rust function that accepts either HashMap and BtreeMap

fn edit_map_values(
map1: &mut HashMap<String, i128> || &mut BTreeMap<String, i128>){
for tuple in map1.iter_mut() {
if !map1.contains_key(&"key1") {
*tuple.1 += 1;
}
}
map1.insert(&"key2", 10);
}
How do I write one function that accepts either HashMap and BtreeMap like in the example above?
It is possible to abstract over types by using traits and for your specific use-case, you can take a look at this more constrained example.
use core::{borrow::Borrow, hash::Hash};
use std::collections::{BTreeMap, HashMap};
trait GenericMap<K, V> {
fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + Ord;
fn each_mut<F>(&mut self, cb: F)
where
F: FnMut((&K, &mut V));
fn insert(&mut self, key: K, value: V) -> Option<V>;
}
impl<K, V> GenericMap<K, V> for HashMap<K, V>
where
K: Eq + Hash,
{
fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + Ord,
{
self.contains_key(k)
}
fn each_mut<F>(&mut self, mut cb: F)
where
F: FnMut((&K, &mut V)),
{
self.iter_mut().for_each(|x| cb(x))
}
fn insert(&mut self, key: K, value: V) -> Option<V> {
self.insert(key, value)
}
}
impl<K, V> GenericMap<K, V> for BTreeMap<K, V>
where
K: Ord,
{
fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + Ord,
{
self.contains_key(k)
}
fn each_mut<F>(&mut self, mut cb: F)
where
F: FnMut((&K, &mut V)),
{
self.iter_mut().for_each(|x| cb(x))
}
fn insert(&mut self, key: K, value: V) -> Option<V> {
self.insert(key, value)
}
}
fn edit_map_values<T: GenericMap<String, i128>>(map: &mut T) {
map.each_mut(|(k, v)| {
if k != "key1" {
*v += 1;
}
});
map.insert("key2".into(), 10);
}
fn main() {
let mut hm: HashMap<String, i128> = [("One".into(), 1), ("Two".into(), 2)]
.iter()
.cloned()
.collect();
let mut btm: BTreeMap<String, i128> = [("Five".into(), 5), ("Six".into(), 6)]
.iter()
.cloned()
.collect();
dbg!(&hm);
dbg!(&btm);
edit_map_values(&mut hm);
edit_map_values(&mut btm);
dbg!(&hm);
dbg!(&btm);
}
Way back before the 1.0 release, there used to be Map and MutableMap traits, but they have been removed before stabilization. The Rust type system is currently unable to express these traits in a nice way due to the lack of higher kinded types.
The eclectic crate provides experimental collection traits, but they haven't been updated for a year, so I'm not sure they are still useful for recent versions of Rust.
Further information:
Does Rust have Collection traits?
No common trait for Map types? (Rust language forum)
Associated type constructors, part 1: basic concepts and introduction (blog post by Niko Matsakis)
Generic associated type RFC
While there is no common Map trait, you could use a combination of other traits to operate on an Iterator to achieve similar functionality. Although this might not be very memory efficient due to cloning, and also a bit involved depending on the kind of operation you are trying to perform. The operation you tried to do may be implemented like this:
fn edit_map_values<I>(map: &mut I)
where
I: Clone + IntoIterator<Item = (String, i128)> + std::iter::FromIterator<(String, i128)>,
{
// Since into_iter consumes self, we have to clone here.
let (keys, _values): (Vec<String>, Vec<_>) = map.clone().into_iter().unzip();
*map = map
.clone()
.into_iter()
// iterating while mutating entries can be done with map
.map(|mut tuple| {
if !keys.contains(&"key1".to_string()) {
tuple.1 += 1;
}
tuple
})
// inserting an element can be done with chain and once
.chain(std::iter::once(("key2".into(), 10)))
.collect();
// removing an element could be done with filter
// removing and altering elements could be done with filter_map
// etc.
}
fn main() {
use std::collections::{BTreeMap, HashMap};
{
let mut m = HashMap::new();
m.insert("a".to_string(), 0);
m.insert("key3".to_string(), 1);
edit_map_values(&mut m);
println!("{:#?}", m);
}
{
let mut m = BTreeMap::new();
m.insert("a".to_string(), 0);
m.insert("key3".to_string(), 1);
edit_map_values(&mut m);
println!("{:#?}", m);
}
}
Both times the output is the same, except for the order of the HashMap of course:
{
"a": 1,
"key2": 10,
"key3": 2,
}

How to back a HashMap with a Vec

I tried implementing a generic A* tree search algorithm. The important part is in the function hucs marked with a TODO:
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::cmp::Ordering;
pub trait SearchTree<A> {
fn available_actions(&self) -> Vec<A>;
fn apply_action(&self, act: &A) -> Self;
}
pub trait CostSearchTree<A>: SearchTree<A> + Eq {
fn action_cost(&self, act: &A) -> f64;
}
/// Node in the expanded search tree for uniform cost search with heuristic
struct HucsNode<A, T>
where
T: CostSearchTree<A>,
{
cost: f64,
heuristic_cost: f64,
parent_index: usize,
action: Option<A>,
tree: T,
}
impl<A, T> PartialEq for HucsNode<A, T>
where
T: CostSearchTree<A>,
{
fn eq(&self, other: &HucsNode<A, T>) -> bool {
// Can be used for closed list checking if we just compare the trees
return self.tree == other.tree;
}
}
impl<A, T> Eq for HucsNode<A, T>
where
T: CostSearchTree<A>,
{
}
impl<A, T> PartialOrd for HucsNode<A, T>
where
T: CostSearchTree<A>,
{
fn partial_cmp(&self, other: &HucsNode<A, T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<A, T> Ord for HucsNode<A, T>
where
T: CostSearchTree<A>,
{
fn cmp(&self, other: &HucsNode<A, T>) -> Ordering {
let self_cost = self.cost + self.heuristic_cost;
let other_cost = other.cost + other.heuristic_cost;
// Flip for min-heap
match other_cost.partial_cmp(&self_cost) {
Some(order) => order,
_ => Ordering::Equal,
}
}
}
/// Perform a uniform cost search with a monotonous heuristic function on a search tree.
/// Returns a sequence of actions if a state is found that satisfies the predicate or None if the search terminates before.
pub fn hucs<A, T: CostSearchTree<A> + Hash>(
tree: T,
predicate: &Fn(&T) -> bool,
heuristic: &Fn(&T) -> f64,
) -> Option<Vec<A>> {
let mut node_heap = BinaryHeap::new() as BinaryHeap<HucsNode<A, T>>;
// Push the initial node onto the tree
node_heap.push(HucsNode {
action: None,
parent_index: usize::max_value(),
cost: 0.0,
heuristic_cost: heuristic(&tree),
tree: tree,
});
let mut old_nodes = Vec::new();
let mut last_node_index = 0 as usize;
'outer: while let Some(current_node) = node_heap.pop() {
// Break borrows with scope so current_node can be moved out
{
if predicate(&current_node.tree) {
return Some(form_action_sequence(current_node, old_nodes));
}
// Check if visited nodes already contains this tree with less cost
// TODO: Time complexity is hardly ideal
for old_node in old_nodes.iter() {
if old_node.tree == current_node.tree && old_node.cost <= current_node.cost {
continue 'outer;
}
}
let ref current_tree = current_node.tree;
for action in current_tree.available_actions() {
let action_cost = current_tree.action_cost(&action);
let new_tree = current_tree.apply_action(&action);
let new_cost = current_node.cost + action_cost;
let new_node = HucsNode {
action: Some(action),
cost: new_cost,
parent_index: last_node_index,
heuristic_cost: heuristic(&new_tree),
tree: new_tree,
};
node_heap.push(new_node);
}
}
old_nodes.push(current_node);
last_node_index += 1;
}
return None;
}
/// Restore the sequence of actions that was used to get to this node by climbing the tree of expanded nodes
fn form_action_sequence<A, T: CostSearchTree<A>>(
leaf: HucsNode<A, T>,
mut older_nodes: Vec<HucsNode<A, T>>,
) -> Vec<A> {
let mut action_vector = Vec::new();
let mut current = leaf;
while let Some(action) = current.action {
action_vector.insert(0, action);
// Safe to swap as nodes' parents are always before them
current = older_nodes.swap_remove(current.parent_index);
}
return action_vector;
}
The problem is that looking up whether the current node was in the old nodes by scanning over the old nodes takes way too long. Therefore I wanted to add a HashMap. Since I however also need to be able to access the old nodes by indices to form the solution action sequence at the end, I also need to keep the Vec. To solve this I tried adding a wrapper that I can insert into the HashMap as a key that just looks up its content in the Vec like this:
use std::hash::Hash;
use std::hash::Hasher;
struct BackedHashWrapper<'a, T: 'a + Hash + Eq> {
source: &'a Vec<T>,
index: usize,
}
impl<A, T> Hash for HucsNode<A, T>
where
T: CostSearchTree<A> + Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.tree.hash(state);
}
}
impl<'a, T> Hash for BackedHashWrapper<'a, T>
where
T: Eq + Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.source[self.index].hash(state);
}
}
impl<'a, T> PartialEq for BackedHashWrapper<'a, T>
where
T: Eq + Hash,
{
fn eq(&self, other: &BackedHashWrapper<T>) -> bool {
self.source[self.index] == other.source[other.index]
}
}
impl<'a, T> Eq for BackedHashWrapper<'a, T>
where
T: Eq + Hash,
{
}
I cannot figure out how to implement this in the hucs method, I tried the following just for adding elements to the hashmap
...
let mut old_nodes = Vec::new();
let mut hash_map = HashMap::new();
...
...
hash_map.insert(BackedHashWrapper {source: &old_nodes, index: last_node_index}, current_node.cost);
old_nodes.push(current_node);
last_node_index += 1;
...
but the borrow checker will not allow me to create such a BackedHashWrapper while the source vector is mutable. Clearly I am doing this completely the wrong way, so how could I accomplish this without having to clone either the tree or any actions?
I suppose it is easier to use other type of backing storage (TypedArena from typed-arena crate, for example).
But taking the question at face value, the problem you are dealing with is caused by Rust borrowing rules. That is you can't have shared (&) and mutable (&mut) references or multiple mutable references to the same object in the same scope.
hash_map in your example holds shared references to the vector, "freezing" it, which makes it impossible to modify the vector while hash_map is in the scope.
Solution to this problem is interior mutability pattern.
In your case, you can use RefCell<Vec<T>> to be able to modify vector while holding multiple references to it.
use std::cell::RefCell;
type RVec<T> = RefCell<Vec<T>>;
struct BackedHashWrapper<'a, T: 'a + Hash + Eq> {
source: &'a RVec<T>,
index: usize,
}
...
impl<'a, T> Hash for BackedHashWrapper<'a, T>
where
T: Eq + Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.source.borrow()[self.index].hash(state);
}
}
...
// Similar changes for Eq and PartialEq
...
let mut old_nodes: RVec<_> = RefCell::default();
let mut hash_map = HashMap::new();
...
...
hash_map.insert(BackedHashWrapper {source: &old_nodes, index: last_node_index}, current_node.cost);
old_nodes.borrow_mut().push(current_node);
last_node_index += 1;
...
Maybe a couple of borrow()s and borrow_mut()s will be required in other places.

How to implement Index over a wrapped HashMap?

I would like to implement the Index trait for a wrapper type over the HashMap type:
use std::collections::HashMap;
use std::option::Option;
#[cfg(test)]
use std::ops::Index;
#[derive(Debug, Clone)]
struct Value {
val: i32,
}
#[derive(Debug, Clone)]
pub struct HMShadow {
hashmap: HashMap<String, Value>,
}
impl HMShadow {
fn new() -> HMShadow {
HMShadow {
hashmap: {
HashMap::<String, Value>::new()
},
}
}
fn insert<S>(&mut self, key: S, element: Value) -> Option<Value>
where S: Into<String>
{
self.hashmap.insert(key.into(), element)
}
fn get(&mut self, key: &str) -> &mut Value {
self.hashmap.get_mut(key).expect("no entry found for key")
}
}
fn main()
{
let mut s: HMShadow = HMShadow::new();
let v: Value = Value { val : 5 };
let _ = s.insert("test", v);
println!("{:?}", s);
println!("Get: {}", s.get("test").val);
}
#[cfg(test)]
impl<'a> Index<&'a str> for HMShadow {
type Output = &'a mut Value;
fn index(&self, key: &'a str) -> &&'a mut Value {
match self.hashmap.get_mut(key) {
Some(val) => &mut val,
_ => panic!("no entry found for key"),
}
}
}
#[cfg(test)]
#[test]
fn test_index() {
let mut s: HMShadow = HMShadow::new();
let v: Value = Value { val : 5 };
let _ = s.insert("test", v);
println!("{:?}", s);
println!("Index: {}", s["test"].val);
}
Doing rustc --test tt.rs the compiler says:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> tt.rs:51:28
|
51 | match self.hashmap.get_mut(key) {
| ^^^^^^^
|
help: consider using an explicit lifetime parameter as shown: fn index(&'a self, key: &'a str) -> &&'a mut Value
--> tt.rs:50:5
|
50 | fn index(&self, key: &'a str) -> &&'a mut Value {
| ^
But I cannot do fn index(&'a self, key: &'a str) -> &&'a mut Value because the Index trait does not allow &'a self and the compiler errors:
error[E0308]: method not compatible with trait
Since your question is pretty unclear, I will reinterpret it as follows:
I am trying to implement Index for my struct, but somehow it doesn't work.
The errors
After looking at the compiler errors, it became clear that your implementation of Index is wrong for many reasons:
The Index trait defines a function called index, which returns an immutable reference to the value. However, you are trying to return a mutable reference. Of course, Rust complains that the method you are implementing is incompatible with the trait.
The Output associated type of your Index implementation should not be wrapped in a reference. Therefore, instead of type Output = &'a mut Value; you need type Output = Value;
The lifetimes of key and the output in the index function are unrelated, but you use 'a for both.
You need to make the Value type public in order to use it in a trait implementation.
The code
A correct and simple implementation of Index would be:
impl<'a> Index<&'a str> for HMShadow {
type Output = Value;
fn index(&self, key: &'a str) -> &Value {
&self.hashmap[key]
}
}
I guess, I was looking for
#[cfg(test)]
impl<'a> IndexMut<&'a str> for HMShadow {
fn index_mut<'b>(&'b mut self, key: &'a str) -> &'b mut Value {
self.hashmap.get_mut(key).expect("no entry found for key")
}
}

Resources