Reputation: 13
I am new to Rust having gone through only the Rust book, working on a project which requires capturing a screenshot of the primary display. I am using the scrap crate for this.
fn screen_shot_and_save_image(iter:i32) {
let one_second = Duration::new(1, 0);
let one_frame = one_second / 60;
let mut buffer = None;
let display = Display::primary().expect("Couldn't find primary display.");
let mut capturer = Capturer::new(display).expect("Couldn't begin capture.");
let (mut w, mut h) = (capturer.width(), capturer.height());;
while buffer.is_none() {
// Wait until there's a frame.
match capturer.frame() {
Ok(buf) => {
buffer = Some(buf);
}
Err(error) => {
if error.kind() == WouldBlock {
// Keep spinning.
thread::sleep(one_frame);
continue;
} else {
panic!("Error: {}", error);
}
}
};
}
//work with buffer
}
the capturer.frame() has a signature of
scrap::common::dxgi::Capturer
pub fn frame<'a>(&'a mut self) -> io::Result<Frame<'a>>
Error:
error[E0499]: cannot borrow `capturer` as mutable more than once at a time
--> src\main.rs:103:15
|
103 | match capturer.frame() {
| ^^^^^^^^^^^^^^^^ `capturer` was mutably borrowed here in the previous iteration of the loop
Based on similar questions, I understand that Rust does not allow mutable borrows in a loop. However I need to use this function in a while loop, incase I get the WouldBlock error, which returns a blank image intermittently. I cannot make good sense of the compiler error or suggestion so any help will be much appreciated, thank you!
Upvotes: 1
Views: 1608
Reputation: 13750
I think you can get the borrow checker to stop complaining if you're a bit more explicit about exactly when your loop will end:
let buffer = loop {
// Wait until there's a frame.
match capturer.frame() {
Ok(buf) => {
break buf;
}
Err(error) => { ... }
};
}
If this works (I haven't tested it), it's because it proves to the borrow checker that the result of capturer.frame()
, which is stored in buffer
, won't exist concurrently with another call to capturer.frame()
. The compiler is not very smart, and can't see that buffer.is_none()
implies buffer
isn't storing capturer.frame()
.
Upvotes: 1
Reputation: 22501
I will assume this is your minimal example, because I couldn't get your example running:
use std::{thread, time::Duration};
struct Capturer {
data: String,
iteration: u32,
}
impl Capturer {
fn new() -> Self {
Self {
data: "Captured data!".to_string(),
iteration: 0,
}
}
fn frame(&mut self) -> Result<&str, Box<dyn std::error::Error>> {
self.iteration += 1;
if self.iteration == 3 {
Ok(&self.data)
} else {
Err(format!("Incorrect iteration: {}", self.iteration).into())
}
}
}
fn main() {
let mut buffer = None;
let mut capturer = Capturer::new();
while buffer.is_none() {
// Wait until there's a frame.
match capturer.frame() {
Ok(buf) => {
buffer = Some(buf);
}
Err(error) => {
println!("No result yet: {}", error);
thread::sleep(Duration::from_millis(100));
}
};
}
//work with buffer
println!("Received: '{}'", buffer.unwrap());
}
error[E0499]: cannot borrow `capturer` as mutable more than once at a time
--> src/main.rs:31:15
|
31 | match capturer.frame() {
| ^^^^^^^^^^^^^^^^ `capturer` was mutably borrowed here in the previous iteration of the loop
The return value of capturer.frame()
contains a lifetime. That means that some part of the return value is referencing capturer
. And because .frame()
uses self
as &mut self
, it is assumed that this is a mutable borrow, and there can only ever be one mutable borrow at a time.
Because you store the result outside of the loop, Rust does not allow you to loop any more, because the next iteration of the loop might call .frame()
again although you still have a mutable reference.
I think the real solution here is to avoid all of that and use the fact that Rust loops themselves can have a value:
use std::{thread, time::Duration};
struct Capturer {
data: String,
iteration: u32,
}
impl Capturer {
fn new() -> Self {
Self {
data: "Captured data!".to_string(),
iteration: 0,
}
}
fn frame(&mut self) -> Result<&str, Box<dyn std::error::Error>> {
self.iteration += 1;
if self.iteration == 3 {
Ok(&self.data)
} else {
Err(format!("Incorrect iteration: {}", self.iteration).into())
}
}
}
fn main() {
let mut capturer = Capturer::new();
let buffer = loop {
// Wait until there's a frame.
match capturer.frame() {
Ok(buf) => {
break buf;
}
Err(error) => {
println!("No result yet: {}", error);
thread::sleep(Duration::from_millis(100));
}
};
};
//work with buffer
println!("Received: '{}'", buffer);
}
No result yet: Incorrect iteration: 1
No result yet: Incorrect iteration: 2
Received: 'Captured data!'
Upvotes: 3