如何将特征绑定到使用 document.create_element 构建的元素
How to put a trait Bound to elements built with document.create_element
正在使用 Rust 和 wasm-bindgen
.
编写用于 Dom 操作的最小 prototype/test 程序
使用 document.create_element(tag)
构建元素,其中 returns 和 web_sys::Element
. The element is casted to specific type, depending on tag e.g. 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();
现在我寻找一个 trait Bound,它限制了可以从 web_sys::Element
转换的元素。例如。 HtmlSpanElement
, HtmlDivElement
, ..., HtmlButtonElement
.
绑定到 impl<T : wasm_bindgen::JsCast>
中的 wasm_bindgen::JsCast
的附加或替换绑定,可以这样做吗?
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>
。这很可能是 web-sys
作者有意识的设计决定,因为它在 WebIDL / JavaScript perspective:
中也有意义
正在使用 Rust 和 wasm-bindgen
.
使用 document.create_element(tag)
构建元素,其中 returns 和 web_sys::Element
. The element is casted to specific type, depending on tag e.g. 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();
现在我寻找一个 trait Bound,它限制了可以从 web_sys::Element
转换的元素。例如。 HtmlSpanElement
, HtmlDivElement
, ..., HtmlButtonElement
.
绑定到 impl<T : wasm_bindgen::JsCast>
中的 wasm_bindgen::JsCast
的附加或替换绑定,可以这样做吗?
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>
。这很可能是 web-sys
作者有意识的设计决定,因为它在 WebIDL / JavaScript perspective: