разрешение несоответствия типов ‹impl std::future::Future as std::future::Future›::Output == std::result::Result‹wasm_bindgen::JsValue, wasm_bindgen::JsValue›

Я пытаюсь реализовать класс API, используя wasm_bindgen с асинхронными вызовами.

#![allow(non_snake_case)]

use std::future::Future;

use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use js_sys::Promise;
use web_sys::{Request, RequestInit, RequestMode, Response};
use wasm_bindgen_futures::future_to_promise;

use crate::fetch_example::*;


#[wasm_bindgen]
#[derive(Debug, Serialize, Deserialize)]
pub struct API {
    root: String,
}


#[wasm_bindgen]
impl API {
    pub fn new(root: &str) -> Self {
        Self {
            root: root.to_string(),
        }
    }

    pub fn getVersion(&self) -> Promise {
        let url = format!("{}/version", self.root);

        future_to_promise(async move {
            _request_json(&url, "GET")
        })
    }

    // other methods ...
}


// What is the correct returned type instead of Result<JsValue, JsValue> ???
async fn _request_json(url: &str, method: &str) -> Result<JsValue, JsValue> {
    let mut opts = RequestInit::new();
    opts.method(method);
    opts.mode(RequestMode::Cors);

    let request = Request::new_with_str_and_init(&url, &opts)?;

    request.headers().set("Accept", "application/json")?;

    let window = web_sys::window().unwrap();
    let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;

    let resp: Response = resp_value.dyn_into().unwrap();

    let json = JsFuture::from(resp.json()?).await?;

    Ok(json)
}

Как видно, HTTP-вызов я вынес в отдельную приватную функцию _request_json, чтобы избежать дублирования кода в разных API-методах (их должно быть несколько, а не только getVersion).

Я взял базовый пример вызова HTTP отсюда: https://rustwasm.github.io/wasm-bindgen/examples/fetch.html

Также я обнаружил, что асинхронные вызовы методов структуры должны быть реализованы с помощью future_to_promise: https://github.com/rustwasm/wasm-bindgen/issues/1858

Таким образом, проблема связана с типом, возвращаемым _request_json. Я не могу правильно угадать.

При компиляции проекта получаю ошибку:

type mismatch resolving `<impl std::future::Future as std::future::Future>::Output == std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`

Если я копирую тело _request_json внутрь future_to_promise, все работает нормально.

Каково правильное возвращаемое выражение для _request_json, чтобы код работал?


person Fomalhaut    schedule 03.03.2021    source источник


Ответы (1)


Эта конструкция:

async move {
    _request_json(&url, "GET")
}

имеет тип impl Future<Output = impl Future<Output = Result<JsValue, JsValue>>>.

Вы можете исправить это следующим образом:

future_to_promise(async move {
    _request_json(&url, "GET").await
})

и вероятно также нравится это:

future_to_promise(_request_json(&url, "GET"))
person Markus Unterwaditzer    schedule 03.03.2021
comment
Спасибо. Ваше объяснение вполне понятно. - person Fomalhaut; 04.03.2021