Calling a method on a value inside a mutable Option - rust

I have a mutable Option type and I'm trying to mutate the thing inside the Some but I can't figure out how to do it.
use std::net::TcpStream;
use std::io::Write;
struct Foo {
stream: Option<TcpStream>,
}
impl Foo {
fn send(&mut self) {
self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
}
}
This produces the error:
error[E0596]: cannot borrow immutable argument `x` as mutable
--> src/main.rs:10:29
|
10 | self.stream.map(|x| x.write(b"test")).expect("Couldn't write");
| - ^ cannot borrow mutably
| |
| consider changing this to `mut x`
Can someone try to implement send as an example to help me understand?

As Vladimir Matveev points out, if let is even nicer, and is more idiomatic than iterating over the Option:
#[derive(Debug)]
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x += 1;
}
}
}
fn main() {
let mut f = Foo { stream: Some(0) };
println!("{:?}", f);
f.send();
println!("{:?}", f);
}
As of Rust 1.26, match ergonomics allows you to omit some of the keywords:
impl Foo {
fn send(&mut self) {
if let Some(x) = &mut self.stream {
*x += 1;
}
}
}
Before that, I would usually use Option::as_mut:
impl Foo {
fn send(&mut self) {
if let Some(x) = self.stream.as_mut() {
*x += 1;
}
}
}
Other options
As Vladimir Matveev points out (again!), map is usually used to transform data, not for side effects (which I agree with). You could instead use iter_mut (or the shorthand of &mut collection), as I feel that iteration is usually for side effects. I like this because it means our code can avoid having a conditional:
impl Foo {
fn send(&mut self) {
for x in &mut self.stream {
*x += 1;
}
}
}
You can also leverage the IntoIterator implementation for Option:
impl Foo {
fn send(&mut self) {
for x in self.stream.as_mut() {
*x += 1;
}
}
}

As a follow-up to #idupree's variant, it is also possible to use if-let syntax:
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
if let Some(ref mut x) = self.stream {
*x = 0;
}
}
}
I'd also argue that this is more idiomatic than map(), because map() method is intended for transforming an Option, not executing side effects (and assignment is a side effect).

You can match on the Option directly, like the following (showing i32 rather than TcpStream):
struct Foo {
stream: Option<i32>,
}
impl Foo {
fn send(&mut self) {
match self.stream {
Some(ref mut x) => {
*x = 0;
}
None => {}
}
}
}
(Not sure whether that's the most idiomatic way to do it.)

Related

Cannot return reference to temporary value with RwLock and iterators

I haven't found an answer to this in other questions.
I have reduced my problem to the following:
use std::sync::RwLock;
pub fn main() {
iter_lock().for_each(|v| {
println!("{}", v);
});
}
fn get_lock<'a>() -> &'a RwLock<Vec<u32>> {
static mut lock: RwLock<Vec<u32>> = RwLock::new(Vec::new());
unsafe { &lock }
}
fn iter_lock<'a>() -> impl std::iter::Iterator<Item = &'a u32> {
get_lock().read().unwrap().iter()
}
playground
The code above will not compile and give the following error:
error[E0515]: cannot return reference to temporary value
--> src/main.rs:15:5
|
15 | get_lock().read().unwrap().iter()
| --------------------------^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
|
= help: use `.collect()` to allocate the iterator
Note that the static mut is not necessary in the code above, but I need it because I need to define a variable inside of an impl block.
I need to return an iterator, not a Vec because I am trying to avoid any allocations, and this function will always be used to iterate.
How can I solve this issue? I'm not afraid of using unsafe code, so unsafe suggestions are also welcome.
You can try something like this:
use std::sync::{RwLock, RwLockReadGuard};
pub fn main() {
let data = Data::new(&[1, 2, 3]);
data.iter().for_each(|x| println!("{:?}", x));
}
struct Data {
inner: RwLock<Vec<u32>>,
}
impl Data {
fn new(vec: &[u32]) -> Self {
Self {
inner: RwLock::new(vec.to_vec()),
}
}
fn iter(&self) -> Iter<'_> {
let d = self.inner.read().unwrap();
Iter::new(d)
}
}
struct Iter<'a> {
inner: RwLockReadGuard<'a, Vec<u32>>,
current_index: usize,
}
impl<'a> Iter<'a> {
pub fn new(inner: RwLockReadGuard<'a, Vec<u32>>) -> Iter<'a> {
Self {
inner,
current_index: 0,
}
}
}
impl Iterator for Iter<'_> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.current_index >= self.inner.len() {
return None;
}
let item = &self.inner[self.current_index];
self.current_index += 1;
Some(*item)
}
}

Cannot borrow `*self` as mutable more than once at a time when using an iterator

I'm trying to learn rust making a game with SDL2. I have a struct GameEngine which has ownership of some variables to control the game state.
The method GameEngine::run() is responsible to manage the game loop. I want this method to do 2 things:
Check if some event is related to closing the game and in this case break the loop
For any other kind of event I want to call a method GameEngine::handle_event() to handle it
The problem is that the compiler is refusing to accept my code telling me I'm trying to borrow self as mutable more than once. The first borrow happen on this line:
let event_poll_iterator = self.event_pump.poll_iter();
and the second on this:
self.handle_event(event);
As I'm a newbie in Rust, I'm getting stuck in this error.
The complete code:
pub mod engine {
use std::time::Duration;
use sdl2::{EventPump, Sdl};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::render::WindowCanvas;
fn get_canvas(sdl_context: &Sdl) -> WindowCanvas {
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
.window("SDL2 Snake Game", 800, 600)
.position_centered()
.opengl()
.build()
.map_err(|e| e.to_string()).unwrap();
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string()).unwrap();
canvas.set_draw_color(Color::BLACK);
canvas
}
pub struct GameEngine {
context: Sdl,
event_pump: EventPump,
canvas: WindowCanvas,
}
impl GameEngine {
pub fn new() -> Self {
let context = sdl2::init().unwrap();
let canvas = get_canvas(&context);
let event_pump = context.event_pump().unwrap();
GameEngine { context, canvas, event_pump }
}
fn redraw(&mut self) {
self.canvas.clear();
self.canvas.present();
}
fn handle_event(&mut self, event: Event) {
todo!()
}
pub fn run(&mut self) {
'game_loop: loop {
let event_poll_iterator = self.event_pump.poll_iter();
for event in event_poll_iterator {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'game_loop,
_ => {
self.handle_event(event);
}
}
}
self.redraw();
std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 30));
}
}
}
}
Edit
I could reproduce the same problem (I think) with a much smaller example:
struct List {
v: Vec<u32>
}
impl List {
fn increment(&mut self, x: &mut u32) {
*x += 1;
}
fn iter(&mut self) {
for x in &mut self.v {
self.increment(x);
}
}
}
fn main() {
let mut list = List { v: vec![1, 2, 3] };
list.iter();
assert!(list.v == vec![2, 3, 4]);
}
Error log:
λ cargo run
Compiling rustlings v4.7.1 (/home/luizalabs/repositories/rust/rustlings)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:12:13
|
11 | for x in &mut self.v {
| -----------
| |
| first mutable borrow occurs here
| first borrow later used here
12 | self.increment(x);
| ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `rustlings` due to previous error
The problem is, self.handle_event could modify whatever you are iterating over (in this case event_poll_iterator). If you are modifying what the iterator is iterating over, you might want to consider cloning the iterator. If self.handle_event isn't modifying the iterator, you have to show the borrow checker that you are not modifying the iterator. One option is to inline self.handle_event. Another option is to pass whatever you are modifying as mutable to self.handle_event. Here is a simple example of what is going on:
#[derive(Debug)]
struct Point {
x: i32,
y: i32
}
struct Points {
points: Vec<Point>,
num_points: usize
}
impl Points {
fn bar(&mut self, point: &mut Point) {
println!("{:?}", point)
}
fn foo(&mut self) {
for p in &mut self.points {
self.bar(p);
}
}
}
Inlining would change foo as such:
fn foo(&mut self) {
for p in &mut self.points {
println!("{:?}", p); // modified line
}
}
Tried to simplify your example
fn main() {
let i: i32 = 4326;
let b = i.to_le_bytes();
for i in 0..4 {
println!("{}", b[i]);
}
}
pub struct GameEngine {
event_pump: EventPump,
}
pub struct EventPump {
}
impl EventPump {
pub fn poll_iter(&mut self) -> Vec<i32> {
vec![0, 1, 2]
}
}
impl GameEngine {
pub fn new() -> Self {
GameEngine {
event_pump: EventPump { },
}
}
fn redraw(&mut self) {
}
fn handle_event(&mut self, _event: i32) {
todo!()
}
pub fn run(&mut self) {
loop {
let ep = self.event_pump.poll_iter();
let event_poll_iterator = ep.iter();
for event in event_poll_iterator {
match event {
_ => {
self.handle_event(*event);
}
}
}
self.redraw();
}
}
}
Hope without losing sense. Seems it compiled ok.
It changes Iter to vector instance but I'm not sure if that matters.

How do I implement Deref + DerefMut properly?

Hi I have the following this tutorial for learning more in depth what can I do with rust so I'm aware that this might now be the proper way to do thing. Here is the repository which contains all the code to take a in depth look. I'm having a global vga writer instance which needs to be safe for data races so using lazy_static I initialize it. What I want to do is is to be able to aquire the lock only when I actually print the string so that I implement fmt::Write on the WrappedWriter instead of the Writer to not obtain the lock over the spin::Mutex when I want to print a string rather I want to obtain the lock after the params were formatted . But when I call this the write function:
crate::vga_buffer::WRITER.write_fmt(args).unwrap();
I get the following error:
Compiling rust_os v0.1.0 (D:\Workspace\Organiztions\home\rust\rust_os)
error[E0055]: reached the recursion limit while auto-dereferencing `vga_buffer::writer::WrappedWriter`
--> src\lib.rs:19:31
|
19 | crate::vga_buffer::WRITER.write_fmt(args).unwrap();
| ^^^^^^^^^ deref recursion limit reached
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`rust_os`)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0055`.
error: could not compile `rust_os`.
Here is the implementation of the Writer + WrappedWriter
use core::fmt;
use lazy_static::lazy_static;
use volatile::Volatile;
use super::color::*;
use super::screen_character;
use core::ops::{DerefMut, Deref};
// #[allow(dead_code)]
// use crate::serial_print;
// use crate::serial_println;
pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct Buffer {
chars: [[Volatile<screen_character::ScreenCharacter>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
pub struct Writer {
column_position: usize,
color_code: ColorCode,
buffer: &'static mut Buffer,
}
impl Writer {
pub fn new(column_position: usize,
color_code: ColorCode) -> Writer {
return Writer {
column_position,
color_code,
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
};
}
}
impl Writer {
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => self.new_line(),
byte => {
if self.column_position >= BUFFER_WIDTH {
self.new_line();
}
let row = BUFFER_HEIGHT - 1;
let col = self.column_position;
let color_code = self.color_code;
self.buffer.chars[row][col].write(screen_character::ScreenCharacter::new(byte, color_code));
self.column_position += 1;
}
}
}
pub fn write_string(&mut self, s: &str) {
for byte in s.bytes() {
match byte {
// printable ASCII byte or newline
0x20..=0x7e | b'\n' => self.write_byte(byte),
// not part of printable ASCII range
_ => self.write_byte(0xfe),
}
}
}
fn new_line(&mut self) {
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
let current_character = self.buffer.chars[row][col].read();
self.buffer.chars[row - 1][col].write(current_character);
}
}
self.clear_row(BUFFER_HEIGHT - 1);
self.column_position = 0;
}
fn clear_row(&mut self, row_index: usize) {
let blank = screen_character::ScreenCharacter::new(b' ', self.color_code);
for col in 0..BUFFER_WIDTH {
self.buffer.chars[row_index][col].write(blank);
}
}
}
// impl fmt::Write for Writer {
// fn write_str(&mut self, s: &str) -> fmt::Result {
// self.write_string(s);
// Ok(())
// }
// }
struct WrappedWriter {
value: spin::Mutex<Writer>
}
impl fmt::Write for WrappedWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.value.lock().write_string(s);
Ok(())
}
}
impl Deref for WrappedWriter {
type Target = WrappedWriter;
fn deref(&self) -> &Self::Target {
return self;
}
}
impl DerefMut for WrappedWriter {
fn deref_mut(&mut self) -> &mut Self::Target {
return self;
}
}
lazy_static! {
pub static ref WRITER: WrappedWriter = {
let writerInstance = WrappedWriter {
value: spin::Mutex::new(
Writer::new(0, ColorCode::new(Color::Yellow, Color::Black))
)
};
writerInstance
};
}
#[test_case]
fn test_println_output() {
let test_str = "Some test string that fits on a single line";
println!("{}", test_str);
for (char_index, char) in test_str.chars().enumerate() {
let screen_char = WRITER.value.lock().buffer.chars[BUFFER_HEIGHT - 2][char_index].read();
assert_eq!(char::from(screen_char.ascii_character), char);
}
}
Deref + DerefMut Were implemented because I get the following error without them but then again I didn't knew on what should I deref cause I don't actually need to deref from my point of view this are needed because write_fmt gets a mut of self
error[E0596]: cannot borrow data in a dereference of `vga_buffer::writer::WRITER` as mutable
--> src\lib.rs:19:5
|
19 | crate::vga_buffer::WRITER.write_fmt(args).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `vga_buffer::writer::WRITER`
WrappedWriter currently derefs to itself, which derefs to itself, which derefs to itself, and so on, which is why you reach the recursion limit. You probably want to make it deref to the Writer inside by obtaining a lock.

How to change the variable from inside Fn closure in Rust?

I have the following code (playground):
struct A {
pub vec: Vec<u64>,
}
impl A {
fn perform_for_all<F: Fn(&mut u64)>(&mut self, f: F) {
for mut i in &mut self.vec {
f(i);
}
}
}
fn main() {
let mut a = A {
vec: vec![1, 3, 44, 2, 4, 5, 6],
};
let mut done = false;
a.perform_for_all(|v| {
println!("value: {:?}", v);
done = true;
});
if !done {
a.perform_for_all(|v| {
println!("value {:?}", v);
});
}
}
The following errors occur:
error[E0594]: cannot assign to `done`, as it is a captured variable in a `Fn` closure
--> src/main.rs:21:9
|
21 | done = true;
| ^^^^^^^^^^^ cannot assign
|
help: consider changing this to accept closures that implement `FnMut`
--> src/main.rs:19:23
|
19 | a.perform_for_all(|v| {
| _______________________^
20 | | println!("value: {:?}", v);
21 | | done = true;
22 | | });
| |_____^
I have a list of loaded objects and a list of objects in a database. I need a function that takes a closure and executes it on the loaded objects and if we don't have the objects in the list, execute it on a list of objects from the database.
That function looks like:
pub fn perform_for_match_with_mark<F>(&mut self, mark: MatchMark, f: F)
where
F: Fn(&mut GameMatch),
{
self.perform_for_all_matches(
|m| {
// runtime list
if let Game::Match(ref mut gm) = *m {
if gm.match_stamp().mark == mark {
f(gm);
}
}
},
None,
);
// if we have called `f` above - don't execute lines below.
let tx = self.match_tx.clone();
GamesDatabase::perform_for_match_with_mark(mark, |ms| {
// database
self.perform_for_all_matches(
|m| {
if let Game::Match(ref gm) = *m {
if gm.match_stamp().id == ms.id {
f(&mut GameMatch::new_with_match_stamp(
tx.clone(),
ms.clone(),
gm.needs_server_set,
gm.server_id,
))
}
}
},
None,
);
});
}
We have to operate on objects from the database only if we were unable to find them in runtime list. That is why I decided to make a variable which says "we already found these objects in the list, leave the database alone".
Change your perform_for_all function to use FnMut instead of Fn:
fn perform_for_all<F>(&mut self, mut f: F)
where
F: FnMut(&mut u64),
{
for mut i in &mut self.vec {
f(&mut i);
}
}
As Peter said, there is some compiler magic going on.
The signature for Fn::call is:
extern "rust-call" fn call(&self, args: Args) -> Self::Output
This takes an immutable reference to self, which is why you can't modify any of the captured variables.
The signature for FnMut::call_mut lets you mutate variables because it takes &mut self:
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output
By changing your closure from Fn to FnMut, you allow it to modify its captured variables, given that the references you pass to it are mutable.
Just to expand a little on SplittyDev's answer.
When you use a closure, the compiler does some magic to let the closure access variables in its environment. Effectively it will create a new struct, whose members are the variables that you tried to access.
It's not exactly this (which won't actually compile), but it's a reasonable approximation conceptually:
struct Closure_1 {
done: bool
}
impl FnMut<&mut u64> for Closure_1 {
fn call_mut(&mut self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true;
}
}
And when you call it, those variables will be borrowed or copied (or moved if you use move keyword).
let mut c1 = Closure_1 { done : done };
a.perform_for_all(|v| c1.call(&v));
done = c1.done;
When the closure modifies its environment, it cannot be a Fn because it must also mutate the variables on itself:
impl Fn<&mut u64> for Closure_1 {
fn call(&self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true; // Can't do this because self is not a mutable ref
}
}
See The Rust Programming Language section on closures and their environment for more information.

match + RefCell = X does not live long enough

I need to initialize an item (fn init(&mut self) -> Option<&Error>), and use it if there's no errors.
pub fn add(&mut self, mut m: Box<Item>) {
if let None = m.init() {
self.items.push(m);
}
}
This works unless I need to check the error if there's any:
pub fn add(&mut self, mut m: Box<Item>) {
if let Some(e) = m.init() {
//process error
} else {
self.items.push(m); //won't compile, m is borrowed
}
}
Fair. Need to use RefCell. However, this
pub fn add(&mut self, mut m: Box<Item>) {
let rc = RefCell::new(m);
if let Some(e) = rc.borrow_mut().init() {
//process error
} else {
self.items.push(rc.borrow_mut())
}
}
ends with weird
error: `rc` does not live long enough
if let Some(e) = rc.borrow_mut().init() {
^~
note: reference must be valid for the destruction scope surrounding block at 75:60...
pub fn add_module(&mut self, mut m: Box<RuntimeModule>) {
^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 76:30
let rc = RefCell::new(m);
I tried nearly everything: plain box, Rc'ed box, RefCell'ed box, Rc'ed RefCell. Tried to adapt this answer to my case. No use.
Complete example:
use std::cell::RefCell;
use std::error::Error;
trait Item {
fn init(&mut self) -> Option<&Error>;
}
struct ItemImpl {}
impl Item for ItemImpl {
fn init(&mut self) -> Option<&Error> {
None
}
}
//===========================================
struct Storage {
items: Vec<Box<Item>>,
}
impl Storage {
fn new() -> Storage {
Storage{
items: Vec::new(),
}
}
fn add(&mut self, mut m: Box<Item>) {
let rc = RefCell::new(m);
if let Some(e) = rc.borrow_mut().init() {
//process error
} else {
self.items.push(*rc.borrow_mut())
}
}
}
fn main() {
let mut s = Storage::new();
let mut i = Box::new(ItemImpl{});
s.add(i);
}
(Playground)
UPD: As suggested, this is a "family" of mistakes like I did, it is well explained here. However my case has easier solution.
As krdln suggested, the simplest way to work around this is to return in the if block and thus scope the borrow:
fn add(&mut self, mut m: Box<Item>) {
if let Some(e) = m.init() {
//process error
return;
}
self.items.push(m);
}

Resources