Return different types from match arms

โš“ Rust    ๐Ÿ“… 2025-09-29    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 12      

surdeus

Warning

This post was published 112 days ago. The information described in this article may have changed.

I am trying to create a handle function for axum, but the compiler doesn't let me return the types Html<String> and Result<([(HeaderName, String)], Body), (StatusCode, String)> from two different match arms, even though they both implement IntoResponse. I tried wrapping impl IntoResponse into a Box Box<dyn IntoResponse>, but it seems like axum doesn't implement IntoResponse for Box<IntoResponse>.
Thanks in advance.

Edit: The two types from the if and else blocks are not compatible either, even though i created the if false block to make sure the compiler infers the exact same type.

pub async fn any(State(send_log): ArcSendLog, Path(path): Path<String>) -> impl IntoResponse {
    match read_file(format!("{}/{}", HTML_DIR, path)) {
        Ok(c) => Html(c),
        Err(err) => {
            if err.kind() == ErrorKind::InvalidData {
                file(State(send_log), path).await
            } else {
                super::warning("Could not open file", err.kind());
                not_found(State(send_log), path.as_str()).await
            }
        }
    }
}
pub async fn file(State(_): ArcSendLog, path: String) -> impl IntoResponse {
    let filename = if path.contains('/') {
        path.split('/').last().unwrap()
    } else {
        path.as_str()
    };
    let file = match tokio::fs::File::open("Cargo.toml").await {
        Ok(file) => file,
        Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
    };
    // convert the `AsyncRead` into a `Stream`
    let stream = ReaderStream::new(file);
    // convert the `Stream` into an `axum::body::HttpBody`
    let body = Body::from_stream(stream);

    let headers = [
        (header::CONTENT_TYPE, "text/toml; charset=utf-8".to_string()),
        (
            header::CONTENT_DISPOSITION,
            format!("attachment; filename=\"{}\"", filename),
        ),
    ];

    Ok((headers, body))
}
pub async fn not_found(State(_): ArcSendLog, path: &str) -> impl IntoResponse {
    let body = read_file_panic(HTML_INVALID).replace("ยงPATHยง", path);
    let headers = [(header::CONTENT_LENGTH, body.len().to_string())];
    if false {
        Err((StatusCode::NOT_FOUND, "File not found".to_string()))
    } else {
        Ok((headers, body))
    }
}
error[E0308]: `if` and `else` have incompatible types
  --> src/response.rs:19:17
   |
15 | /             if err.kind() == ErrorKind::InvalidData {
16 | |                 file(State(send_log), path).await
   | |                 --------------------------------- expected because of this
17 | |             } else {
18 | |                 super::warning("Could not open file", err.kind());
19 | |                 not_found(State(send_log), path.as_str()).await
   | |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
20 | |             }
   | |_____________- `if` and `else` have incompatible types
...
24 |   pub async fn file(State(_): ArcSendLog, path: String) -> impl IntoResponse {
   |                                                            ----------------- the expected opaque type
...
52 |   pub async fn not_found(State(_): ArcSendLog, path: &str) -> impl IntoResponse {
   |                                                               ----------------- the found opaque type
   |
   = note: expected opaque type `impl IntoResponse`
              found opaque type `impl IntoResponse`
   = note: distinct uses of `impl Trait` result in different opaque types

2 posts - 2 participants

Read full topic

๐Ÿท๏ธ Rust_feed