0

使用 Rust 和wasm-bindgen.

用 构建元素document.create_element(tag),它返回一个web_sys::Element。元素被转换为特定类型,具体取决于标签,例如web_sys::HtmlButtonElement. 这可行,并且还放入了一个小包装器,用于设置元素类型特定的构建器。

struct ElemSpec<T> {
    html_tag : html_const::HtmlTag<'static>,
    resource_type: std::marker::PhantomData<T>
}

impl<T : wasm_bindgen::JsCast> ElemSpec<T> {

    fn build_element(&self) -> T {
        let window = web_sys::window().expect("no global `window` exists");
        let document = window.document().expect("should have a document on window");
        let elem = document.create_element(&self.html_tag);

        let elem = match elem {
            Ok(e) => e,
            Err(error) => {
                panic!("Call to document.create_element failed with error: {:?}", error)
            },
        };
        let result = wasm_bindgen::JsCast::dyn_into::<T>(elem);
        let helement = match result {
            Ok(e) => e,
            Err(e) => {
                panic!("Cast to specific Element failed tag:{}", &self.html_tag);
            },
        };
        helement
    }
}

const BUTTON_ELEM : ElemSpec<web_sys::HtmlButtonElement> =
    ElemSpec{ html_tag: html_const::BUTTON, resource_type: std::marker::PhantomData};

这是有效的,一个HtmlButtonElement是用:

let buttonElement = BUTTON_ELEM.build_element();

现在我寻找一个特征 Bound,它限制为可以从web_sys::Element. 例如HtmlSpanElement, HtmlDivElement, ..., HtmlButtonElement

附加或替换 Bound to wasm_bindgen::JsCastin impl<T : wasm_bindgen::JsCast>,可以这样做吗?

4

1 回答 1

2

wasm_bindgen::JsCast::dyn_into文档说明它依赖于它,而JsCast::has_type后者又调用JsCast::instanceof. 并且确实web_sys::Element实现JsCast了特征。其他 HTML 元素类型也是如此,例如HtmlButtonElement.

该实现是从Web IDL文件生成的,这些文件是 Web 浏览器接口的正式定义。然而:

impl JsCast for Element {
    fn instanceof(val: &JsValue) -> bool {
        #[link(wasm_import_module = "__wbindgen_placeholder__")]
        #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
        extern "C" {
            fn __widl_instanceof_Element(val: u32) -> u32;
        }
        #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
        unsafe fn __widl_instanceof_Element(_: u32) -> u32 {
            panic!("cannot check instanceof on non-wasm targets");
        }
        unsafe {
            let idx = val.into_abi();
            __widl_instanceof_Element(idx) != 0
        }
    }
}

生成的instanceof方法调用 WebIDL 本机库。由于它跨越了语言边界,它不能告诉我们太多关于这些元素类型在 Rust 方面的共同点。

另一方面,HtmlButtonElement其他人也实现AsRef<Element>为:

impl AsRef<Element> for HtmlButtonElement {
    #[inline]
    fn as_ref(&self) -> &Element {
        use wasm_bindgen::JsCast;
        Element::unchecked_from_js_ref(self.as_ref())
    }
}

所以你有它,其中一个常见的界限是AsRef<Element>. 这很可能是作者有意识的设计决定,因为从WebIDL/JavaScript 的角度来看web-sys它也很有意义:

在此处输入图像描述

于 2020-01-11T10:38:12.157 回答