I'm searching a way to pass a variable url_path to this thread, as in this code:
async fn download_dist(all_paths: Vec<String>, mode: &str) {
let mut download_path = "";
let mut root_path = "";
let mut url_path = String::new();
if mode.contains("pool") {
root_path = POOL_ROOT_PATH;
url_path = format!("http://{}/{}", DEBIAN_REPOSITORY, DEBIAN_PATH);
download_path = DEBIAN_POOL_PATH;
} else {
root_path = DIST_ROOT_PATH;
url_path = format!("http://{}/{}/", DEBIAN_REPOSITORY, DEBIAN_DIST_PATH);
download_path = DEBIAN_DIST_PATH;
}
let responses = futures::stream::iter(all_paths.into_iter().map(move |path| {
tokio::spawn(async move {
println!("{}", url_path);
})
}))
.buffer_unordered(10)
.collect::<Vec<_>>();
responses.await;
}
Error is :
cannot move out of url_path, a captured variable in an FnMut closure
move out of url_path occurs here
.map calls the closure you provide many times.
The problem is that your url_path variable can only be moved to a thread once. So in order to move it to many threads (as you do), you have to clone it:
async fn download_dist(all_paths: Vec<String>, mode: &str) {
let mut download_path = "";
let mut root_path = "";
let mut url_path = String::new();
if mode.contains("pool") {
root_path = POOL_ROOT_PATH;
url_path = format!("http://{}/{}", DEBIAN_REPOSITORY, DEBIAN_PATH);
download_path = DEBIAN_POOL_PATH;
} else {
root_path = DIST_ROOT_PATH;
url_path = format!("http://{}/{}/", DEBIAN_REPOSITORY, DEBIAN_DIST_PATH);
download_path = DEBIAN_DIST_PATH;
}
let responses = futures::stream::iter(all_paths.into_iter().map(move |path| {
let url_path = url_path.clone();
tokio::spawn(async move {
println!("{}", url_path);
})
}))
.buffer_unordered(10)
.collect::<Vec<_>>();
responses.await;
}
Side note:
If you set a variable exactly once before using it and the compiler understands that, you can skip the initialization and the mut, like so:
async fn download_dist(all_paths: Vec<String>, mode: &str) {
let download_path;
let root_path;
let url_path;
if mode.contains("pool") {
root_path = POOL_ROOT_PATH;
url_path = format!("http://{}/{}", DEBIAN_REPOSITORY, DEBIAN_PATH);
download_path = DEBIAN_POOL_PATH;
} else {
root_path = DIST_ROOT_PATH;
url_path = format!("http://{}/{}/", DEBIAN_REPOSITORY, DEBIAN_DIST_PATH);
download_path = DEBIAN_DIST_PATH;
}
let responses = futures::stream::iter(all_paths.into_iter().map(move |path| {
let url_path = url_path.clone();
tokio::spawn(async move {
println!("{}", url_path);
})
}))
.buffer_unordered(10)
.collect::<Vec<_>>();
responses.await;
}
You're using mut but you don't need to. Consider:
let (download_path, url_path, root_path) = if mode.contains("pool")
{
(
POOL_ROOT_PATH,
format!("http://{}/{}",DEBIAN_REPOSITORY,DEBIAN_PATH),
DEBIAN_POOL_PATH
)
}
else
{
(
POOL_ROOT_PATH,
format!("http://{}/{}/",DEBIAN_REPOSITORY,DEBIAN_DIST_PATH),
DEBIAN_POOL_PATH
)
};
Collapsing it like this exposes that you're not really changing either download_path or url_path anyway.
Tip: In Rust when you have let mut x = "" and then later assign to it, that's a sign you might want let x = if (...) { } instead.
If you're still stuck on the references, you can go down the Arc path:
let url_path = Arc::new(url_path);
let responses = futures::stream::iter(all_paths.into_iter().map(|path| {
let url_path = url_path.clone();
tokio::spawn(async move {
println!("{}", url_path);
})
}))
This way each spawned task gets their "own" copy of the url_path, but to avoid needless copies, they're all Arc references to the same thing.
Related
I am using the stream function of redis in actix-web 4, I want to create the consumer in the main function, this is my current code
[dependencies]
actix-web = "4"
tokio = { version = "1", features = ["full"] }
redis = { version = "0.21", features = [
# "cluster",
"tokio-comp",
"tokio-native-tls-comp",
] }
#[actix_web::main]
async fn main() -> std::io::Result<()> {
utils::init::init_envfile();
env_logger::init_from_env(env_logger::Env::new());
let redis_pool = utils::init::init_redis_pool();
let mysql_pool = utils::init::init_mysql_pool();
let redist_stream_consumer = web::block(redis_stream_group);
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(redis_pool.clone()))
.app_data(web::Data::new(mysql_pool.clone()))
.service(web::scope("/api").configure(controller::api::config))
})
.bind(("0.0.0.0", 7777))?
.run()
.await?;
redist_stream_consumer.await.unwrap();
Ok(())
}
fn redis_stream_group() {
let client = redis::Client::open("redis://127.0.0.1/").expect("client");
let mut con = client.get_connection().expect("con");
let key = "s.order";
let group_name = "g1";
let consumer_name = "c1";
let _: Result<(), _> = con.xgroup_create_mkstream(key, group_name, "$");
let opts = StreamReadOptions::default()
.group(group_name, consumer_name)
.count(1)
.block(0);
loop {
let read_reply: StreamReadReply =
con.xread_options(&[key], &[">"], &opts).expect("read err");
for StreamKey { key, ids } in read_reply.keys {
for StreamId { id, map } in &ids {
log::info!("id:{} | key:{} | data:{:?}", id, key, map);
}
let id_strs: Vec<&String> = ids.iter().map(|StreamId { id, map: _ }| id).collect();
let _: usize = con.xack(key, group_name, &id_strs).expect("ack err");
}
}
}
When I use cargo r, I can run the program normally and get the sent messages, but when I execute ctrl+c, I can't exit the program.
Also I'm not sure if using web::block in the main function is correct and if there is a better way to run child threads
UPDATE: Tried using tokio::spawn, seems to work
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let redis_pool = utils::init::init_redis_pool();
let mysql_pool = utils::init::init_mysql_pool();
for consumer_index in 1..=2 {
let c_redis_pool = redis_pool.clone();
tokio::spawn(async move {
let mut con = c_redis_pool.get().await.unwrap();
let key = "s.order";
let group_name = "g1";
let consumer_name = &format!("c{consumer_index}");
let _: Result<(), _> = con.xgroup_create_mkstream(key, group_name, "$").await;
let opts = StreamReadOptions::default()
.group(group_name, consumer_name)
.count(1)
.block(5000);
loop {
let read_reply: StreamReadReply = con
.xread_options(&[key], &[">"], &opts)
.await
.expect("err");
for StreamKey { key, ids } in read_reply.keys {
for StreamId { id, map } in &ids {
log::info!(
"consumer: {} | id:{} | key:{} | data:{:?}",
consumer_name,
id,
key,
map
);
}
let id_strs: Vec<&String> =
ids.iter().map(|StreamId { id, map: _ }| id).collect();
let _: usize = con
.xack(key, group_name, &id_strs)
.await
.expect("ack err");
}
}
});
}
let serve = HttpServer::new(move || {
...
}
This can be done with the standard library by useing std::thread and then creating the thread and whatever you want the other thread to do in a closure
fn main() {
thread::spawn(|| {
println!("doing things in the thread!");
});
println!("doing things outside the thread.... how boring");
}
if you want to pass data between them, you can use std::sync::mpsc to transfer data between the threads safely and quickly, using let (item_one,item_two) = mpsc::channel();, like so
fn main() {
let (sender,receiver) = mpsc::channel();
thread::spawn(move || {
let message = String::from("This message is from the thread");
sender.send(message).unwrap();
});
let letter = receiver.recv().unwrap();
note that the main thread proceeds as normal until it comes to the .recv(), at which it either receives the data from the thread, or waits until the other thread is done.
in your example you could do something like
use std::sync::mpsc;
use std::thread;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
utils::init::init_envfile();
env_logger::init_from_env(env_logger::Env::new());
let port = get_env!("ACTIX_PORT", u16);
log::info!(
"starting HTTP server at http://{}:{}",
local_ipaddress::get().unwrap_or("localhost".to_string()),
port
);
let redis_pool = utils::init::init_redis_pool();
let mysql_pool = utils::init::init_mysql_pool();
let (consumer_sender,consumer_listener) = mpsc::channel();
thread::spawn(move || {
consumer_sender.send(redis_stream_group()).expect("You probably want to handle this case, but I'm too lazy");
});
let serve = HttpServer::new(move || {
let app_state = utils::init::AppState {
app_name: get_env!("APP_NAME", String),
pwd_secret: get_env!("PWD_SECRET", String),
jwt_secret: get_env!("JWT_SECRET", String),
jwt_exp: get_env!("JWT_EXP", i64),
};
App::new()
.app_data(web::Data::new(awc::Client::default()))
.app_data(web::Data::new(app_state))
.app_data(web::Data::new(redis_pool.clone()))
.app_data(web::Data::new(mysql_pool.clone()))
.wrap(actix_cors::Cors::default().allowed_origin_fn(|_, _| true))
.service(web::scope("/chat").configure(controller::chat::config))
.service(web::scope("/ws").configure(controller::ws::config))
.service(web::scope("/api").configure(controller::api::config))
});
if cfg!(debug_assertions) {
serve.bind(("0.0.0.0", port))?
} else {
let p = format!("/tmp/{}.socket", get_env!("APP_NAME", String));
let r = serve.bind_uds(&p)?;
let mut perms = std::fs::metadata(&p)?.permissions();
perms.set_readonly(false);
std::fs::set_permissions(&p, perms)?;
r
}
.run()
.await?;
let consumer = consumer_listener.recv().unwrap();
//then put things to do with the consumer here, or not idc
Ok(())
}
fn redis_stream_group() {
let client = redis::Client::open("redis://127.0.0.1/").expect("client");
let mut con = client.get_connection().expect("con");
let key = "s.order";
let group_name = "g1";
let consumer_name = "c1";
let _: Result<(), _> = con.xgroup_create_mkstream(key, group_name, "$");
let opts = StreamReadOptions::default()
.group(group_name, consumer_name)
.count(1)
.block(0);
loop {
let read_reply: StreamReadReply =
con.xread_options(&[key], &[">"], &opts).expect("read err");
for StreamKey { key, ids } in read_reply.keys {
for StreamId { id, map } in &ids {
log::info!("id:{} | key:{} | data:{:?}", id, key, map);
}
let id_strs: Vec<&String> = ids.iter().map(|StreamId { id, map: _ }| id).collect();
let _: usize = con.xack(key, group_name, &id_strs).expect("ack err");
}
}
}
for downloading with reqwest and tokio and progress I am using the code below
pub async fn download_file(client: &Client, url: &str, path: &str) -> Result<(), String> {
// Reqwest setup
let res = client
.get(url)
.send()
.await
.or(Err(format!("Failed to GET from '{}'", &url)))?;
let total_size = res
.content_length()
.ok_or(format!("Failed to get content length from '{}'", &url))?;
// Indicatif setup
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
.progress_chars("#>-"));
pb.set_message(format!("Downloading {}", url));
// download chunks
let mut file = File::create(path).or(Err(format!("Failed to create file '{}'", path)))?;
let mut downloaded: u64 = 0;
let mut stream = res.bytes_stream();
while let Some(item) = stream.next().await {
let chunk = item.or(Err(format!("Error while downloading file")))?;
file.write(&chunk)
.or(Err(format!("Error while writing to file")))?;
let new = min(downloaded + (chunk.len() as u64), total_size);
downloaded = new;
pb.set_position(new);
}
pb.finish_with_message(format!("Downloaded {} to {}", url, path));
return Ok(());
}
from the while loop I can set progress and see progressbar like examples here https://github.com/mitsuhiko/indicatif
now I am trying to find make progressbar from upload, but could not find the way to monitor reqwest client, code below is my upload function
pub async fn upload_file(client: &Client, url: &str, path: &str) -> Result<(), String> {
let f = File::open(path).expect("Unable to open file");
let total_size = f.metadata().unwrap().len();
// Indicatif setup
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
.progress_chars("#>-"));
pb.set_message(format!("Posting {}", url));
let file = tokio::fs::File::open(path).await.unwrap();
let stream = FramedRead::new(file, BytesCodec::new());
let res=client
.post(url)
.body(Body::wrap_stream(stream))
.send()
.await;
pb.finish_with_message(format!("Uploaded {} to {}", url, path));
return Ok(());
}
upload works but no progressbar with percent or any indicator. there should have been status monitor, like below
.post(url)
.body(Body::wrap_stream(stream))
.send()
.monitorStatus(|stat|{
pb.set_position(stat);
}).....
you can see working code here https://github.com/ozkanpakdil/rust-examples/blob/5f4965f2b086d07c8294352182639dc75232bb30/download_upload/src/download_file.rs#L43 just uncomment those tests and run cargo test
My question is, how to monitor reqwest client for upload and making a progressbar from it ?
You can create an async_stream and yield chunks of the input to upload:
let file = tokio::fs::File::open(&input).await.unwrap();
let total_size = file.metadata().await.unwrap().len();
let input_ = input.to_string();
let output_ = output.to_string();
let mut reader_stream = ReaderStream::new(file);
let mut uploaded = HTTPSHandler::get_already_uploaded(output).await;
bar.set_length(total_size);
let async_stream = async_stream::stream! {
while let Some(chunk) = reader_stream.next().await {
if let Ok(chunk) = &chunk {
let new = min(uploaded + (chunk.len() as u64), total_size);
uploaded = new;
bar.set_position(new);
if(uploaded >= total_size){
bar.finish_upload(&input_, &output_);
}
}
yield chunk;
}
};
Then, just wrap the stream when building the Body:
let _ = reqwest::Client::new()
.put(output)
.header("content-type", "application/octet-stream")
.header("Range", "bytes=".to_owned() + &uploaded.to_string() + "-")
.header(
reqwest::header::USER_AGENT,
reqwest::header::HeaderValue::from_static(CLIENT_ID),
)
.body(reqwest::Body::wrap_stream(async_stream))
.send()
.await
.unwrap();
Btw, have a look at the implementation of aim, I've faced similar problems there!
I have a rust program that creates temporary email addresses using the mail.tm API, and I want to use threads to create emails simultaneously, to increase the speed. However, what I have tried, only results in printing "Getting email.." x amount of times, and exiting. I am unsure what to do about this. Any help or suggestions are appreciated.
use json;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use reqwest;
use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE};
use std::{collections::HashMap, io, iter, vec::Vec};
use std::thread;
fn gen_address() -> Vec<String> {
let mut rng = thread_rng();
let address: String = iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.map(char::from)
.take(10)
.collect();
let password: String = iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
.map(char::from)
.take(5)
.collect();
let body = reqwest::blocking::get("https://api.mail.tm/domains")
.unwrap()
.text()
.unwrap();
let domains = json::parse(&body).expect("Failed to parse domain json.");
let domain = domains["hydra:member"][0]["domain"].to_string();
let email = format!("{}#{}", &address, &domain);
vec![email, password]
}
fn gen_email() -> Vec<String> {
let client = reqwest::blocking::Client::new();
let address_info = gen_address();
let address = &address_info[0];
let password = &address_info[1];
let mut data = HashMap::new();
data.insert("address", &address);
data.insert("password", &password);
let mut headers = HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/ld+json"));
headers.insert(
CONTENT_TYPE,
HeaderValue::from_static("application/ld+json"),
);
let res = client
.post("https://api.mail.tm/accounts")
.headers(headers)
.json(&data)
.send()
.unwrap();
vec![
res.status().to_string(),
address.to_string(),
password.to_string(),
]
}
fn main() {
fn get_amount() -> i32 {
let mut amount = String::new();
loop {
println!("How many emails do you want?");
io::stdin()
.read_line(&mut amount)
.expect("Failed to read line.");
let _amount: i32 = match amount.trim().parse() {
Ok(num) => return num,
Err(_) => {
println!("Please enter a number.");
continue;
}
};
}
}
let amount = get_amount();
let handle = thread::spawn(move || {
for _gen in 0..amount {
let handle = thread::spawn(|| {
println!("Getting email...");
let maildata = gen_email();
println!(
"Status: {}, Address: {}, Password: {}",
maildata[0], maildata[1], maildata[2]);
});
}
});
handle.join().unwrap();
}
Rust Playground example
I see a number of sub-threads being spawned from an outer thread. I think you might want to keep those handles and join them. Unless you join those sub threads the outer thread will exit early. I set up a Rust Playground to demonstrate ^^.
In the playground example, first run the code as-is and note the output of the code - the function it's running is not_joining_subthreads(). Note that it terminates rather abruptly. Then modify the code to call joining_subthreads(). You should then see the subthreads printing out their stdout messages.
let handle = thread::spawn(move || {
let mut handles = vec![];
for _gen in 0..amount {
let handle = thread::spawn(|| {
println!("Getting email...");
let maildata = gen_email();
println!(
"Status: {}, Address: {}, Password: {}",
maildata[0], maildata[1], maildata[2]);
});
handles.push(handle);
}
handles.into_iter().for_each(|h| h.join().unwrap());
});
handle.join().unwrap();
I get this error while compiling my code: please help me.
use of moved value: `path`
value used here after moverustc(E0382)
main.rs(16, 9): move occurs because `path` has type `std::result::Result`, which does not implement the `Copy` trait
main.rs(18, 32): `path` moved due to this method call
main.rs(19, 29): value used here after move
fn main() -> std::io::Result<()> {
let paths = fs::read_dir("./").unwrap();
let mut text = String::new();
let mut idx = 0;
for path in paths {
// let path_str = path.unwrap().path().display().to_string();
let path_str = if path.unwrap().path().is_dir() {
path.unwrap().path().display().to_string()
}
else {
let mut path = path.unwrap().path().display().to_string();
path.push_str("[file]");
path
};
let path_trimed = path_str.trim_start_matches("./");
idx += 1;
println!("{} -> file/folder: {}", idx + 1, path_trimed);
text.push_str(&path_trimed);
text.push_str("\n");
}
// println!("{}", text);
// writing the string to file
let mut file = fs::File::create("file_list.txt")?;
file.write_all(&text.as_bytes())?;
Ok(())
}
I think the problem is that you're unwrapping path many times, each unwrapping borrows the variable path, so you rust will complain when you try to unwrap a second time.
I suggest you try to unwrap it just once:
use std::fs;
use std::io::Write;
fn main() -> std::io::Result<()> {
let paths = fs::read_dir("./").unwrap();
let mut text = String::new();
let mut idx = 0;
for path in paths {
// let path_str = path.unwrap().path().display().to_string();
let path = path.unwrap().path();
let path_str = if path.is_dir() {
path.display().to_string()
} else {
let mut path = path.display().to_string();
path.push_str("[file]");
path
};
let path_trimed = path_str.trim_start_matches("./");
idx += 1;
println!("{} -> file/folder: {}", idx + 1, path_trimed);
text.push_str(&path_trimed);
text.push_str("\n");
}
// println!("{}", text);
// writing the string to file
let mut file = fs::File::create("file_list.txt")?;
file.write_all(&text.as_bytes())?;
Ok(())
}
I'm building a multiplex in rust. It's one of my first applications and a great learning experience!
However, I'm facing a problem and I cannot find out how to solve it in rust:
Whenever a new channel is added to the multiplex, I have to listen for data on this channel.
The new channel is allocated on the stack when it is requested by the open() function.
However, this channel must not be allocated on the stack but on the heap somehow, because it should stay alive and should not be freed in the next iteration of my receiving loop.
Right now my code looks like this (v0.10-pre):
extern crate collections;
extern crate sync;
use std::comm::{Chan, Port, Select};
use std::mem::size_of_val;
use std::io::ChanWriter;
use std::io::{ChanWriter, PortReader};
use collections::hashmap::HashMap;
use sync::{rendezvous, SyncPort, SyncChan};
use std::task::try;
use std::rc::Rc;
struct MultiplexStream {
internal_port: Port<(u32, Option<(Port<~[u8]>, Chan<~[u8]>)>)>,
internal_chan: Chan<u32>
}
impl MultiplexStream {
fn new(downstream: (Port<~[u8]>, Chan<~[u8]>)) -> ~MultiplexStream {
let (downstream_port, downstream_chan) = downstream;
let (p1, c1): (Port<u32>, Chan<u32>) = Chan::new();
let (p2, c2):
(Port<(u32, Option<(Port<~[u8]>, Chan<~[u8]>)>)>,
Chan<(u32, Option<(Port<~[u8]>, Chan<~[u8]>)>)>) = Chan::new();
let mux = ~MultiplexStream {
internal_port: p2,
internal_chan: c1
};
spawn(proc() {
let mut pool = Select::new();
let mut by_port_num = HashMap::new();
let mut by_handle_id = HashMap::new();
let mut handle_id2port_num = HashMap::new();
let mut internal_handle = pool.handle(&p1);
let mut downstream_handle = pool.handle(&downstream_port);
unsafe {
internal_handle.add();
downstream_handle.add();
}
loop {
let handle_id = pool.wait();
if handle_id == internal_handle.id() {
// setup new port
let port_num: u32 = p1.recv();
if by_port_num.contains_key(&port_num) {
c2.send((port_num, None))
}
else {
let (p1_,c1_): (Port<~[u8]>, Chan<~[u8]>) = Chan::new();
let (p2_,c2_): (Port<~[u8]>, Chan<~[u8]>) = Chan::new();
/********************************/
let mut h = pool.handle(&p1_); // <--
/********************************/
/* the error is HERE ^^^ */
/********************************/
unsafe { h.add() };
by_port_num.insert(port_num, c2_);
handle_id2port_num.insert(h.id(), port_num);
by_handle_id.insert(h.id(), h);
c2.send((port_num, Some((p2_,c1_))));
}
}
else if handle_id == downstream_handle.id() {
// demultiplex
let res = try(proc() {
let mut reader = PortReader::new(downstream_port);
let port_num = reader.read_le_u32().unwrap();
let data = reader.read_to_end().unwrap();
return (port_num, data);
});
if res.is_ok() {
let (port_num, data) = res.unwrap();
by_port_num.get(&port_num).send(data);
}
else {
// TODO: handle error
}
}
else {
// multiplex
let h = by_handle_id.get_mut(&handle_id);
let port_num = handle_id2port_num.get(&handle_id);
let port_num = *port_num;
let data = h.recv();
try(proc() {
let mut writer = ChanWriter::new(downstream_chan);
writer.write_le_u32(port_num);
writer.write(data);
writer.flush();
});
// todo check if chan was closed
}
}
});
return mux;
}
fn open(self, port_num: u32) -> Result<(Port<~[u8]>, Chan<~[u8]>), ()> {
let res = try(proc() {
self.internal_chan.send(port_num);
let (n, res) = self.internal_port.recv();
assert!(n == port_num);
return res;
});
if res.is_err() {
return Err(());
}
let res = res.unwrap();
if res.is_none() {
return Err(());
}
let (p,c) = res.unwrap();
return Ok((p,c));
}
}
And the compiler raises this error:
multiplex_stream.rs:81:31: 81:35 error: `p1_` does not live long enough
multiplex_stream.rs:81 let mut h = pool.handle(&p1_);
^~~~
multiplex_stream.rs:48:16: 122:4 note: reference must be valid for the block at 48:15...
multiplex_stream.rs:48 spawn(proc() {
multiplex_stream.rs:49 let mut pool = Select::new();
multiplex_stream.rs:50 let mut by_port_num = HashMap::new();
multiplex_stream.rs:51 let mut by_handle_id = HashMap::new();
multiplex_stream.rs:52 let mut handle_id2port_num = HashMap::new();
multiplex_stream.rs:53
...
multiplex_stream.rs:77:11: 87:7 note: ...but borrowed value is only valid for the block at 77:10
multiplex_stream.rs:77 else {
multiplex_stream.rs:78 let (p1_,c1_): (Port<~[u8]>, Chan<~[u8]>) = Chan::new();
multiplex_stream.rs:79 let (p2_,c2_): (Port<~[u8]>, Chan<~[u8]>) = Chan::new();
multiplex_stream.rs:80
multiplex_stream.rs:81 let mut h = pool.handle(&p1_);
multiplex_stream.rs:82 unsafe { h.add() };
Does anyone have an idea how to solve this issue?
The problem is that the new channel that you create does not live long enough—its scope is that of the else block only. You need to ensure that it will live longer—its scope must be at least that of pool.
I haven't made the effort to understand precisely what your code is doing, but what I would expect to be the simplest way to ensure the lifetime of the ports is long enough is to place it into a vector at the same scope as pool, e.g. let ports = ~[];, inserting it with ports.push(p1_); and then taking the reference as &ports[ports.len() - 1]. Sorry, that won't cut it—you can't add new items to a vector while references to its elements are active. You'll need to restructure things somewhat if you want that appraoch to work.