[Help] Poll future from an Iterator implementation with hyper + tokio

I am currently in the process of writing a library for a web api with async-await.
Based on the hyper-async examples I came up with the following main function:

#![feature(async_await)]

// omitted some stuff

#[tokio::main]
async fn main() -> Result<()> {
    let client = complicated_builder_response.await?;

    // .search.await? returns the Search struct from below.
    for i in client.search("Certain Show").await? {
        dbg!(i);
    }
    Ok(())
}

So far so good and now every function, that uses .await needs to be flagged as async (questionable because wouldn't .await block the function and therefore make it sync again?).

The search api should be wrapped in an Iterator, that fetches every 50 iterations a new list of search results. The Iterator trait has to be sync (afaik there isn't even a way to define async traits) and therefore I can't await the responses inside the next()-function.

While searching for solutions, I came across this post, which states, that I have to use tokio, to poll the future. The only type, that polls a future and yields the Result of it is tokio::runtime::Runtime::block_on() and I came up with the following code:

pub struct Search {
    query       : String,
    media_types : String,
    offset      : usize,
    limit       : usize,
    locale      : String, // TODO: make smart once lifetime of Locale is removed!
    session_id  : String,
    client      : Rc<RefCell<HttpsClient>>,
    runtime     : Runtime,
    position    : usize,
    result      : Vec<SeriesData>,
}

impl Iterator for Search {
    type Item = SeriesData;

    fn next(&mut self) -> Option<Self::Item> {
        if self.position+1 >= self.result.len() {
            let future = request! [
                @client     => self.client,
                @method     => "POST",
                // implementation details omitted,
                // it sends the self fields to the server
                @result     => Response<Vec<SeriesData>>,
            ];

            // into_data() converts Response<T> to Result<T>
            self.result = self.runtime.block_on(future).unwrap().into_data().unwrap();

            self.offset += 50;
            self.position = 0;

        }

        let result = self.result[self.position].clone();
        self.position += 1;
        Some(result)
    }
}

The above code will panic, because a tokio executor is already running -.- (I suspect #[tokio::main] as the culprit)

thread 'main' panicked at 'nested block_on: EnterError { reason: "attempted to run an executor while another executor is already running" }', src/libcore/result.rs:1084:5

I found no other function in the tokio library, that allows me to block the thread and resolve the future.

Is this even possible? or do I have to wait until there is an async Iterator?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.