Как поставить черту, привязанную к элементам, созданным с помощью document.create_element - PullRequest
0 голосов
/ 11 января 2020

Работа над минимальным прототипом / тестовой программой для работы с Dom с использованием Rust и wasm-bindgen.

Создание элемента с помощью document.create_element(tag), который возвращает web_sys::Element. Элемент приводится к указанному типу c, в зависимости от тега, например, web_sys::HtmlButtonElement. Это работает и, кроме того, помещает небольшую оболочку, используемую для установки типа элемента, определяющего c сборщиков.

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.

Дополнительная или замена, связанная с wasm_bindgen::JsCast в impl<T : wasm_bindgen::JsCast>. Может ли это быть сделано?

1 Ответ

2 голосов
/ 11 января 2020

Документация wasm_bindgen::JsCast::dyn_into гласит, что она полагается на JsCast::has_type, что в свою очередь вызывает JsCast::instanceof. И действительно, web_sys::Element реализует черту JsCast. Как и другие типы элементов HTML, такие как HtmlButtonElement.

. Реализация создается из файлов Web IDL , которые являются формальным определением интерфейсов веб-браузера. Однако:

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> as:

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 перспективы :

enter image description here

...