I don't know what to do next. It looks like I misunderstand something, or maybe I have not learned some critical topic.
use std::sync::Arc;
use reqwest::{Error, Response}; // 0.11.4
use tokio::sync::mpsc::{self, Receiver, Sender}; // 1.9.0
pub struct Task {
pub id: u32,
pub url: String,
}
pub enum Message {
Failure(Task, Error),
Success(Task, Response),
}
struct State {
client: reqwest::Client,
res_tx: Sender<Message>,
res_rx: Receiver<Message>,
}
pub struct Proxy {
state: Arc<State>,
max_rps: u16,
max_pending: u16,
id: u32,
parent_tx: Sender<String>,
}
async fn send_msg<T>(tx: &Sender<T>, msg: T) {
match tx.send(msg).await {
Err(error) => {
eprintln!("{}", error)
}
_ => (),
};
}
impl Proxy {
// Starts loop for input channel
async fn start_chin(&mut self) -> Sender<Task> {
let (chin_tx, mut chin_rx) = mpsc::channel::<Task>(self.max_pending as usize + 1 as usize);
let state_outer = self.state.clone();
tokio::spawn(async move {
loop {
match chin_rx.recv().await {
Some(task) => {
let res_tx = state_outer.res_tx.clone();
let state = state_outer.clone();
tokio::spawn(async move {
match state.client.get(&task.url).send().await {
Ok(res) => send_msg(&res_tx, Message::Success(task, res)).await,
Err(err) => send_msg(&res_tx, Message::Failure(task, err)).await,
}
});
}
None => (),
}
}
});
chin_tx
}
async fn start_chres(&self) {
let state = self.state.clone();
tokio::spawn(async move {
loop {
match state.res_rx.recv().await { // LINE PRODUCES ERROR
Some(task) => {}
None => (),
}
}
});
}
}
impl Proxy {
pub fn new(
id: u32,
parent_tx: Sender<String>,
proxy_addr: &str,
max_rps: u16,
max_pending: u16,
) -> Result<Self, Error> {
let client = reqwest::Client::builder();
if proxy_addr != "none" {
client = client.proxy(reqwest::Proxy::all(proxy_addr)?)
}
let (res_tx, res_rx) = mpsc::channel::<Message>(max_pending as usize + 1 as usize); // TODO: check size
Ok(Proxy {
id,
state: Arc::new(State {
client: client.build()?,
res_tx,
res_rx,
}),
max_rps,
max_pending,
parent_tx,
})
}
}
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/lib.rs:69:23
|
69 | match state.res_rx.recv().await {
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<State>`
use std::sync::Arc;
struct Something {
size: usize
}
impl Something {
fn increase(&mut self) {
self.size = self.size + 1;
}
}
fn main() {
let something = Something{size: 1};
let arc = Arc::new(something);
arc.increase();
}
gives
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/main.rs:16:5
|
16 | arc.increase();
| ^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<Something>`
error: aborting due to previous error; 1 warning emitted
because it tries to borrow arc as mutable. For it to happen, DerefMut would have to be implemented for Arc but it's not because Arc is not meant to be mutable.
Wraping your object in a Mutex works:
use std::sync::{Arc, Mutex};
struct Something {
size: usize
}
impl Something {
fn increase(&mut self) {
self.size = self.size + 1;
}
}
fn main() {
let something = Something{size: 1};
let arc = Arc::new(Mutex::new(something));
arc.lock().unwrap().increase();
}
Now it can be shared and can be increased.
Lucas Zanella's answer and Shepmaster's comments helped alot to refactor and simplify code. I've desided to pass ownership inside Proxy::new() function instead of using shared reference. The code became more readable, and I've avoided shared reference for mutable tokio::sync::mpsc::Receiver. Perhaps the question turned out to be too unstructured, but I came to a new approach thanks to the community. Refactored code is listed below.
use reqwest::{Client, Error, Response};
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Sender, Receiver};
pub struct Task {
pub id: u32,
pub url: String,
}
pub enum Message{
Failure(Task, Error),
Success(Task, Response),
}
pub struct Proxy{
id: u32,
max_rps: u16,
max_pending: u16,
in_tx: Sender<Task>,
}
async fn send_msg<T>(tx: &Sender<T>, msg: T){
match tx.send(msg).await {
Err(error) => { eprintln!("{}", error) },
_ => (),
};
}
async fn start_loop_in(client: Client, mut in_rx: Receiver<Task>, res_tx: Sender<Message>){
loop {
if let Some(task) = in_rx.recv().await {
let client_clone = client.clone();
let res_tx_clone = res_tx.clone();
tokio::spawn(async move {
println!("SENDING: {}", &task.url); // TODO: DELETE DEBUG
match client_clone.get(&task.url).send().await {
Ok(res) => send_msg(&res_tx_clone, Message::Success(task, res)).await,
Err(err) => send_msg(&res_tx_clone, Message::Failure(task, err)).await,
}
});
}
}
}
async fn start_loop_res(mut res_rx: Receiver<Message>, out_tx: Sender<String>){
loop {
if let Some(message) = res_rx.recv().await {
match message {
Message::Success(task, res) => {
send_msg(
&out_tx,
format!("{:#?}", res.text().await.unwrap()) // TODO: change in release!
).await;
},
Message::Failure(task, err) => {
send_msg(&out_tx, err.to_string()).await;
},
}
}
}
}
impl Proxy{
pub fn new(id: u32, parent_tx: Sender<String>, proxy_addr: &str, max_rps: u16, max_pending: u16) -> Result<Self, Error> {
let mut client = Client::builder();
if proxy_addr != "none" { client = client.proxy(reqwest::Proxy::all(proxy_addr)?) }
let (res_tx, res_rx) = mpsc::channel::<Message>(max_pending as usize + 1 as usize); // TODO: check size
let client = client.build()?;
let (in_tx, in_rx) = mpsc::channel::<Task>(max_pending as usize + 1 as usize);
let res_tx_clone = res_tx.clone();
tokio::spawn(async move { start_loop_in(client, in_rx, res_tx_clone).await });
tokio::spawn(async move { start_loop_res(res_rx, parent_tx).await });
Ok(Proxy{
id,
max_rps,
max_pending,
in_tx,
})
}
pub fn get_in_tx(&self) -> Sender<Task> {
self.in_tx.clone()
}
}
Related
As the title says, we have an application which runs wasm plugins. Each plugin can register their own State in the StateRegistry. Then whenever the plugins are executed, they will modify their respective State.
The code below illustrates this:
use std::{collections::HashMap, any::Any};
type ContractId = String;
type GenericContractState = Box<dyn Any>;
// This will be WASM code
mod foo_contract {
use super::StateRegistry;
pub struct State {
}
pub fn update(states: &mut StateRegistry) {
let state = states.states.get_mut(&"foo_contract".to_string()).unwrap();
let state = state.downcast_mut::<State>().unwrap();
// I'd prefer something like:
// let state = state.lookup::<State>().unwrap()
}
}
pub struct StateRegistry {
pub states: HashMap<ContractId, GenericContractState>,
}
impl StateRegistry {
fn new() -> Self {
Self { states: HashMap::new() }
}
fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
self.states.insert(contract_id, state);
}
/*
fn lookup<'a, S>(&'a mut self, contract_id: &ContractId) -> Option<StateRefWrapper<'a, S>> {
match self.states.get_mut(contract_id) {
Some(state) => {
let ptr = state.downcast_mut::<S>();
match ptr {
Some(ptr) => Some(StateRefWrapper { _mut: state, ptr }),
None => None,
}
}
None => None,
}
}
*/
}
/*
struct StateRefWrapper<'a, S> {
_mut: &'a mut Box<dyn Any>,
ptr: &'a mut S,
}
*/
fn main() {
let mut states = StateRegistry::new();
let foo_state = Box::new(foo_contract::State {});
states.register("foo_contract".to_string(), foo_state);
foo_contract::update(&mut states);
}
The part I want to improve is that currently the plugin developer has to use this code to lookup their State in the registry:
let state = states.states.get_mut(&"foo_contract".to_string()).unwrap();
let state = state.downcast_mut::<State>().unwrap();
I want to create a respective method in StateRegistry that is usable like this:
let state = state.lookup::<State>().unwrap()
My attempt (commented above) was something like this:
impl StateRegistry {
// ...
fn lookup<'a, S>(&'a mut self, contract_id: &ContractId) -> Option<StateRefWrapper<'a, S>> {
match self.states.get_mut(contract_id) {
Some(state) => {
let ptr = state.downcast_mut::<S>();
match ptr {
Some(ptr) => Some(StateRefWrapper { _mut: state, ptr }),
None => None,
}
}
None => None,
}
}
}
struct StateRefWrapper<'a, S> {
_mut: &'a mut Box<dyn Any>,
ptr: &'a mut S,
}
How can I get this lookup() function working?
Thanks
You can't construct your StateRefWrapper in the way you want to, because it would contain two mutable borrows of the same value. You can, however, return just a &mut S which seems sufficient:
fn lookup<'a, S: 'static>(&'a mut self, contract_id: &ContractId) -> Option<&'a mut S> {
self.states
.get_mut(contract_id)
.and_then(|state| state.downcast_mut())
}
And use it like this:
pub fn update(states: &mut StateRegistry) {
let state = states.lookup::<State>(&"foo_contract".to_string()).unwrap();
// state.modify();
}
In the __enter__ method I want to return an object which is accessible in Rust and Python, so that Rust is able to update values in the object and Python can read the updated values.
I would like to have something like this:
#![feature(specialization)]
use std::thread;
use pyo3::prelude::*;
use pyo3::types::{PyType, PyAny, PyDict};
use pyo3::exceptions::ValueError;
use pyo3::PyContextProtocol;
use pyo3::wrap_pyfunction;
#[pyclass]
#[derive(Debug, Clone)]
pub struct Statistics {
pub files: u32,
pub errors: Vec<String>,
}
fn counter(
root_path: &str,
statistics: &mut Statistics,
) {
statistics.files += 1;
statistics.errors.push(String::from("Foo"));
}
#[pyfunction]
pub fn count(
py: Python,
root_path: &str,
) -> PyResult<PyObject> {
let mut statistics = Statistics {
files: 0,
errors: Vec::new(),
};
let rc: std::result::Result<(), std::io::Error> = py.allow_threads(|| {
counter(root_path, &mut statistics);
Ok(())
});
let pyresult = PyDict::new(py);
match rc {
Err(e) => { pyresult.set_item("error", e.to_string()).unwrap();
return Ok(pyresult.into())
},
_ => ()
}
pyresult.set_item("files", statistics.files).unwrap();
pyresult.set_item("errors", statistics.errors).unwrap();
Ok(pyresult.into())
}
#[pyclass]
#[derive(Debug)]
pub struct Count {
root_path: String,
exit_called: bool,
thr: Option<thread::JoinHandle<()>>,
statistics: Statistics,
}
#[pymethods]
impl Count {
#[new]
fn __new__(
obj: &PyRawObject,
root_path: &str,
) {
obj.init(Count {
root_path: String::from(root_path),
exit_called: false,
thr: None,
statistics: Statistics {
files: 0,
errors: Vec::new(),
},
});
}
#[getter]
fn statistics(&self) -> PyResult<Statistics> {
Ok(Statistics { files: self.statistics.files,
errors: self.statistics.errors.to_vec(), })
}
}
#[pyproto]
impl<'p> PyContextProtocol<'p> for Count {
fn __enter__(&mut self) -> PyResult<Py<Count>> {
let gil = GILGuard::acquire();
self.thr = Some(thread::spawn(|| {
counter(self.root_path.as_ref(), &mut self.statistics)
}));
Ok(PyRefMut::new(gil.python(), *self).unwrap().into())
}
fn __exit__(
&mut self,
ty: Option<&'p PyType>,
_value: Option<&'p PyAny>,
_traceback: Option<&'p PyAny>,
) -> PyResult<bool> {
self.thr.unwrap().join();
let gil = GILGuard::acquire();
self.exit_called = true;
if ty == Some(gil.python().get_type::<ValueError>()) {
Ok(true)
} else {
Ok(false)
}
}
}
#[pymodule(count)]
fn init(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Count>()?;
m.add_wrapped(wrap_pyfunction!(count))?;
Ok(())
}
But I'm getting the following error:
error[E0477]: the type `[closure#src/lib.rs:90:39: 92:10 self:&mut &'p mut Count]` does not fulfill the required lifetime
--> src/lib.rs:90:25
|
90 | self.thr = Some(thread::spawn(|| {
| ^^^^^^^^^^^^^
|
= note: type must satisfy the static lifetime
I've found a solution. The use of a guarded reference does the trick:
#![feature(specialization)]
use std::{thread, time};
use std::sync::{Arc, Mutex};
extern crate crossbeam_channel as channel;
use channel::{Sender, Receiver, TryRecvError};
use pyo3::prelude::*;
use pyo3::types::{PyType, PyAny};
use pyo3::exceptions::ValueError;
use pyo3::PyContextProtocol;
#[pyclass]
#[derive(Debug, Clone)]
pub struct Statistics {
pub files: u32,
pub errors: Vec<String>,
}
pub fn counter(
statistics: Arc<Mutex<Statistics>>,
cancel: &Receiver<()>,
) {
for _ in 1..15 {
thread::sleep(time::Duration::from_millis(100));
{
let mut s = statistics.lock().unwrap();
s.files += 1;
}
match cancel.try_recv() {
Ok(_) | Err(TryRecvError::Disconnected) => {
println!("Terminating.");
break;
}
Err(TryRecvError::Empty) => {}
}
}
{
let mut s = statistics.lock().unwrap();
s.errors.push(String::from("Foo"));
}
}
#[pyclass]
#[derive(Debug)]
pub struct Count {
exit_called: bool,
statistics: Arc<Mutex<Statistics>>,
thr: Option<thread::JoinHandle<()>>,
cancel: Option<Sender<()>>,
}
#[pymethods]
impl Count {
#[new]
fn __new__(obj: &PyRawObject) {
obj.init(Count {
exit_called: false,
statistics: Arc::new(Mutex::new(Statistics {
files: 0,
errors: Vec::new(),
})),
thr: None,
cancel: None,
});
}
#[getter]
fn statistics(&self) -> PyResult<u32> {
let s = Arc::clone(&self.statistics).lock().unwrap().files;
Ok(s)
}
}
#[pyproto]
impl<'p> PyContextProtocol<'p> for Count {
fn __enter__(&'p mut self) -> PyResult<()> {
let statistics = self.statistics.clone();
let (sender, receiver) = channel::bounded(1);
self.cancel = Some(sender);
self.thr = Some(thread::spawn(move || {
counter(statistics, &receiver)
}));
Ok(())
}
fn __exit__(
&mut self,
ty: Option<&'p PyType>,
_value: Option<&'p PyAny>,
_traceback: Option<&'p PyAny>,
) -> PyResult<bool> {
let _ = self.cancel.as_ref().unwrap().send(());
self.thr.take().map(thread::JoinHandle::join);
let gil = GILGuard::acquire();
self.exit_called = true;
if ty == Some(gil.python().get_type::<ValueError>()) {
Ok(true)
} else {
Ok(false)
}
}
}
#[pyproto]
impl pyo3::class::PyObjectProtocol for Count {
fn __str__(&self) -> PyResult<String> {
Ok(format!("{:?}", self))
}
}
#[pymodule(count)]
fn init(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Count>()?;
Ok(())
}
Now I can run the following code:
import time
import count
c = count.Count()
with c:
for _ in range(5):
print(c.statistics)
time.sleep(0.1)
As the example shows thread cancelling also works, although a maybe nicer solution is using the crate thread_control.
To learn Rust, I began working on a simple parser. I got it working, but I used a ton of bad practices like using .clone() for saving data in my structs.
Today I started refactoring the code to use references to the object rather than cloning them. I got pretty far before getting stuck with these two errors:
error: cannot borrow 'm_list' as mutable because it is also borrowed as immutable [E0502]
and
error: cannot borrow 'h_list' as mutable because it is also borrowed as immutable [E0502]
After reading about the error, I'm very confused. Some say it's a bug in Rust's borrow checker, but I'm 99% sure that its a bug with my code.
Code where the error manifests:
mod utypes;
use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::error::Error;
use utypes::*;
fn main() {
let args: Vec<_> = env::args().collect();
let file = match File::open(&args[1]) {
Ok(file) => file,
Err(why) => panic!("IO Error on line: {}, cause: {}", line!(), Error::description(&why)),
};
let buffer = BufReader::new(file);
let mut m_list: Vec<Materia> = Vec::new();
let mut h_list: Vec<Hora> = Vec::new();
let mut t_list: Vec<Turno> = Vec::new();
for line in buffer.lines() {
let l = line.unwrap();
let spl_line: Vec<&str> = l.split(':').collect();
if spl_line[0].starts_with('#') { continue; }
match spl_line[0] {
"mat" => { parse_mat(&mut m_list,spl_line) },
"hra" => { parse_hra(&m_list,&mut h_list,spl_line) },
"trn" => { parse_trn(&mut t_list,spl_line) },
"tad" => { exec_tad(&h_list,&mut t_list,spl_line) },
"" => continue,
_ => panic!("Unknown type identifier: {}.", spl_line[0]),
}
}
for turno in t_list.iter() {
println!("\nTurno: {}:\n", turno.nombre);
for dia in turno.dias.iter() {
print!("{:?}: ", dia.enum_id);
for hora in dia.horas.iter() {
print!("\n\t{} ", hora);
}
println!("");
}
}
/*
println!("\nDEBUG INFO:\n");
println!("{:?}", m_list);
println!("{:?}", h_list);
println!("{:?}", t_list);
*/
}
fn get_trn( t_list: &Vec<Turno>, gid: u32 ) -> Option<usize> {
for (i,trn) in t_list.iter().enumerate() {
if trn.id == gid {
return Some(i);
}
}
None
}
fn get_hra ( h_list: &Vec<Hora>, gid: u32 ) -> Option<usize> {
for (i,hra) in h_list.iter().enumerate() {
if hra.id == gid {
return Some(i);
}
}
None
}
fn get_mat ( m_list: &Vec<Materia>, gid: u32 ) -> Option<usize> {
for (i,mat) in m_list.iter().enumerate() {
if mat.id == gid {
return Some(i);
}
}
None
}
fn parse_mat<'a> ( m_list: &'a mut Vec<Materia>, line: Vec<&str> ) {
assert_eq!(4,line.len());
let id: u32 = match line[1].parse::<u32>() {
Ok(id) => id,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
m_list.push(Materia::new(id,line[2].to_string(),line[3].to_string()));
}
fn parse_hra<'a> ( m_list: &'a Vec<Materia>, h_list: &mut Vec<Hora<'a>>, line: Vec<&str> ) {
assert_eq!(5,line.len());
let id: u32 = match line[1].parse::<u32>() {
Ok(id) => id,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let start: u32 = match line[2].parse::<u32>() {
Ok(start) => start,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let durat: u32 = match line[3].parse::<u32>() {
Ok(durat) => durat,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let matid: u32 = match line[4].parse::<u32>() {
Ok(matid) => matid,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let mat_i: usize = match get_mat(m_list,matid) {
Some(x) => x,
None => panic!("Error matid not found in m_list!")
};
h_list.push(Hora::new(id,start,durat,&m_list[mat_i]));
}
fn parse_trn<'a> ( t_list: &mut Vec<Turno<'a>>, line: Vec<&str> ) {
assert_eq!(3,line.len());
let id: u32 = match line[1].parse::<u32>() {
Ok(id) => id,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
t_list.push(Turno::new(id,line[2].to_string()));
}
fn exec_tad<'a> ( h_list: &'a Vec<Hora<'a>>, t_list: &mut Vec<Turno<'a>>, line: Vec<&str> ) {
assert_eq!(4,line.len());
let hid: u32 = match line[2].parse::<u32>(){
Ok(hid) => hid,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let tid: u32 = match line[3].parse::<u32>(){
Ok(tid) => tid,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let hra_i: usize = match get_hra(h_list,hid) {
Some(x) => x,
None => panic!("Error matid not found in m_list!")
};
let trn_i: usize = match get_trn(t_list,tid) {
Some(x) => x,
None => panic!("Error matid not found in m_list!")
};
match line[1] {
"Dom" => t_list[trn_i].addhra(Dias::Dom,&h_list[hra_i]),
"Lun" => t_list[trn_i].addhra(Dias::Lun,&h_list[hra_i]),
"Mar" => t_list[trn_i].addhra(Dias::Mar,&h_list[hra_i]),
"Mie" => t_list[trn_i].addhra(Dias::Mie,&h_list[hra_i]),
"Jue" => t_list[trn_i].addhra(Dias::Jue,&h_list[hra_i]),
"Vie" => t_list[trn_i].addhra(Dias::Vie,&h_list[hra_i]),
"Sab" => t_list[trn_i].addhra(Dias::Sab,&h_list[hra_i]),
_ => panic!("Unknown day error!")
}
}
And utypes.rs:
use std::fmt;
//Dias
#[derive(Debug)]
pub enum Dias {
Dom,
Lun,
Mar,
Mie,
Jue,
Vie,
Sab,
}
//Materia
#[derive(Debug)]
pub struct Materia {
pub id: u32,
pub nombre: String,
pub profesor: String,
}
impl Materia {
pub fn new( i: u32, nom: String, prof: String ) -> Materia {
Materia {
id: i,
nombre: nom,
profesor: prof,
}
}
}
//Hora
#[derive(Debug,Clone)]
pub struct Hora<'a> {
pub id: u32,
pub comienzo: u32,
pub duracion: u32,
pub materia: &'a Materia,
}
impl<'a> Hora<'a> {
pub fn new ( id: u32, com: u32, dur: u32, mat: &'a Materia ) -> Hora<'a> {
Hora {
id: id,
comienzo: com,
duracion: dur,
materia: mat,
}
}
pub fn fin ( &self ) -> u32 {
self.comienzo + self.duracion
}
pub fn fmt_time ( tot: u32 ) -> String {
let min = ( tot / 60 ) % 60;
let hra = tot / 3600;
format!("{:02}:{:02}", hra, min)
}
}
impl<'a> fmt::Display for Hora<'a> {
fn fmt( &self, f: &mut fmt::Formatter ) -> fmt::Result {
write!(f, "[{}-{}, {}]", Hora::fmt_time(self.comienzo), Hora::fmt_time(self.fin()), self.materia.nombre)
}
}
//Dia
#[derive(Debug)]
pub struct Dia<'a> {
pub enum_id: Dias,
pub nombre: String,
pub horas: Vec<&'a Hora<'a>>,
}
impl<'a> Dia<'a> {
pub fn new( ei: Dias, nom: String ) -> Dia<'a> {
Dia {
enum_id: ei,
nombre: nom,
horas: Vec::new(),
}
}
pub fn addhra( &mut self, hra: &'a Hora<'a> ){
self.horas.push(hra);
}
}
//Turno
#[derive(Debug)]
pub struct Turno<'a> {
pub id: u32,
pub nombre: String,
pub dias: [Dia<'a>; 7],
}
impl<'a> Turno<'a> {
pub fn new( i: u32, nom: String ) -> Turno<'a> {
Turno {
id: i,
nombre: nom,
dias: [
Dia::new(Dias::Dom,"Domingo" .to_string()),
Dia::new(Dias::Lun,"Lunes" .to_string()),
Dia::new(Dias::Mar,"Martes" .to_string()),
Dia::new(Dias::Mie,"Miercoles".to_string()),
Dia::new(Dias::Jue,"Jueves" .to_string()),
Dia::new(Dias::Vie,"Viernes" .to_string()),
Dia::new(Dias::Sab,"Sabado" .to_string())
],
}
}
pub fn addhra( &mut self, dia: Dias, hra: &'a Hora<'a> ) {
match dia {
Dias::Dom => self.dias[0].addhra(hra),
Dias::Lun => self.dias[1].addhra(hra),
Dias::Mar => self.dias[2].addhra(hra),
Dias::Mie => self.dias[3].addhra(hra),
Dias::Jue => self.dias[4].addhra(hra),
Dias::Vie => self.dias[5].addhra(hra),
Dias::Sab => self.dias[6].addhra(hra),
}
}
}
I think the mutable reference &mut m_list ends after the function parse_mat() returns so I should be able to, in another iteration of the for loop, call parse_hra() and pass &m_list without problems, right?
Full error:
src/main.rs:36:39: 36:45 error: cannot borrow `m_list` as mutable because it is also borrowed as immutable [E0502]
src/main.rs:36 "mat" => { parse_mat(&mut m_list,spl_line) },
^~~~~~
src/main.rs:37:35: 37:41 note: previous borrow of `m_list` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `m_list` until the borrow ends
src/main.rs:37 "hra" => { parse_hra(&m_list,&mut h_list,spl_line) },
^~~~~~
src/main.rs:71:2: 71:2 note: previous borrow ends here
src/main.rs:11 fn main() {
...
src/main.rs:71 }
^
src/main.rs:37:47: 37:53 error: cannot borrow `h_list` as mutable because it is also borrowed as immutable [E0502]
src/main.rs:37 "hra" => { parse_hra(&m_list,&mut h_list,spl_line) },
^~~~~~
src/main.rs:39:34: 39:40 note: previous borrow of `h_list` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `h_list` until the borrow ends
src/main.rs:39 "tad" => { exec_tad(&h_list,&mut t_list,spl_line) },
^~~~~~
src/main.rs:71:2: 71:2 note: previous borrow ends here
src/main.rs:11 fn main() {
...
src/main.rs:71 }
^
I'm not a native speaker so sorry for any mistakes.
play-rust
#aSpex comment is right.
To solve this problem you can replace the references inside Hora and Dia with the corresponding indices. That is
struct Hora {
materia: usize; //index in m_list
}
struct Dia {
horas: Vec<usize>; //indices in h_list
}
You can also create a struct with fields m_list, h_list and t_list, so they are keeped together.
See this for a comparison with the approach using Rc and RefCell.
Sorry for newbie question. The error here is
<anon>:30:5: 30:17 error: cannot borrow immutable borrowed content as mutable
<anon>:30 routing_node.put(3);
^^^^^^^^^^^^
I have tried many things to work around this but know for sure this is a simple error. Any help much appreciated.
use std::thread;
use std::thread::spawn;
use std::sync::Arc;
struct RoutingNode {
data: u16
}
impl RoutingNode {
pub fn new() -> RoutingNode {
RoutingNode { data: 0 }
}
pub fn run(&self) {
println!("data : {}", self.data);
}
pub fn put(&mut self, increase: u16) {
self.data += increase;
}
}
fn main() {
let mut routing_node = Arc::new(RoutingNode::new());
let mut my_node = routing_node.clone();
{
spawn(move || {my_node.run(); });
}
routing_node.put(3);
}
Arc isn't allowing to mutate of it's inner state, even if container is marked as mutable. You should use one of Cell, RefCell or Mutex. Both Cell and RefCell are non-threadsafe so you should use Mutex (last paragraph in docs).
Example:
use std::thread::spawn;
use std::sync::Mutex;
use std::sync::Arc;
struct RoutingNode {
data: u16,
}
impl RoutingNode {
pub fn new() -> Self { RoutingNode { data: 0, } }
pub fn run(&self) { println!("data : {}" , self.data); }
pub fn put(&mut self, increase: u16) { self.data += increase; }
}
fn main() {
let routing_node = Arc::new(Mutex::new(RoutingNode::new()));
let my_node = routing_node.clone();
let thread = spawn(move || { my_node.lock().unwrap().run(); });
routing_node.lock().unwrap().put(3);
let _ = thread.join();
}
Playpen
Basically, I'm making a program that's listening to a bunch of ports and that handles incoming packets in different ways. I decide to bundle this code into a Trait:
use std::old_io::{TcpStream, TcpListener, Listener, Acceptor, EndOfFile, IoResult};
use std::thread::Thread;
trait Server {
fn new(port: u16) -> Self;
fn hostname(&self) -> &String;
fn initialize(&self) {
let acceptor = TcpListener::bind(self.hostname().as_slice()).listen().unwrap();
Thread::spawn(move|| {
let mut acceptor = acceptor;
for incoming_stream in acceptor.incoming() {
match incoming_stream {
Ok(stream) => {
self.handle_client(stream);
},
Err(ref e) if e.kind == EndOfFile => break,
Err(e) => panic!("Unexpected error: {}", e),
}
}
});
}
fn handle_client(&self, stream: TcpStream) -> ();
}
pub struct InternodeServer {
hostname: String,
}
impl Server for InternodeServer {
fn new(port: u16) -> InternodeServer {
let hostname = format!("127.0.0.1:{}", port);
InternodeServer {
hostname: hostname,
}
}
fn hostname(&self) -> &String {
&self.hostname
}
fn handle_client(&self, stream: TcpStream) {
println!("Received connection");
let mut stream = stream;
let response = b"Hello\r\n";
let _ = stream.write_all(response);
let _ = stream.close_write();
}
}
fn main() {
let test_server = <InternodeServer as Server>::new(9337);
test_server.initialize();
}
However, this code won't work because you can't send Self. This is the error I receive:
test.rs:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `Self` [E0277]
test.rs:11 Thread::spawn(move|| {
^~~~~~~~~~~~~
test.rs:11:9: 11:22 note: `Self` cannot be sent between threads safely
test.rs:11 Thread::spawn(move|| {
^~~~~~~~~~~~~
So I also tried making handle_client a static method to avoid self. To do this, I simply changed handle_client to:
fn handle_client(stream: TcpStream)
And referenced it by doing:
Server::handle_client(stream);
However, I can't reference InternodeServer's static methods from Server's initialize method. When compiling, I get an error like:
test.rs:16:25: 16:46 error: type annotations required: cannot resolve `_ : Server` [E0283]
test.rs:16 Server::handle_client(stream);
^~~~~~~~~~~~~~~~~~~~~
test.rs:16:25: 16:46 note: required by `Server::handle_client`
test.rs:16 Server::handle_client(stream);
Is there any way around this?
Here's a smaller reproduction of the error:
use std::thread::Thread;
trait Server {
fn initialize(&self) {
Thread::spawn(move || self.handle_client());
}
fn handle_client(&self);
}
fn main() {}
The problem is that the argument passed to Thread::spawn must be Send. You are trying to move self into the closure, but your trait doesn't guarantee Send, so the closure can't be Send.
We can attempt to go down that path with trait Server: Send, but then we get "cannot infer an appropriate lifetime" errors because Send also requires 'static (for now). Also, it seems very strange to move yourself into a closure.
Really, I think you want to split up your code. Move handle_client into a separate trait and then ensure that implementations of that trait are Send:
use std::thread::Thread;
trait Server {
fn initialize<D>(&self, driver: D)
where D: Driver + Send
{
Thread::spawn(move || driver.handle_client());
}
}
trait Driver {
fn handle_client(&self);
}
fn main() {}
I don't think that rust will allow you to invoke object methods directly from other thread because "move" closures cannot borrow anything, only move.
So you have to use some kind of inter-thread communication tool, for example, channels:
use std::thread::Thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use std::net::{TcpStream, TcpListener};
use std::io::{ErrorKind, Write};
trait Server {
fn new(port: u16) -> Self;
fn hostname(&self) -> &String;
fn initialize(&mut self, _detached: bool) {
let acceptor = TcpListener::bind(self.hostname().as_slice()).unwrap();
let server_tx = self.make_pipe();
Thread::spawn(move|| {
for incoming_stream in acceptor.incoming() {
match incoming_stream {
Ok(stream) => server_tx.send(Arc::new(Mutex::new(stream))).unwrap(),
Err(ref e) if e.kind() == ErrorKind::NotConnected => break,
Err(e) => panic!("Unexpected error: {}", e),
}
}
});
}
fn handle_client(&self, stream: Arc<Mutex<TcpStream>>);
fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>>;
fn run(&self);
}
pub struct InternodeServer {
hostname: String,
client_rx: Option<Receiver<Arc<Mutex<TcpStream>>>>,
}
impl Server for InternodeServer {
fn new(port: u16) -> InternodeServer {
let hostname = format!("127.0.0.1:{}", port);
InternodeServer {
hostname: hostname,
client_rx: None,
}
}
fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>> {
let (server_tx, client_rx) = channel();
self.client_rx = Some(client_rx);
server_tx
}
fn hostname(&self) -> &String {
&self.hostname
}
fn handle_client(&self, stream_arc: Arc<Mutex<TcpStream>>) {
println!("Received connection");
let mut stream = stream_arc.lock().unwrap();
let response = b"Hello\r\n";
let _ = stream.write_all(response);
let _ = drop(stream);
}
fn run(&self) {
loop {
match self.client_rx.as_ref().unwrap().recv() {
Ok(stream) => self.handle_client(stream),
Err(RecvError) => break,
}
}
}
}
fn main() {
let mut s = <InternodeServer as Server>::new(10101);
s.initialize(false);
s.run();
}