Skip to content

help mapping chrome.tabs.query callback #1910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ctaggart opened this issue Dec 14, 2019 · 3 comments
Closed

help mapping chrome.tabs.query callback #1910

ctaggart opened this issue Dec 14, 2019 · 3 comments
Labels

Comments

@ctaggart
Copy link
Contributor

ctaggart commented Dec 14, 2019

How would I call [chrome.tabs.query] to get back an array of tabs. I'm struggling to write the interop for this.

https://developer.chrome.com/extensions/tabs#method-query
http://definitelytyped.org/docs/chrome--chrome/interfaces/chrome.tabs.tab.html

I created a module named chrome_tabs.rs and it currently has:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct QueryInfo {
    pub active: Option<bool>
}

#[wasm_bindgen]
pub struct Tab {
    pub active: bool,
    pub id: u32,
}

#[wasm_bindgen(module = "chrome.tabs")]
extern "C" {
    pub fn query(query_info: QueryInfo, callback: &Fn([&Tab]));
}

Errors with:

error[E0277]: the trait bound `&dyn for<'r> std::ops::Fn([&'r chrome_tabs::Tab]): wasm_bindgen::convert::traits::IntoWasmAbi` is not satisfied
  --> src/chrome_tabs.rs:19:1
   |
19 | #[wasm_bindgen(module = "chrome.tabs")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `wasm_bindgen::convert::traits::IntoWasmAbi` is not implemented for `&dyn for<'r> std::ops::Fn([&'r chrome_tabs::Tab])`
   |
   = help: the following implementations were found:
             <&'a (dyn for<'r> std::ops::Fn(&'r A) -> R + 'b) as wasm_bindgen::convert::traits::IntoWasmAbi>
             <&'a (dyn std::ops::Fn() -> R + 'b) as wasm_bindgen::convert::traits::IntoWasmAbi>
             <&'a (dyn std::ops::Fn(A) -> R + 'b) as wasm_bindgen::convert::traits::IntoWasmAbi>
             <&'a (dyn std::ops::Fn(A, B) -> R + 'b) as wasm_bindgen::convert::traits::IntoWasmAbi>
           and 6 others

I'm using nightly because I was looking at

#[wasm_bindgen]
pub struct RefFirstArgument {
contents: u32,
}
#[wasm_bindgen_test]
fn reference_as_first_argument_builds_at_all() {
#[wasm_bindgen]
extern "C" {
fn ref_first_arg1(a: &Fn(&JsValue));
fn ref_first_arg2(a: &mut FnMut(&JsValue));
fn ref_first_arg3(a: &Closure<Fn(&JsValue)>);
fn ref_first_arg4(a: &Closure<FnMut(&JsValue)>);
fn ref_first_custom1(a: &Fn(&RefFirstArgument));
fn ref_first_custom2(a: &mut FnMut(&RefFirstArgument));
fn ref_first_custom3(a: &Closure<Fn(&RefFirstArgument)>);
fn ref_first_custom4(a: &Closure<FnMut(&RefFirstArgument)>);
trying to find the answer.

wasm-bindgen = { version = "0.2.55", features = ["serde-serialize","nightly"]  }

If I do not make Tab a reference, then I get this error:

error[E0277]: the trait bound `[chrome_tabs::Tab]: wasm_bindgen::convert::traits::FromWasmAbi` is not satisfied
  --> src/chrome_tabs.rs:29:41
   |
29 |     pub fn query(query_info: QueryInfo, callback: &Fn([Tab]));
   |                                         ^^^^^^^^ the trait `wasm_bindgen::convert::traits::FromWasmAbi` is not implemented for `[chrome_tabs::Tab]`
   |
   = note: required because of the requirements on the impl of `wasm_bindgen::convert::traits::IntoWasmAbi` for `&dyn std::ops::Fn([chrome_tabs::Tab])`
@Pauan
Copy link
Contributor

Pauan commented Dec 14, 2019

This happens because we don't currently support Vec (or slices) for arbitrary types. So you'll have to use js_sys::Array instead, like this:

pub fn query(query_info: &QueryInfo, callback: &dyn Fn(&js_sys::Array));

Then after this PR is accepted, you'll be able to use to_vec to convert the Array into a Vec (or iter to convert the Array into a Rust Iterator).

@ctaggart
Copy link
Contributor Author

ctaggart commented Dec 14, 2019

Thanks! I reread https://rustwasm.github.io/docs/wasm-bindgen/reference/arbitrary-data-with-serde.html and it looks like I can go to and from a JsValue using serde_wasm_bindgen, such as serde_wasm_bindgen::to_value(query_info).unwrap(). I ran into bug #1911 when I tried:

use serde::{Serialize, Deserialize};
use wasm_bindgen::prelude::*;

#[derive(Serialize, Debug)]
pub struct QueryInfo {
    pub active: Option<bool>
}

#[derive(Deserialize, Debug)]
pub struct Tab {
    pub active: bool,
    pub id: u32,
}

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = "chrome.tabs")]
    pub fn query(query_info: &JsValue, callback: &dyn Fn(JsValue));
}

@ctaggart
Copy link
Contributor Author

It took me a while to figure out the lifetimes with the closures, but I'm happy with the result. Great job so far on this library!

Usage

                chrome_tabs::query(&chrome_tabs::QueryInfo{active: None}, &|tabs: Vec<Tab>| 
                    web_sys::console::log_1(&format!("tabs: {:#?}", tabs).into()));

chrome_tabs.rs implementation

use serde::{Serialize, Deserialize};
use wasm_bindgen::prelude::*;

#[derive(Serialize, Debug)]
pub struct QueryInfo {
    pub active: Option<bool>
}

#[derive(Deserialize, Debug)]
pub struct Tab {
    pub active: bool,
    pub id: u32,
}

#[wasm_bindgen]
extern "C" {
    type Tabs;

    #[wasm_bindgen(method)]
    fn query(this: &Tabs, query_info: &JsValue, callback: JsValue);
}

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = chrome)]
    static tabs: Tabs;
}

pub fn query(query_info: &QueryInfo, callback: &'static dyn Fn(Vec<Tab>)){
    tabs.query(&serde_wasm_bindgen::to_value(query_info).unwrap(), Closure::once_into_js(move |v: JsValue| 
        callback(serde_wasm_bindgen::from_value(v).unwrap())   
    ));
}

I'm deferring the error handling until later. #1742 looks like a good idea. There is too many unwrap calls above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants