How to use this argument in this async lambda? - rust

I'm trying the below code but I cannot understand how to fix the error, can you help me?
RUST PLAYGROUND DEMO: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=977a9e7a5bb503e900818b8ff67daf7e
Code:
use std::{future::Future, pin::Pin, sync::Arc};
#[async_trait::async_trait]
pub trait PlayerTrait: Send + Sync {
async fn player_update<'a>(
&'a self,
input: PlayerInput,
lambda: &(dyn Fn(
PlayerLambdaArgs,
) -> Pin<Box<dyn Future<Output = Result<Player, String>> + Send + 'a>>
+ Sync),
) -> Result<Player, String>;
}
#[derive(Debug)]
pub struct Player {
pub name: String,
}
impl Player {
pub fn new(name: &str, team_id: i64) -> Result<Player, String> {
if team_id > 100 {
return Err("Sorry, this team is closed".to_string());
}
Ok(Player {
name: name.to_string(),
})
}
}
pub struct PlayerInput {
pub name: String,
}
pub struct PlayerLambdaArgs {
pub random_team_id: i64,
}
pub struct DBRepo {
pub db: String,
}
impl DBRepo {
pub fn new(db: String) -> Self {
Self { db }
}
}
#[async_trait::async_trait]
impl PlayerTrait for DBRepo {
async fn player_update<'a>(
&'a self,
_input: PlayerInput,
lambda: &(dyn Fn(
PlayerLambdaArgs,
) -> Pin<Box<dyn Future<Output = Result<Player, String>> + Send + 'a>>
+ Sync),
) -> Result<Player, String> {
// get from DB here
let random_team_id = 123;
let lambda_args = PlayerLambdaArgs { random_team_id };
let res = lambda(lambda_args).await?;
// do something with res here
Ok(Player { name: res.name })
}
}
#[tokio::main]
async fn main() {
let db_repo = Arc::new(DBRepo::new(String::from("hello")));
let input = PlayerInput {
name: "Bob".to_string(),
};
let player = db_repo
.player_update(input, &|args| {
Box::pin(async {
let player = Player::new(&input.name, args.random_team_id)?;
Ok(player)
})
})
.await;
dbg!(player);
}
Error:
Compiling playground v0.0.1 (/playground)
error[E0373]: async block may outlive the current function, but it borrows `args.random_team_id`, which is owned by the current function
--> src/main.rs:82:28
|
82 | Box::pin(async {
| ____________________________^
83 | | let player = Player::new(&input.name, args.random_team_id)?;
| | ------------------- `args.random_team_id` is borrowed here
84 | |
85 | | Ok(player)
86 | | })
| |_____________^ may outlive borrowed value `args.random_team_id`
|
note: async block is returned here
--> src/main.rs:82:13
|
82 | / Box::pin(async {
83 | | let player = Player::new(&input.name, args.random_team_id)?;
84 | |
85 | | Ok(player)
86 | | })
| |______________^
help: to force the async block to take ownership of `args.random_team_id` (and any other referenced variables), use the `move` keyword
|
82 | Box::pin(async move {
| ++++
For more information about this error, try `rustc --explain E0373`.
error: could not compile `playground` due to previous error

So, pretty much always, async closures must also be move. This also means that any closure they're inside must be move as well.
So the first thing to do is add move:
#[tokio::main]
async fn main() {
let db_repo = Arc::new(DBRepo::new(String::from("hello")));
let input = PlayerInput {
name: "Bob".to_string(),
};
let player = db_repo
.player_update(input, &(move |args| {
Box::pin(async move {
let player = Player::new(&input.name, args.random_team_id)?;
Ok(player)
})
}))
.await;
dbg!(player);
}
We're still getting some errors here around input.name. This is because we're trying to move input as an argument to player_update and as a capture of the closure and the async block.
So let's add a clone for the PlayerInput construction:
#[tokio::main]
async fn main() {
let db_repo = Arc::new(DBRepo::new(String::from("hello")));
let name = "Bob".to_string();
let input = PlayerInput {
name: name.clone(),
};
let player = db_repo
.player_update(input, &(move |args| {
Box::pin(async move {
let player = Player::new(&name, args.random_team_id)?;
Ok(player)
})
}))
.await;
dbg!(player);
}
This leads to one final move error. We can fix this by taking a reference to name outside the closure, instead of inside it:
#[tokio::main]
async fn main() {
let db_repo = Arc::new(DBRepo::new(String::from("hello")));
let name = "Bob".to_string();
let name = &name;
let input = PlayerInput {
name: name.clone(),
};
let player = db_repo
.player_update(input, &(move |args| {
Box::pin(async move {
let player = Player::new(name, args.random_team_id)?;
Ok(player)
})
}))
.await;
dbg!(player);
}
playground

Related

future created by async block is not `Send`

I do a server update in rust. it create patches between 2 binaries files, and serves static files
I try to do
let mut update_state;
if let Some(state) = update_stream.next().await {
if let Ok(state) = state {
update_state = state
} else if let Err(err) = state {
reply = BuildOutput { error: "Update failed: ".to_string() + &err.to_string() }
}
} else {
reply = BuildOutput { error: "Unreacheable".to_string() }
}
let state = update_state.borrow();
let progress = state.histogram.progress();
let res = update_stream.try_for_each(|_state| future::ready(Ok(()))).await;
but get
note: future is not `Send` as this value is used across an await
--> server\grpc\src\rpc.rs:260:50
|
259 | let mut update_state;
| ---------------- has type `SharedUpdateProgress` which is not `Send`
260 | if let Some(state) = update_stream.next().await {
| ^^^^^^ await occurs here, with `mut update_state` maybe used later
...
305 | }
| - `mut update_state` is later dropped here
= note: required for the cast from `impl futures::Future<Output = Result<tonic::Response<BuildOutput>, Status>>` to the object type `dyn futures::Future<Output = Result<tonic::Response<BuildOutput>, Status>> + std::marker::Send
SharedUpdateProgress:
#[derive(Clone)]
pub struct SharedUpdateProgress {
state: Rc<RefCell<UpdateProgress>>,
}
impl SharedUpdateProgress {
pub fn new(target_revision: CleanName) -> Self {
Self { state: Rc::new(RefCell::new(UpdateProgress::new(target_revision))) }
}
pub fn borrow(&self) -> Ref<'_, UpdateProgress> {
self.state.borrow()
}
pub(crate) fn borrow_mut(&self) -> RefMut<'_, UpdateProgress> {
self.state.borrow_mut()
}
}
I don't know why and don't know how to fix it
I assume a minimal reproducible example of your problem is as follows:
use std::{cell::RefCell, rc::Rc};
use tokio::time::{sleep, Duration};
#[derive(Clone)]
pub struct SharedString {
state: Rc<RefCell<String>>,
}
impl SharedString {
pub fn new(initial: &str) -> Self {
Self {
state: Rc::new(RefCell::new(initial.into())),
}
}
}
async fn run() {
let shared_string = SharedString::new("Hello,");
sleep(Duration::from_millis(1)).await;
*shared_string.state.borrow_mut() += " world!";
sleep(Duration::from_millis(1)).await;
println!("{:?}", shared_string.state.borrow());
}
#[tokio::main]
async fn main() {
tokio::task::spawn(run()).await.unwrap();
}
error: future cannot be sent between threads safely
--> src/main.rs:27:24
|
27 | tokio::task::spawn(run()).await.unwrap();
| ^^^^^ future returned by `run` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<RefCell<String>>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:19:36
|
18 | let shared_string = SharedString::new("Hello,");
| ------------- has type `SharedString` which is not `Send`
19 | sleep(Duration::from_millis(1)).await;
| ^^^^^^ await occurs here, with `shared_string` maybe used later
...
23 | }
| - `shared_string` is later dropped here
note: required by a bound in `tokio::spawn`
--> /home/martin/.cargo/git/checkouts/tokio-dd4afa005f1f4b79/686577b/tokio/src/task/spawn.rs:163:21
|
163 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
The tokio Runtime is usually multi-threaded, meaning that at any .await point your task could get moved from one thread to another. That's why everything that is held across an .await point must be Send. Which Rc<RefCell<>> is explicitely not, because it's a single-threaded reference counter.
Solution: Replace Rc<RefCell<>> with Arc<Mutex<>>, which is the thread-safe equivalent.
use std::sync::{Arc, Mutex};
use tokio::time::{sleep, Duration};
#[derive(Clone)]
pub struct SharedString {
state: Arc<Mutex<String>>,
}
impl SharedString {
pub fn new(initial: &str) -> Self {
Self {
state: Arc::new(Mutex::new(initial.into())),
}
}
}
async fn run() {
let shared_string = SharedString::new("Hello,");
sleep(Duration::from_millis(1)).await;
*shared_string.state.lock().unwrap() += " world!";
sleep(Duration::from_millis(1)).await;
println!("{:?}", shared_string.state.lock().unwrap());
}
#[tokio::main]
async fn main() {
tokio::task::spawn(run()).await.unwrap();
}
"Hello, world!"

Why can't I use this input?

I simplified a lot the code of my real project to narrowing down one issue I cannot understand how to fix.
Rust Explorer Playground here.
The code:
use std::{future::Future, pin::Pin, sync::Arc};
#[derive(Default)]
pub struct PlayerInput {
pub id: String,
pub name: String,
pub location: String,
// pub team: Box<Team>,
// others...
}
#[derive(Debug, sqlx::FromRow)]
pub struct DomainPlayer {
pub id: String,
pub name: String,
pub location: String,
pub shirt_number: i64,
// pub team: Box<Team>,
// others...
}
impl DomainPlayer {
fn new(id: &str, name: &str, location: &str, shirt_number: i64) -> Self {
Self {
id: id.to_string(),
name: name.to_string(),
location: location.to_string(),
shirt_number,
}
}
}
pub struct PlayerCreateLambdaArgs<'a> {
// other needed fields here
pub shirt_next_value: Box<
dyn FnOnce(&'a str) -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send + 'a>>
+ Send
+ Sync
+ 'a,
>,
}
async fn player_create<'a>(
pool: Arc<sqlx::PgPool>,
_team_id: &'a str,
_input: &'a PlayerInput,
lambda: &(dyn for<'b> Fn(
PlayerCreateLambdaArgs<'b>,
) -> Pin<Box<dyn Future<Output = Result<DomainPlayer, String>> + Send + 'b>>
+ Sync
+ '_),
) -> Result<DomainPlayer, String> {
let mut tx = pool.begin().await.unwrap();
let domain_player = lambda(PlayerCreateLambdaArgs {
shirt_next_value: Box::new(|model: &str| {
Box::pin(shirt_get_next_and_increase(&mut tx, model))
}),
})
.await?;
let res =
sqlx::query_as::<_, DomainPlayer>("INSERT INTO player (...) VALUES (...) RETURNING *")
.bind(domain_player.id)
.bind(domain_player.shirt_number)
.fetch_one(&mut *tx)
.await
.unwrap();
Ok(res)
}
async fn shirt_get_next_and_increase(
tx: &mut sqlx::PgConnection,
model: &str,
) -> Result<i64, String> {
// Here I'm awaiting an async call for DB operations using the same DB transacion of the caller (_tx)...
dbg!(tx);
// use model here...
dbg!(model);
let res = 123;
Ok(res)
}
pub async fn handle(pool: Arc<sqlx::PgPool>, input: &PlayerInput) -> Result<DomainPlayer, String> {
let res = player_create(pool, "team", input, &|args| {
let input = input;
Box::pin(async move {
let shirt_number = (args.shirt_next_value)("player").await?;
let o = DomainPlayer::new(&input.id, &input.name, &input.location, shirt_number);
Ok(o)
})
})
.await?;
Ok(res)
}
#[tokio::main]
async fn main() -> Result<(), String> {
let pool = Arc::new(sqlx::PgPool::connect("fake_url").await.unwrap());
let new_player_input = PlayerInput {
id: "abc".to_string(),
name: "John".to_string(),
location: "Boston".to_string(),
};
let player = handle(pool.clone(), &new_player_input).await?;
dbg!(player);
Ok(())
}
The error:
error: lifetime may not live long enough
--> src/main.rs:104:9
|
100 | pub async fn handle(pool: Arc<sqlx::PgPool>, input: &PlayerInput) -> Result<DomainPlayer, String> {
| - let's call the lifetime of this reference `'1`
...
104 | / Box::pin(async move {
105 | | let shirt_number = (args.shirt_next_value)("player").await?;
106 | |
107 | | let o = DomainPlayer::new(&input.id, &input.name, &input.location, shirt_number);
108 | |
109 | | Ok(o)
110 | | })
| |__________^ returning this value requires that `'1` must outlive `'static`
Let's rewrite your handle a little bit, to make it easier to explain:
pub async fn handle(pool: Arc<sqlx::PgPool>, input: &PlayerInput) -> Result<DomainPlayer, String> {
let lambdaref: &(dyn for<'b> Fn(PlayerCreateLambdaArgs<'b>) -> Pin<Box<dyn Future<Output=Result<DomainPlayer, String>> + Send + 'b>> + Sync) = &|args: PlayerCreateLambdaArgs| {
let input = input;
Box::pin(async move {
let shirt_number = (args.shirt_next_value)("player").await?;
let o = DomainPlayer::new(&input.id, &input.name, &input.location, shirt_number);
Ok(o)
})
};
let res = player_create(pool, "team", input, lambdaref)
.await?;
Ok(res)
}
so lambdaref references a lambda, which takes a PlayerCreateLambdaArgs<'b> and produces a a boxed future guaranteed to live at least as long as 'b.
And it also captures input which we know lives at least as long as 'a.
So we can deduce, that 'a must live at least as long as 'b otherwise the boxed future couldn't live at least as long as 'b, as it needs access to input, too.
But 'b is not yet determined and can be chosen by the caller of the lamba. The caller of the lambda could choose to use a PlayerCreateLambdaArgs<'static> and therefore choose 'b to be 'static.
So rustc has to demand 'a to be 'static so the lambda can be called with every possible 'b.
If you can change player_create and PlayerCreateLambdaArgs, then you can
side step this issue. player_create already gets input and could just
hand it down to the lamba inside PlayerCreateLambdaArgs, too.
Like in https://www.rustexplorer.com/b/8vonk0
If you don't mind me saying, it looks all a bit convoluted, what is it, you really want to achieve?

Cannot borrow data in an `Arc` as mutable

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()
}
}

How to write a simple warp handler returning json or html?

I have the following:
use warp::Filter;
pub struct Router {}
impl Router {
pub async fn handle(
&self,
) -> std::result::Result<impl warp::Reply, warp::Rejection> {
let uri = "/path";
match uri {
"/metrics-list" => {
let empty : Vec<u8> = Vec::new();
Ok(warp::reply::json(&empty))
}
"/metrics-ips" => {
let empty : Vec<u8> = Vec::new();
Ok(warp::reply::json(&empty))
}
&_ => {
Err(warp::reject::reject())
}
}
}
}
#[tokio::main]
pub async fn main() {
let r = Router {};
let handler = warp::path("/").map(|| r.handle());
warp::serve(handler);
// .run(([0, 0, 0, 0], 3000))
// .await;
}
But even with this simplified example I get an error:
error[E0277]: the trait bound `impl warp::Future: warp::Reply` is not satisfied
--> src/main.rs:41:17
|
41 | warp::serve(handler);
| ^^^^^^^ the trait `warp::Reply` is not implemented for `impl warp::Future`
|
::: $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.5/src/server.rs:26:17
|
26 | F::Extract: Reply,
| ----- required by this bound in `warp::serve`
|
= note: required because of the requirements on the impl of `warp::Reply` for `(impl warp::Future,)`
Why is that?
One solution is to call .into_response() on all your replies and then change the return type from std::result::Result<impl warp::Reply, warp::Rejection> to std::result::Result<warp::reply::Response, warp::Rejection>
pub async fn handle(
&self,
) -> std::result::Result<warp::reply::Response, warp::Rejection> {
let uri = "/path";
match uri {
"/metrics-list" => {
let empty : Vec<u8> = Vec::new();
Ok(warp::reply::json(&empty).into_response())
}
"/metrics-ips" => {
let empty : Vec<u8> = Vec::new();
Ok(warp::reply::json(&empty).into_response())
}
&_ => {
Err(warp::reject::reject().into_response())
}
}
}
The reason being if I understand this correctly that having an impl Trait in your return type lets you only use one type that implements that trait at once, since your function can ever only have one return type.

Returning a value from a function that spawns threads

I'm trying to return a String using pop() in a thread:
use crossbeam_utils::thread; // 0.7.2
use std::sync::{Arc, Mutex};
pub struct MyText {
my_text: Mutex<Vec<String>>,
}
pub trait MyTextOptions {
fn get(&self) -> String;
}
impl MyTextOptions for MyText {
fn get(&self) -> String {
let mut int_text = Arc::new(self);
thread::scope(|scope| {
scope.spawn(|_| {
let mut text_feed = int_text.my_text.lock().unwrap();
text_feed.pop().unwrap()
});
})
.unwrap()
}
}
When I try to run it I get:
error[E0308]: mismatched types
--> src/lib.rs:15:9
|
13 | fn get(&self) -> String {
| ------ expected `std::string::String` because of return type
14 | let mut int_text = Arc::new(self);
15 | / thread::scope(|scope| {
16 | | scope.spawn(|_| {
17 | | let mut text_feed = int_text.my_text.lock().unwrap();
18 | | text_feed.pop().unwrap()
19 | | });
20 | | })
21 | | .unwrap()
| |_________________^ expected struct `std::string::String`, found `()`
I don't understand why it is not returning the popped String value in text_feed.pop().unwrap().
The first problem is the following line:
text_feed.pop().unwrap()
You want an expression in order to return something, so you should remove the ;.
Once you do so, you hit the second problem: the return value of thread::scope will be of type crossbeam_utils::thread::ScopedJoinHandle but you want a String. The docs states that it has a join().
Putting it all together we get:
use crossbeam_utils::thread; // 0.7.2
use std::sync::{Arc, Mutex};
pub struct MyText {
my_text: Mutex<Vec<String>>,
}
pub trait MyTextOptions {
fn get(&self) -> String;
}
impl MyTextOptions for MyText {
fn get(&self) -> String {
let int_text = Arc::new(self);
thread::scope(|scope| {
scope
.spawn(|_| {
let mut text_feed = int_text.my_text.lock().unwrap();
text_feed.pop().unwrap()
})
.join()
.unwrap()
})
.unwrap()
}
}

Resources