Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use predicates in an async function?

I use thirtyfour in my Rust script, and it uses tokio as the async runtime.

When I use find in a Vec::iter, it doesn't work as I expect:

#[tokio::main]
async fn main() -> WebDriverResult<()> {
    let dropdown = driver.find_element(By::Tag("select")).await?;
    dropdown
        .find_elements(By::Tag("option"))
        .await?
        .iter()
        .find(|&&x| x.text() == book_time.date) // Error, x.text() return a futures::Future type while book_time.date return a &str.
        .click()
        .await?;
}

After I tried Ibraheem Ahmed's solution, I met more errors:

let dropdown = driver.find_element(By::Tag("select")).await?;
let elements = dropdown.find_elements(By::Tag("option")).await?;
let stream = stream::iter(elements);
let elements = stream.filter(|x| async move { x.text().await.unwrap() == target_date });
error: lifetime may not live long enough
   --> src\main.rs:125:38
    |
125 |     let elements = stream.filter(|x| async move { x.text().await.unwrap() == target_date });
    |                                   -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
    |                                   ||
    |                                   |return type of closure is impl futures::Future
    |                                   has type `&'1 thirtyfour::WebElement<'_>`
like image 416
CloudL Avatar asked Aug 06 '26 18:08

CloudL


1 Answers

There's a good thread on the Rust User's Forum that covers a similar question.

I tried the code snippets below by modifying the thirtyfour tokio_async example. I didn't have your full context, so I created an example that found a link based on its text on the wikipedia.org home page.

  1. filter_map.

    let target_value = "Terms of Use";
    let found_elements: Vec<_> = stream
        .filter_map(|x| async move {
            if let Ok(text) = x.text().await {
                if text == target_value {
                    println!("found");
                    return Some(x);
                }
            }
            None
        })
        .collect()
        .await;
    
  2. while loop (which is probably not what you are after, but could be a simple solution if your logic fits easily inside)...

    while let Some(element) = stream.next().await {
        let text = element.text().await?;
        println!("link text result: {}", text);
    }
    
like image 61
Ultrasaurus Avatar answered Aug 09 '26 12:08

Ultrasaurus



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!