I'm trying to create a simple minesweeper in Rust. For this I want to create a Grid object, holding all Case objects. When a Case is clicked, it notifies the Grid.
I want all cases to have a Weak reference to the grid. Why does the borrow checker prevent me from doing so?
Quoting the doc:
Weak is a version of Rc that holds a non-owning reference to the managed allocation.
link marked by the comment should not be owning the grid, yet the compiler tells me the value has been moved.
use std::rc::{Rc, Weak};
pub struct Grid {
dimensions: (usize, usize),
n_mines: usize,
content: Vec<Vec<Case>>,
}
impl Grid {
pub fn new(dimensions: (usize, usize), n_mines: usize) -> Self {
let (n, m) = dimensions;
let mines: Vec<Vec<Case>> = Vec::with_capacity(m);
let mut grid = Self {
dimensions: dimensions,
n_mines: n_mines,
content: mines,
};
let link = Rc::new(grid);
let link = Rc::downgrade(&link); // here link loses the ownership of grid, right ?
println!("{}\n", grid.n_mines);
for i in 0..m {
let mut line: Vec<Case> = Vec::with_capacity(n);
for j in 0..n {
let case = Case::new_with_parent((i, j), Weak::clone(&link));
line.push(case)
}
grid.content.push(line);
}
grid
}
pub fn click_neighbours(&mut self, coordinates: (usize, usize)) {
let surrouding = vec![(0, 0), (0, 1)]; // not a real implementation
for coord in surrouding {
self.content[coord.0][coord.1].click();
}
}
}
pub struct Case {
pub coordinates: (usize, usize),
parent: Weak<Grid>,
}
impl Case {
pub fn new_with_parent(coordinates: (usize, usize), parent: Weak<Grid>) -> Case {
Self {
coordinates: coordinates,
parent: parent,
}
}
pub fn click(&mut self) {
match self.parent.upgrade() {
Some(x) => x.click_neighbours(self.coordinates),
None => println!("whatever, not the issue here"),
}
}
}
fn main() {
let grid = Grid::new((10, 10), 5);
}
I tried multiple variation around enforcement of borrowing rules at runtime by putting the grid content into a RefCell. I'm also currently trying to adapt the Observer design pattern implementation in Rust to my problem, but without any success so far.
There is a misconception here, by moving the grid here:
let link = Rc::new(grid);
you irrevocably destroy grid, nothing you do to link brings back your old grid.
The only thing that could do so would be to use Rc::try_unwrap to unwrap link and assign it back to grid,
but that's not what you want to do here.
Instead you can additionally wrap the grid in a RefCell like so:
let grid = Rc::new(RefCell::new(grid));
Which in then lets you edit the grid inside with borrow_mut:
grid.borrow_mut().content.push(line);
You can see in PitaJ's answer how the full listing of your code should look like.
grid is moved into Rc::new, so you can't use it any longer. You'll have to return that Rc from Grid::new
You can't modify the value within the Rc while you hold Weak references to it. So you'll have to wrap the inner value in a RefCell as well. Otherwise the loop where you create the lines is impossible
Here's a valid version of your code:
use std::cell::RefCell;
use std::rc::{Rc, Weak};
pub struct Grid {
dimensions: (usize, usize),
n_mines: usize,
content: Vec<Vec<Case>>,
}
impl Grid {
pub fn new(dimensions: (usize, usize), n_mines: usize) -> Rc<RefCell<Self>> {
let (n, m) = dimensions;
let mines: Vec<Vec<Case>> = Vec::with_capacity(m);
let grid = Rc::new(RefCell::new(Self {
dimensions: dimensions,
n_mines: n_mines,
content: mines,
}));
let link_weak = Rc::downgrade(&grid);
println!("{}\n", grid.borrow().n_mines);
{
// avoid repeatedly calling `borrow_mut` in the loop
let grid_mut = &mut *grid.borrow_mut();
for i in 0..m {
let mut line: Vec<Case> = Vec::with_capacity(n);
for j in 0..n {
let case = Case::new_with_parent((i, j), Weak::clone(&link_weak));
line.push(case)
}
grid_mut.content.push(line);
}
}
grid
}
pub fn click_neighbours(&mut self, coordinates: (usize, usize)) {
let surrouding = vec![(0, 0), (0, 1)]; // not a real implementation
for coord in surrouding {
self.content[coord.0][coord.1].click();
}
}
}
pub struct Case {
pub coordinates: (usize, usize),
parent: Weak<RefCell<Grid>>,
}
impl Case {
pub fn new_with_parent(coordinates: (usize, usize), parent: Weak<RefCell<Grid>>) -> Case {
Self {
coordinates: coordinates,
parent: parent,
}
}
pub fn click(&mut self) {
match self.parent.upgrade() {
Some(grid) => grid.borrow_mut().click_neighbours(self.coordinates),
None => println!("whatever, not the issue here"),
}
}
}
fn main() {
let grid = Grid::new((10, 10), 5);
}
playground
Related
I am practicing rust and decided to create a Matrix ops/factorization project.
Basically I want to be able to process the underlying vector in multiple threads. Since I will be providing each thread non-overlapping indexes (which may or may not be contiguous) and the threads will be joined before the end of whatever function created them, there is no need for a lock /synchronization.
I know that there are several crates that can do this, but I would like to know if there is a relatively idiomatic crate-free way to implement it on my own.
The best I could come up with is (simplified the code a bit):
use std::thread;
//This represents the Matrix
#[derive(Debug, Clone)]
pub struct MainStruct {
pub data: Vec<f64>,
}
//This is the bit that will be shared by the threads,
//ideally it should have its lifetime tied to that of MainStruct
//but i have no idea how to make phantomdata work in this case
#[derive(Debug, Clone)]
pub struct SliceTest {
pub data: Vec<SubSlice>,
}
//This struct is to hide *mut f64 to allow it to be shared to other threads
#[derive(Debug, Clone)]
pub struct SubSlice {
pub data: *mut f64,
}
impl MainStruct {
pub fn slice(&mut self) -> (SliceTest, SliceTest) {
let mut out_vec_odd: Vec<SubSlice> = Vec::new();
let mut out_vec_even: Vec<SubSlice> = Vec::new();
unsafe {
let ptr = self.data.as_mut_ptr();
for i in 0..self.data.len() {
let ptr_to_push = ptr.add(i);
//Non contiguous idxs
if i % 2 == 0 {
out_vec_even.push(SubSlice{data:ptr_to_push});
} else {
out_vec_odd.push(SubSlice{data:ptr_to_push});
}
}
}
(SliceTest{data: out_vec_even}, SliceTest{data: out_vec_odd})
}
}
impl SubSlice {
pub fn set(&self, val: f64) {
unsafe {*(self.data) = val;}
}
}
unsafe impl Send for SliceTest {}
unsafe impl Send for SubSlice {}
fn main() {
let mut maindata = MainStruct {
data: vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
};
let (mut outvec1, mut outvec2) = maindata.slice();
let mut threads = Vec::new();
threads.push(
thread::spawn(move || {
for i in 0..outvec1.data.len() {
outvec1.data[i].set(999.9);
}
})
);
threads.push(
thread::spawn(move || {
for i in 0..outvec2.data.len() {
outvec2.data[i].set(999.9);
}
})
);
for handles in threads {
handles.join();
}
println!("maindata = {:?}", maindata.data);
}
EDIT:
Following kmdreko suggestion below, got the code to work exactly how I wanted it without using unsafe code, yay!
Of course in terms of performance it may be cheaper to copy the f64 slices than to create mutable reference vectors unless your struct is filled with other structs instead of f64
extern crate crossbeam;
use crossbeam::thread;
#[derive(Debug, Clone)]
pub struct Matrix {
data: Vec<f64>,
m: usize, //number of rows
n: usize, //number of cols
}
...
impl Matrix {
...
pub fn get_data_mut(&mut self) -> &mut Vec<f64> {
&mut self.data
}
pub fn calculate_idx(max_cols: usize, i: usize, j: usize) -> usize {
let actual_idx = j + max_cols * i;
actual_idx
}
//Get individual mutable references for contiguous indexes (rows)
pub fn get_all_row_slices(&mut self) -> Vec<Vec<&mut f64>> {
let max_cols = self.max_cols();
let max_rows = self.max_rows();
let inner_data = self.get_data_mut().chunks_mut(max_cols);
let mut out_vec: Vec<Vec<&mut f64>> = Vec::with_capacity(max_rows);
for chunk in inner_data {
let row_vec = chunk.iter_mut().collect();
out_vec.push(row_vec);
}
out_vec
}
//Get mutable references for disjoint indexes (columns)
pub fn get_all_col_slices(&mut self) -> Vec<Vec<&mut f64>> {
let max_cols = self.max_cols();
let max_rows = self.max_rows();
let inner_data = self.get_data_mut().chunks_mut(max_cols);
let mut out_vec: Vec<Vec<&mut f64>> = Vec::with_capacity(max_cols);
for _ in 0..max_cols {
out_vec.push(Vec::with_capacity(max_rows));
}
let mut inner_idx = 0;
for chunk in inner_data {
let row_vec_it = chunk.iter_mut();
for elem in row_vec_it {
out_vec[inner_idx].push(elem);
inner_idx += 1;
}
inner_idx = 0;
}
out_vec
}
...
}
fn test_multithreading() {
fn test(in_vec: Vec<&mut f64>) {
for elem in in_vec {
*elem = 33.3;
}
}
fn launch_task(mat: &mut Matrix, f: fn(Vec<&mut f64>)) {
let test_vec = mat.get_all_row_slices();
thread::scope(|s| {
for elem in test_vec.into_iter() {
s.spawn(move |_| {
println!("Spawning thread...");
f(elem);
});
}
}).unwrap();
}
let rows = 4;
let cols = 3;
//new function code omitted, returns Result<Self, MatrixError>
let mut mat = Matrix::new(rows, cols).unwrap()
launch_task(&mut mat, test);
for i in 0..rows {
for j in 0..cols {
//Requires index trait implemented for matrix
assert_eq!(mat[(i, j)], 33.3);
}
}
}
This API is unsound. Since there is no lifetime annotation binding SliceTest and SubSlice to the MainStruct, they can be preserved after the data has been destroyed and if used would result in use-after-free errors.
Its easy to make it safe though; you can use .iter_mut() to get distinct mutable references to your elements:
pub fn slice(&mut self) -> (Vec<&mut f64>, Vec<&mut f64>) {
let mut out_vec_even = vec![];
let mut out_vec_odd = vec![];
for (i, item_ref) in self.data.iter_mut().enumerate() {
if i % 2 == 0 {
out_vec_even.push(item_ref);
} else {
out_vec_odd.push(item_ref);
}
}
(out_vec_even, out_vec_odd)
}
However, this surfaces another problem: thread::spawn cannot hold references to local variables. The threads created are allowed to live beyond the scope they're created in, so even though you did .join() them, you aren't required to. This was a potential issue in your original code as well, just the compiler couldn't warn about it.
There's no easy way to solve this. You'd need to use a non-referential way to use data on the other threads, but that would be using Arc, which doesn't allow mutating its data, so you'd have to resort to a Mutex, which is what you've tried to avoid.
I would suggest reaching for scope from the crossbeam crate, which does allow you to spawn threads that reference local data. I know you've wanted to avoid using crates, but this is the best solution in my opinion.
See a working version on the playground.
See:
How to get multiple mutable references to elements in a Vec?
Can you specify a non-static lifetime for threads?
I'am a junior developer with Rust language.
I come from JavaScript and a lot of features and specificities are still unclear to me.
Currently, I'm looking to build my own ECS (entity component system) system in Rust.
I'am stay stuck when i want to get an component from an entity.
Actualy i store component in entity with an dyn boxed vector, it's that a good way?
My code:
enum ComponentEnum {
Position,
Size
}
trait Component {}
// Position Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Position {
x: i32,
y: i32
}
// Size Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Size {
height: i32,
width: i32
}
impl Component for Position {}
impl Component for Size {}
struct Entity {
id: usize,
components: Vec<Box<dyn Component>>
}
impl Entity {
fn new(index: usize) -> Self {
Entity { id: index, components: vec![] }
}
// Add a component in Entity
fn add_component<T: 'static + Component>(&mut self, component: T) {
self.components.push(Box::new(component));
}
}
struct EntityStore {
entities: Vec<Entity>,
current_index: usize,
}
impl EntityStore {
fn new() -> EntityStore {
EntityStore { entities: vec![], current_index: 0 }
}
fn generate_index(&self) -> usize {
unimplemented!();
}
// Stop creation system and update EntityStore current_index
fn end(&mut self) -> &mut Entity {
let entity = self.entities.get_mut(self.current_index).unwrap();
self.current_index = self.current_index + 1;
entity
}
fn create_entity(&mut self) -> &mut Self {
let mut entity = Entity::new(self.current_index);
self.entities.push(entity);
self
}
// Add component to entity
fn with_component<T: 'static + Component>(&mut self, component: T) -> &mut Self {
let mut entity = self.entities.get_mut(self.current_index).unwrap();
entity.add_component(component);
self
}
}
fn main() {
let mut es = EntityStore::new();
// Make entity
let mut entity1 = es
.create_entity()
.with_component(Position { x: 0, y: 0 })
.with_component(Size { height: 10, width: 10 })
.end();
// Get entity position component
// let component_position_entity1 = entity1.get_component(ComponentEnum::Position);
}
How can I get my Position component back from my entity?
EDIT:
Here, a test function to get a component (in Entity implementation) :
fn get_component(&mut self, component_enum: ComponentEnum) { //want return Position or Size component
let mut entity_components = &self.components;
// Search component by Name ?
// Currently, i try to compare Component trait with Component Enum element...
let component = entity_components
.iter_mut()
.find(|component| component == component_enum)
.unwrap();
// Here, the component type is "&mut Box<dyn Component>" but i want type like "&mut Position" or "&mut Size"
component // Here i need to return a Position or Size struct component, but i have Component Trait so i can't use Position/Size functions
}
Thanks.
I would use enums to differentiate between components types (bear in mind I have very little experience with ECS systems in general). Then you have various ways of getting one type, but I have made a method get_component, that takes a closure to use when finding the right components. You can then pass it a closure that checks for a position component specifically.
This is my implementation, based on your example:
// Position Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Position {
x: i32,
y: i32
}
// Size Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Size {
height: i32,
width: i32
}
#[derive(PartialEq, PartialOrd, Debug)]
enum Component {
Position(Position),
Size(Size)
}
struct Entity {
id: usize,
components: Vec<Component>
}
impl Entity {
fn new(index: usize) -> Self {
Entity { id: index, components: vec![] }
}
// Add a component in Entity
fn add_component(&mut self, component: Component) {
self.components.push(component);
}
fn get_component(&self, pred: impl Fn(&&Component) -> bool) -> Option<&Component>{
self.components.iter().find(pred)
}
}
struct EntityStore {
entities: Vec<Entity>,
current_index: usize,
}
impl EntityStore {
fn new() -> EntityStore {
EntityStore { entities: vec![], current_index: 0 }
}
fn generate_index(&self) -> usize {
unimplemented!();
}
// Stop creation system and update EntityStore current_index
fn end(&mut self) -> &mut Entity {
let entity = self.entities.get_mut(self.current_index).unwrap();
self.current_index = self.current_index + 1;
entity
}
fn create_entity(&mut self) -> &mut Self {
let mut entity = Entity::new(self.current_index);
self.entities.push(entity);
self
}
// Add component to entity
fn with_component(&mut self, component: Component) -> &mut Self {
let mut entity = self.entities.get_mut(self.current_index).unwrap();
entity.add_component(component);
self
}
}
fn main() {
let mut es = EntityStore::new();
// Make entity
let mut entity1 = es
.create_entity()
.with_component(Component::Position(Position { x: 0, y: 0 }))
.with_component(Component::Size(Size { height: 10, width: 10 }))
.end();
// Get entity position component
let component_position_entity1 = entity1.get_component(|c| if let Component::Position(_) = c { true} else {false});
println!("{:?}", component_position_entity1);
}
Note that there many alternatives to my get_component, but my main point is to use enums to differentiate component types and to not use Box<dyn Component>.
#user4815162342 posted this in the comments to index into entity.components directly:
like this:
fn main() {
let mut es = EntityStore::new();
// Make entity
let mut entity1 = es
.create_entity()
.with_component(Position { x: 0, y: 0 })
.with_component(Size { height: 10, width: 10 })
.end();
// Get entity position component
let v0 = &entity1.components[0];
let v1 = &entity1.components[1];
v0.display();
v1.display();
}
But since the index depends on the order that the entities were added, then you'd be much better off storing the entities components in a hash map, or with an enum tag to make it clearer what each component is.
I am trying to write a program that will find the longest path in the graph (i.e. the greatest depth) for a directed graph which is always a rooted or multi-rooted tree.
The specs of the assignment require I use DFS and memoization, but multiple mutable references occur when performing the DFS. Is there any other way to do this?
I thought about using HashMaps instead of internal Graph fields, but it would just produce the same error on mutability of the HashMap. I've found several other questions on the Rust user forum and here, but none of them gives the advise on how to resolve this. Am I supposed to use "unsafe" code or some other strategy?
use std::io;
struct Node {
neighbours: Vec<usize>,
depth: usize,
visited: bool,
}
impl Node {
fn new() -> Node { Node { neighbours: Vec::new(), depth: 0, visited: false } }
fn add_neighbour(&mut self, node: usize) { self.neighbours.push(node); }
fn neighbourhood_size(&self) -> usize { self.neighbours.len() }
}
struct Graph {
nodes: Vec<Node>,
depth: usize,
}
impl Graph {
fn new() -> Graph { Graph { nodes: Vec::new(), depth: 0} }
fn nodes_number(&self) -> usize { self.nodes.len()}
fn add_node(&mut self) { self.nodes.push(Node::new()); }
fn node(&mut self, i: usize) -> &mut Node { &mut self.nodes[i] }
fn dfs(graph: &mut Graph, index: usize) {
if !graph.node(index).visited {
graph.node(index).visited = true;
}
match graph.node(index).neighbourhood_size() == 0 {
true => { graph.node(index).depth = 1; },
false => {
for &i in graph.node(index).neighbours.iter() {
// multiple mutable references
Graph::dfs(graph, i);
}
graph.node(index).depth =
1 + graph.node(index).
neighbours.iter().
map(|&x| graph.node(x).depth).
max().unwrap();
}
}
if graph.node(index).depth > graph.depth {
graph.depth = graph.node(index).depth;
}
}
}
fn main() {
let mut input_line = String::new();
io::stdin().read_line(&mut input_line);
let n = input_line.trim().parse::<usize>().unwrap();
// to avoid counting from 0 or excessive use of (-1)
let mut graph = Graph::new(); graph.add_node();
for _ in 0 .. n {
let mut input_line = String::new();
io::stdin().read_line(&mut input_line);
let separated = input_line.
split(" ").
collect::<Vec<_>>();
let u = separated[0].trim().parse::<usize>().unwrap();
let v = separated[1].trim().parse::<usize>().unwrap();
if graph.nodes_number() <= u { graph.add_node(); }
if graph.nodes_number() <= v { graph.add_node(); }
graph.node(u).add_neighbour(v);
}
let n = graph.nodes_number();
for i in 1 .. n {
if !graph.node(i).visited { Graph::dfs(&mut graph, i); }
}
println!("{}", graph.depth);
}
Instead of taking a copy of the vector before iterating over it, you could also iterate over the indices:
for ni in 0..graph.node(index).neighbours.len() {
let neighbour = graph.node(index).neighbours[ni];
Graph::dfs(graph, neighbour);
}
The neighbours vector gets still borrowed for performing the iteration, but not for the whole course of the iteration:
graph.node(index).neighbours.len(): once at the beginning of the iteration for getting the length
let neighbour = graph.node(index).neighbours[ni];: in each iteration step for getting the neighbour at the current index
Like the copy approach, this solution is based on the constraint that the neighbours vector you are iterating over will not be changed by the call to dfs.
You can solve the remaining issues regarding multiple references in your code by providing immutable access to the graph nodes:
fn node_mut(&mut self, i: usize) -> &mut Node {
&mut self.nodes[i]
}
fn node(&self, i: usize) -> &Node {
&self.nodes[i]
}
Only make use of the mutable access via node_mut where necessary. For example when adding a neighbour: graph.node_mut(u).add_neighbour(v);
You are modifying your graph structure while iterating through a vector contained within it. The compiler has no way of verifying that you do not add or remove from the vector during the iteration, which would invalidate the iterator. This is the intuitive reason for the error.
The easiest way to avoid this is to take a copy of the vector before iterating over it, so the compiler can see that the iterator does not change. This is a little suboptimal but resolves the error for now. Another lifetime error is solved in a similar way (but without much cost) by copying the depth into a variable before doing a comparison.
use std::io;
use std::env;
struct Node {
neighbours: Vec<usize>,
depth: usize,
visited: bool,
}
impl Node {
fn new() -> Node {
Node {
neighbours: Vec::new(),
depth: 0,
visited: false,
}
}
fn add_neighbour(&mut self, node: usize) {
self.neighbours.push(node);
}
fn neighbourhood_size(&self) -> usize {
self.neighbours.len()
}
}
struct Graph {
nodes: Vec<Node>,
depth: usize,
}
impl Graph {
fn new() -> Graph {
Graph {
nodes: Vec::new(),
depth: 0,
}
}
fn nodes_number(&self) -> usize {
self.nodes.len()
}
fn add_node(&mut self) {
self.nodes.push(Node::new());
}
fn node(&mut self, i: usize) -> &mut Node {
&mut self.nodes[i]
}
fn dfs(graph: &mut Graph, index: usize) {
if !graph.node(index).visited {
graph.node(index).visited = true;
}
match graph.node(index).neighbourhood_size() == 0 {
true => {
graph.node(index).depth = 1;
}
false => {
let neighbours = graph.node(index).neighbours.clone();
for &i in neighbours.iter() {
// multiple mutable references
Graph::dfs(graph, i);
}
graph.node(index).depth = 1
+ neighbours
.iter()
.map(|&x| graph.node(x).depth)
.max()
.unwrap();
}
}
let depth = graph.node(index).depth;
if depth > graph.depth {
graph.depth = graph.node(index).depth;
}
}
}
fn main() {
env::set_var("RUST_BACKTRACE", "1");
let mut input_line = String::new();
io::stdin().read_line(&mut input_line);
let n = input_line.trim().parse::<usize>().unwrap();
// to avoid counting from 0 or excessive use of (-1)
let mut graph = Graph::new();
graph.add_node();
for _ in 0..n {
let mut input_line = String::new();
io::stdin().read_line(&mut input_line);
let separated = input_line.split(" ").collect::<Vec<_>>();
let u = separated[0].trim().parse::<usize>().unwrap();
let v = separated[1].trim().parse::<usize>().unwrap();
if graph.nodes_number() <= u {
graph.add_node();
}
if graph.nodes_number() <= v {
graph.add_node();
}
graph.node(u).add_neighbour(v);
}
let n = graph.nodes_number();
for i in 1..n {
if !graph.node(i).visited {
Graph::dfs(&mut graph, i);
}
}
println!("{}", graph.depth);
}
playground
If you were to modify your approach so that you did not mutate the structure during the search (i.e. you stored the visited data elsewhere), the code would work without this copy. This would also be more friendly to concurrent use.
I have a struct Foo:
struct Foo {
v: String,
// Other data not important for the question
}
I want to handle a data stream and save the result into Vec<Foo> and also create an index for this Vec<Foo> on the field Foo::v.
I want to use a HashMap<&str, usize> for the index, where the keys will be &Foo::v and the value is the position in the Vec<Foo>, but I'm open to other suggestions.
I want to do the data stream handling as fast as possible, which requires not doing obvious things twice.
For example, I want to:
allocate a String only once per one data stream reading
not search the index twice, once to check that the key does not exist, once for inserting new key.
not increase the run time by using Rc or RefCell.
The borrow checker does not allow this code:
let mut l = Vec::<Foo>::new();
{
let mut hash = HashMap::<&str, usize>::new();
//here is loop in real code, like:
//let mut s: String;
//while get_s(&mut s) {
let s = "aaa".to_string();
let idx: usize = match hash.entry(&s) { //a
Occupied(ent) => {
*ent.get()
}
Vacant(ent) => {
l.push(Foo { v: s }); //b
ent.insert(l.len() - 1);
l.len() - 1
}
};
// do something with idx
}
There are multiple problems:
hash.entry borrows the key so s must have a "bigger" lifetime than hash
I want to move s at line (b), while I have a read-only reference at line (a)
So how should I implement this simple algorithm without an extra call to String::clone or calling HashMap::get after calling HashMap::insert?
In general, what you are trying to accomplish is unsafe and Rust is correctly preventing you from doing something you shouldn't. For a simple example why, consider a Vec<u8>. If the vector has one item and a capacity of one, adding another value to the vector will cause a re-allocation and copying of all the values in the vector, invalidating any references into the vector. This would cause all of your keys in your index to point to arbitrary memory addresses, thus leading to unsafe behavior. The compiler prevents that.
In this case, there's two extra pieces of information that the compiler is unaware of but the programmer isn't:
There's an extra indirection — String is heap-allocated, so moving the pointer to that heap allocation isn't really a problem.
The String will never be changed. If it were, then it might reallocate, invalidating the referred-to address. Using a Box<[str]> instead of a String would be a way to enforce this via the type system.
In cases like this, it is OK to use unsafe code, so long as you properly document why it's not unsafe.
use std::collections::HashMap;
#[derive(Debug)]
struct Player {
name: String,
}
fn main() {
let names = ["alice", "bob", "clarice", "danny", "eustice", "frank"];
let mut players = Vec::new();
let mut index = HashMap::new();
for &name in &names {
let player = Player { name: name.into() };
let idx = players.len();
// I copied this code from Stack Overflow without reading the prose
// that describes why this unsafe block is actually safe
let stable_name: &str = unsafe { &*(player.name.as_str() as *const str) };
players.push(player);
index.insert(idx, stable_name);
}
for (k, v) in &index {
println!("{:?} -> {:?}", k, v);
}
for v in &players {
println!("{:?}", v);
}
}
However, my guess is that you don't want this code in your main method but want to return it from some function. That will be a problem, as you will quickly run into Why can't I store a value and a reference to that value in the same struct?.
Honestly, there's styles of code that don't fit well within Rust's limitations. If you run into these, you could:
decide that Rust isn't a good fit for you or your problem.
use unsafe code, preferably thoroughly tested and only exposing a safe API.
investigate alternate representations.
For example, I'd probably rewrite the code to have the index be the primary owner of the key:
use std::collections::BTreeMap;
#[derive(Debug)]
struct Player<'a> {
name: &'a str,
data: &'a PlayerData,
}
#[derive(Debug)]
struct PlayerData {
hit_points: u8,
}
#[derive(Debug)]
struct Players(BTreeMap<String, PlayerData>);
impl Players {
fn new<I>(iter: I) -> Self
where
I: IntoIterator,
I::Item: Into<String>,
{
let players = iter
.into_iter()
.map(|name| (name.into(), PlayerData { hit_points: 100 }))
.collect();
Players(players)
}
fn get<'a>(&'a self, name: &'a str) -> Option<Player<'a>> {
self.0.get(name).map(|data| Player { name, data })
}
}
fn main() {
let names = ["alice", "bob", "clarice", "danny", "eustice", "frank"];
let players = Players::new(names.iter().copied());
for (k, v) in &players.0 {
println!("{:?} -> {:?}", k, v);
}
println!("{:?}", players.get("eustice"));
}
Alternatively, as shown in What's the idiomatic way to make a lookup table which uses field of the item as the key?, you could wrap your type and store it in a set container instead:
use std::collections::BTreeSet;
#[derive(Debug, PartialEq, Eq)]
struct Player {
name: String,
hit_points: u8,
}
#[derive(Debug, Eq)]
struct PlayerByName(Player);
impl PlayerByName {
fn key(&self) -> &str {
&self.0.name
}
}
impl PartialOrd for PlayerByName {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PlayerByName {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.key().cmp(&other.key())
}
}
impl PartialEq for PlayerByName {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
impl std::borrow::Borrow<str> for PlayerByName {
fn borrow(&self) -> &str {
self.key()
}
}
#[derive(Debug)]
struct Players(BTreeSet<PlayerByName>);
impl Players {
fn new<I>(iter: I) -> Self
where
I: IntoIterator,
I::Item: Into<String>,
{
let players = iter
.into_iter()
.map(|name| {
PlayerByName(Player {
name: name.into(),
hit_points: 100,
})
})
.collect();
Players(players)
}
fn get(&self, name: &str) -> Option<&Player> {
self.0.get(name).map(|pbn| &pbn.0)
}
}
fn main() {
let names = ["alice", "bob", "clarice", "danny", "eustice", "frank"];
let players = Players::new(names.iter().copied());
for player in &players.0 {
println!("{:?}", player.0);
}
println!("{:?}", players.get("eustice"));
}
not increase the run time by using Rc or RefCell
Guessing about performance characteristics without performing profiling is never a good idea. I honestly don't believe that there'd be a noticeable performance loss from incrementing an integer when a value is cloned or dropped. If the problem required both an index and a vector, then I would reach for some kind of shared ownership.
not increase the run time by using Rc or RefCell.
#Shepmaster already demonstrated accomplishing this using unsafe, once you have I would encourage you to check how much Rc actually would cost you. Here is a full version with Rc:
use std::{
collections::{hash_map::Entry, HashMap},
rc::Rc,
};
#[derive(Debug)]
struct Foo {
v: Rc<str>,
}
#[derive(Debug)]
struct Collection {
vec: Vec<Foo>,
index: HashMap<Rc<str>, usize>,
}
impl Foo {
fn new(s: &str) -> Foo {
Foo {
v: s.into(),
}
}
}
impl Collection {
fn new() -> Collection {
Collection {
vec: Vec::new(),
index: HashMap::new(),
}
}
fn insert(&mut self, foo: Foo) {
match self.index.entry(foo.v.clone()) {
Entry::Occupied(o) => panic!(
"Duplicate entry for: {}, {:?} inserted before {:?}",
foo.v,
o.get(),
foo
),
Entry::Vacant(v) => v.insert(self.vec.len()),
};
self.vec.push(foo)
}
}
fn main() {
let mut collection = Collection::new();
for foo in vec![Foo::new("Hello"), Foo::new("World"), Foo::new("Go!")] {
collection.insert(foo)
}
println!("{:?}", collection);
}
The error is:
error: `s` does not live long enough
--> <anon>:27:5
|
16 | let idx: usize = match hash.entry(&s) { //a
| - borrow occurs here
...
27 | }
| ^ `s` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
The note: at the end is where the answer is.
s must outlive hash because you are using &s as a key in the HashMap. This reference will become invalid when s is dropped. But, as the note says, hash will be dropped after s. A quick fix is to swap the order of their declarations:
let s = "aaa".to_string();
let mut hash = HashMap::<&str, usize>::new();
But now you have another problem:
error[E0505]: cannot move out of `s` because it is borrowed
--> <anon>:22:33
|
17 | let idx: usize = match hash.entry(&s) { //a
| - borrow of `s` occurs here
...
22 | l.push(Foo { v: s }); //b
| ^ move out of `s` occurs here
This one is more obvious. s is borrowed by the Entry, which will live to the end of the block. Cloning s will fix that:
l.push(Foo { v: s.clone() }); //b
I only want to allocate s only once, not cloning it
But the type of Foo.v is String, so it will own its own copy of the str anyway. Just that type means you have to copy the s.
You can replace it with a &str instead which will allow it to stay as a reference into s:
struct Foo<'a> {
v: &'a str,
}
pub fn main() {
// s now lives longer than l
let s = "aaa".to_string();
let mut l = Vec::<Foo>::new();
{
let mut hash = HashMap::<&str, usize>::new();
let idx: usize = match hash.entry(&s) {
Occupied(ent) => {
*ent.get()
}
Vacant(ent) => {
l.push(Foo { v: &s });
ent.insert(l.len() - 1);
l.len() - 1
}
};
}
}
Note that, previously I had to move the declaration of s to before hash, so that it would outlive it. But now, l holds a reference to s, so it has to be declared even earlier, so that it outlives l.
I am just learning Rust. I am trying to create a builder struct for my Game struct. Here is the code:
struct Input {
keys_pressed: HashMap<VirtualKeyCode, bool>,
}
pub struct GameBuilder {
settings: GameSettings,
input: Input,
}
impl GameBuilder {
pub fn new() -> GameBuilder {
GameBuilder {
settings: GameSettings {
window_dimensions: (800, 600),
title: "".to_string(),
},
input: Input {
keys_pressed: HashMap::new(),
}
}
}
pub fn with_dimensions(&mut self, width: u32, height: u32) -> &mut GameBuilder {
self.settings.window_dimensions = (width, height);
self
}
pub fn with_title(&mut self, title: &str) -> &mut GameBuilder {
self.settings.title = title.to_string();
self
}
pub fn game_keys(&mut self, keys: Vec<VirtualKeyCode>) -> &mut GameBuilder {
for key in keys {
self.input.keys_pressed.insert(key, false);
}
self
}
pub fn build(&self) -> Game {
let (width, height) = self.settings.window_dimensions;
Game {
display: glutin::WindowBuilder::new()
.with_dimensions(width, height)
.with_title(self.settings.title.to_string())
.build_glium()
.ok()
.expect("Error in WindowBuilder"),
state: GameState::Running,
input: self.input,
}
}
}
But this code complains in the last line input: self.input with this:
error: cannot move out of borrowed content
I think I understand why. Since the argument passed in the function is &self, I cannot take ownership of it, and that what the last line is doing.
I thought that maybe changing &self to self would work, but then the compile argues that I cannot mutate self.
There is also the Copy trait from what I know, and that maybe should solve the problem. But Input is basically a HashMap, which means that a copy could be expensive if the hash itself is too big.
How would be a nice way of solving this problem?
Edit:
I tried doing this:
#[derive(Debug, Copy, Clone)]
struct Input {
keys_pressed: HashMap<VirtualKeyCode, bool>,
}
But the compiler complains:
error: the trait `Copy` may not be implemented for this type; field `keys_pressed` does not implement `Copy`
Given how your method signatures are formulated, you appear to be aiming for chaining:
let game = GameBuilder::new().with_dimensions(...)
.with_title(...)
.build();
In Rust, this requires that GameBuilder be passed by value:
pub fn with_dimensions(self, ...) -> GameBuilder {
// ...
}
And in order to be able to mutate self within the method, you need to make it mut:
pub fn with_dimensions(mut self, ...) -> GameBuilder {
}
If you change the signature of with_dimensions, with_title, game_keys and build to take self by value (mut self if mutation is intended), then chaining should work.
Try the builder pattern with Option and take()
Example:
#[derive(PartialEq, Debug)]
struct Game {
window: Window,
}
#[derive(PartialEq, Debug)]
struct Window {
title: String,
dimensions: (u32, u32),
}
struct GameBuilder {
window_title: Option<String>,
window_dimensions: Option<(u32, u32)>,
}
impl GameBuilder {
fn new() -> Self {
Self {
window_title: None,
window_dimensions: None,
}
}
fn window_title(&mut self, window_title: &str) -> &mut Self {
self.window_title = Some(window_title.to_owned());
self
}
fn window_dimensions(&mut self, width: u32, height: u32) -> &mut Self {
self.window_dimensions = Some((width, height));
self
}
fn build(&mut self) -> Result<Game, Box<dyn std::error::Error>> {
Ok(Game {
window: Window {
// `ok_or(&str)?` works, because From<&str> is implemented for Box<dyn Error>
title: self.window_title.take().ok_or("window_title is unset")?,
dimensions: self
.window_dimensions
.take()
.ok_or("window_dimensions are unset")?,
},
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let mut builder = GameBuilder::new();
builder.window_title("Awesome Builder");
builder.window_dimensions(800, 600);
let game = builder.build();
assert_eq!(
game.expect("build success"),
Game {
window: Window {
title: "Awesome Builder".into(),
dimensions: (800, 600)
}
}
);
}
#[test]
fn test_1() {
let game2 = GameBuilder::new()
.window_title("Busy Builder")
.window_dimensions(1234, 123)
.build();
assert_eq!(
game2.expect("build success"),
Game {
window: Window {
title: "Busy Builder".into(),
dimensions: (1234, 123),
}
}
)
}
}