2

I have the following Rust function

fn query_list_or_empty<'a, P, R>(
    conn: &'a mut SimpleConnection,
    sql: &'a str,
    params: P,
) -> Peekable<Box<dyn Iterator<Item = Result<R, FbError>> + 'a>>
where
    P: rsfbclient::IntoParams,
    R: FromRow + 'static,
{
    match conn.query_iter(sql, params) {
        Ok(iter) => iter.peekable(),
        Err(e) => {
            error!("Failed to execute query: {}", e);

            Box::new(std::iter::empty::<Result<R, FbError>>()).peekable()
        }
    }
}

In case of an error I just want to log the error and return an empty peekable iterator, however I can not find how to initialize an empty list of the correct type - Peekable<Box<dyn Iterator<Item = Result<R, FbError>> + 'a>>

I found how to return an empty NONE PEEKABLE iterator like this:

fn query_list_or_empty<'a, P, R>(
    conn: &'a mut SimpleConnection,
    sql: &'a str,
    params: P,
) -> Box<dyn Iterator<Item = Result<R, FbError>> + 'a>
where
    P: rsfbclient::IntoParams,
    R: FromRow + 'static,
{
    match conn.query_iter(sql, params) {
        Ok(iter) => iter,
        Err(e) => {
            error!("Failed to execute query: {}", e);

            Box::new(std::iter::empty::<Result<R, FbError>>())
        }
    }
}

It works fine and I can call it and add the "packability" later like this:

            let mut rows_iter = query_list_or_empty(
                &mut conn,
                &config.select_candidates,
                (&config.step_id, &config.block_period),
            )
            .peekable(); // <- make it peekeable

Although it is a solution, I do want to make it work - this is challenging Rust I want to master....

1 Answer 1

2

Minimized example, analogous to the first code snippet from the question (playground):

use std::iter::Peekable;

// Stub for rsfbclient's method
fn query_iter() -> Result<Box<dyn Iterator<Item = ()>>, ()> {
    todo!()
}

fn query_list_or_empty() -> Peekable<Box<dyn Iterator<Item = ()>>> {
    match query_iter() {
        Ok(iter) => iter.peekable(),
        Err(e) => Box::new(std::iter::empty()).peekable()
    }
}

This errors, because Rust can't coerce Box<T> to Box<dyn Trait> inside some other type - in this case, inside Peekable; it must be coerced while it is still a Box.

One possible way to fix this is to add coercion before calling .peekable(); however, it becomes somewhat cumbersome, because most of the type must be spelled explicitly, only an associated type can be inferred:

match query_iter() {
    Ok(iter) => iter.peekable(),
    Err(e) => (Box::new(std::iter::empty()) as Box<dyn Iterator<Item = _>>).peekable()
}

However, you can also just place .peekable() in the same function, but out of the match:

match query_iter() {
    Ok(iter) => iter,
    Err(e) => Box::new(std::iter::empty()),
}.peekable()

...in which case, as you've already noticed, Box can be coerced automatically; first match arm here is guiding type inference.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.