I am trying to read all content from a file into a vector using the async rust api:
let mut content : Vec<u8> = vec![];
let f = tokio::fs::File::open("myfilecontent")
.and_then(|mut myfile| {
myfile.read_buf(&mut content)
});
f.await;
But I keep getting this error:
error[E0515]: cannot return value referencing function parameter `myfile`
Which sounds reasonable, because the future returned by the closure must keep a reference to the file, but as this closure is the only user of the file it could take ownership. How can I convince rust to do the right thing?
You can use an async move block like so:
use futures::TryFutureExt;
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut content: Vec<u8> = vec![];
let f = tokio::fs::File::open("myfilecontent").and_then(
|mut myfile| async move { myfile.read_buf(&mut content).await },
);
f.await?;
Ok(())
}
or skip and_then and go straight for .await:
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut content: Vec<u8> = vec![];
let mut myfile = tokio::fs::File::open("myfilecontent").await?;
myfile.read_buf(&mut content).await?;
Ok(())
}
Related
How do I get back at the original data if I have a reference to a Box<dyn Any> which itself wraps a mutable reference to some Thing?
i.e.
Box<&mut Thing> --> &mut Box<dyn Any> --> &mut Thing
I can get this to work for the case where it wraps an object, but not where it wraps a mutable reference.
Here is an MWE (please excuse the unsafe code to fake the example data!)
use std::any::Any;
struct Thing;
fn main() {
// Fake some data for the example
let mut thing = Thing {};
let thing_ref = &mut thing;
let thing_static_ref: &'static mut Thing = unsafe { std::mem::transmute(thing_ref) };
let boxed_thing = Box::new(thing_static_ref);
let mut boxed_any: Box<dyn Any> = boxed_thing;
let boxed_any_ref = &mut boxed_any;
// Try to get our data back
let unboxed_any = boxed_any_ref.as_mut();
let maybe_unboxed_thing = unboxed_any.downcast_mut::<Thing>();
if maybe_unboxed_thing.is_none(){
println!("Failed");
} else {
println!("OK");
}
}
I've been trying to separate all my Redis operations in a separate implementation, but I got this error when I passed the Redis reference to the implementation.
error[E0596]: cannot borrow `*self.redis_client` as mutable, as it is behind a `&` reference
--> src/main.rs:30:21
|
30 | let _: () = self.redis_client.set("key", "value").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
Code:
use redis::{Commands};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let redis_client_uri = String::from("redis://127.0.0.1:6379");
let redis_client = redis::Client::open(redis_client_uri)?;
let mut redis = redis_client
.get_connection()
.expect("Failed to connect redis");
let batch = vec!["Sample value".to_string()];
CacheOperations::new(&redis, batch);
Ok(())
}
struct CacheOperations<'a> {
redis_client: &'a redis::Connection,
batch: Vec<String>,
}
impl<'a> CacheOperations<'a> {
fn new(redis_client: &'a redis::Connection, batch: Vec<String>) -> Self {
Self {
redis_client: &redis_client,
batch: batch,
}
}
fn insert_batch(self) {
let _: () = self.redis_client.set("key", "value").unwrap();
}
}
You just need to use the mut keyword to indicate that a reference or value is mutable. When you use it with a lifetime, the mut goes after the lifetime usage (Ex: &'abc mut x).
use redis::{Commands};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let redis_client_uri = String::from("redis://127.0.0.1:6379");
let redis_client = redis::Client::open(redis_client_uri)?;
let mut redis = redis_client
.get_connection()
.expect("Failed to connect redis");
let batch = vec!["Sample value".to_string()];
// Use a mutable reference when creating the CacheOperations
CacheOperations::new(&mut redis, batch);
Ok(())
}
struct CacheOperations<'a> {
// Store a mutable reference
redis_client: &'a mut redis::Connection,
batch: Vec<String>,
}
impl<'a> CacheOperations<'a> {
// We need to consume a mutable reference
fn new(redis_client: &'a mut redis::Connection, batch: Vec<String>) -> Self {
// No need to reference the reference, we can store it as-is
Self { redis_client, batch }
}
// While not required here, you can use mut self to state that self is mutable
// when a function consumes self as an owned value.
fn insert_batch(mut self) {
let _: () = self.redis_client.set("key", "value").unwrap();
}
}
I'm writing a program that will concurrently call an API and fill a VecDeque with integers from the response JSON. Since these will be running concurrently, I wrapped the VecDeque in a Mutex. When I test the code and try to push an integer into the VecDeque, I get an error.
#[tokio::main]
async fn main() -> Result<(), ()> {
let client = Client::new();
let mut tank = Mutex::new(VecDeque::new());
// let mut tank = VecDeque::with_capacity(10);
tank.push_back(2);
tank.push_back(3);
println!("{:?}", tank);
Ok(())
}
tank.push_back(2);
^^^^^^^^^ method not found in `std::sync::Mutex<VecDeque<_>>
Do I need to create the VecDeque inside a struct instead?
As per the suggestion, I needed to lock before changing the VecDeque. It works now:
#[tokio::main]
async fn main() -> Result<(), ()> {
let client = Client::new();
let mut tank = Mutex::new(VecDeque::new());
let mut tank = tank.lock().unwrap().push_back(2);
let mut tank = tank.lock().unwrap().push_back(3);
println!("{:?}", tank);
Ok(())
}
I am trying to write a tcp server with async-std, in order to resolve the confilice of read-write borrow check, I found a strange way:
use async_std::prelude::*;
use async_std::task;
use async_std::net::TcpListener;
use async_std::io::BufReader;
fn main() {
task::block_on(async {
let listener = TcpListener::bind("0.0.0.0:9000").await.unwrap();
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
let stream = stream.unwrap();
println!("Client Addr: {:?}", stream.peer_addr().unwrap());
task::spawn( async move {
let (reader, mut writer) = (&stream, &stream); // Stange here <-----
let reader = BufReader::new(reader);
let mut lines = reader.lines();
while let Some(line) = lines.next().await {
let mut line = line.unwrap();
line.push('x');
line.push('\n');
writer.write_all(line.as_bytes()).await.unwrap();
}
});
}
});
}
Strange:
let (reader, mut writer) = (&stream, &stream); // Stange here <-----
I wrote a verification program following this method:
fn main() {
let mut arr = vec![1, 2, 3, 4];
let (r, mut w) = (&arr, &arr);
for v in r.iter() {
if v == &2 {
w.push(5);
}
}
dbg!(arr);
}
got error:
error[E0596]: cannot borrow `*w` as mutable, as it is behind a `&` reference
can anyone explain it ?
This works because TcpStream has the following impls:
impl Read for TcpStream
impl Write for TcpStream
impl<'_> Read for &'_ TcpStream
impl<'_> Write for &'_ TcpStream
The first two are the "normal" ones, the last two are the "special" ones that allow you to do this reader/writer trick.
For example: The read() trait method is defined like this:
pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<Result<usize>>
When you do stream.read(buf), you're using the impl Read for TcpStream impl. Therefore, you're calling the method with self being of type &mut TcpStream.
When you do let reader = &stream; reader.read(buf), you're using the impl<'_> Read for &'_ TcpStream. Therefore, you're calling the method with self being of type &mut &TcpStream.
I am trying to use the read and write of a tcp stream in different threads. This is what I currently have:
use tokio::prelude::*;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("localhost:8080").await?;
let (mut read, mut write) = stream.split();
tokio::spawn(async move {
loop {
let mut buf = [0u8; 32];
read.read(&mut buf).await.unwrap();
println!("{}", std::str::from_utf8(&buf));
}
});
Ok(())
}
Im going to use another thread for the write. My problem is that I get the error that 'stream' is dropped while still borrowed.
That happens due to the method signature of Tokio::split, as you can see it takes &mut self, so its part cannot be used in a tokio::spawn future argument due to the 'static bound. So, this is exactly what the error says.
What you are searching is tokio::io::split. Playground
use tokio::prelude::*;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("localhost:8080").await?;
let (mut read, mut write) = tokio::io::split(stream);
tokio::spawn(async move {
loop {
let mut buf = [0u8; 32];
read.read(&mut buf).await.unwrap();
println!("{:?}", std::str::from_utf8(&buf));
}
});
Ok(())
}
Reading https://users.rust-lang.org/t/why-i-have-to-use-tokio-tcpstream-split-for-concurrent-read-writes/47755/3
And it suggests to use into_split it is more efficient.
tokio::io::split uses a Mutex which into_split apparently does not have (specific to TcpStream)