1

我想编写一个显示大型二进制文件内容的 vscode 扩展,用以下方式编写bincode

#[macro_use]
extern crate serde_derive;

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufWriter};

#[derive(Serialize, Deserialize)]
pub struct MyValue {
    pub name: String,
}

#[derive(Serialize, Deserialize)]
pub struct MyStruct {
    pub data: HashMap<String, MyValue>,
}

impl MyStruct {
    pub fn dump(&self, filename: &str) -> Result<(), String> {
        let file = File::create(filename).map_err(|msg| msg.to_string())?;
        let writer = BufWriter::new(file);
        bincode::serialize_into(writer, self).map_err(|msg| msg.to_string())
    }

    pub fn load(filename: &str) -> Result<Self, String> {
        let file = File::open(filename).map_err(|msg| msg.to_string())?;
        let reader = BufReader::new(file);
        bincode::deserialize_from::<BufReader<_>, Self>(reader).map_err(|msg| msg.to_string())
    }
}

因此有一个 wasm 绑定:


#[wasm_bindgen]
#[derive(Clone)]
pub struct PyMyStruct {
    inner: Arc<MyStruct>,
}

#[wasm_bindgen]
impl PyMyStruct {
    pub fn new(filename: &str) -> Self {
        Self {
            inner: Arc::new(MyStruct::load(filename).unwrap()),
        }
    }

    pub fn header(self) -> Array {
        let keys = Array::new();
        for key in self.inner.data.keys() {
            keys.push(&JsValue::from_str(key));
        }
        keys
    }

    pub fn value(&self, name: &str) -> JsValue {
        if let Some(value) = self.inner.data.get(name) {
            JsValue::from_serde(value).unwrap_or(JsValue::NULL)
        } else {
            JsValue::NULL
        }
    }
}

它为 JavaScript 世界提供了一个简单的接口,以便访问该文件的内容。在 JavaScript 端处理时使用Arc以防止昂贵的意外内存复制。keys(未标记为可变但 rust 编译器推荐这种方式可能看起来很奇怪)

运行测试代码时:

const {PyMyStruct} = require("./corejs.js");

let obj = new PyMyStruct("../../dump.spb")
console.log(obj.header())

您收到错误消息:

错误:传递给 rust 的空指针

有人知道如何处理这个用例吗?

谢谢!

4

2 回答 2

1

这里的问题是您使用new PyMyStruct()的是PyMyStruct.new(). 在 wasm-bindgen 的调试模式下,您将在运行时收到关于此的错误。使用.new()将解决您的问题:

let obj = PyMyStruct.new("../../dump.spb")

如果将#[wasm_bindgen(constructor)]注释添加到new方法中,那么 new PyMyStruct()也可以:

#[wasm_bindgen]
impl PyMyStruct {
    #[wasm_bindgen(constructor)]
    pub fn new(filename: &str) -> Self {
        Self {
            inner: 1,
        }
    }
}

现在这很好:

let obj = new PyMyStruct("../../dump.spb")
于 2020-12-10T23:02:15.857 回答
0

我通过使用https://neon-bindings.com而不是将 API 编译为 web-assembly 解决了这个问题。

此处的绑定如下所示:

use core;
use std::rc::Rc;
use neon::prelude::*;

#[derive(Clone)]
pub struct MyStruct {
    inner: Rc<core::MyStruct>,
}

declare_types! {
    pub class JsMyStruct for MyStruct {
        init(mut cx) {
            let filename = cx.argument::<JsString>(0)?.value();

            match core::MyStruct::load(&filename) {
                Ok(inner) => return Ok(MyStruct{
                    inner: Rc::new(inner)
                }),
                Err(msg) => {
                    panic!("{}", msg)
                }
            }
        }

        method header(mut cx) {
            let this = cx.this();
            let container = {
                let guard = cx.lock();
                let this = this.borrow(&guard);
                (*this).clone()
            };
            let keys = container.inner.data.keys().collect::<Vec<_>>();
            let js_array = JsArray::new(&mut cx, keys.len() as u32);
            for (i, obj) in keys.into_iter().enumerate() {
                let js_string = cx.string(obj);
                js_array.set(&mut cx, i as u32, js_string).unwrap();
            }
            Ok(js_array.upcast())
        }

        method value(mut cx) {
            let key = cx.argument::<JsString>(0)?.value();
            let this = cx.this();
            let container = {
                let guard = cx.lock();
                let this = this.borrow(&guard);
                (*this).clone()
            };
            if let Some(data) = container.inner.data.get(&key) {
                return Ok(neon_serde::to_value(&mut cx, data)?);
            } else {
                panic!("No value for key \"{}\" available", key);
            }
        }
    }
}

register_module!(mut m, {
    m.export_class::<JsMyStruct>("MyStruct")?;
    Ok(())
});

于 2020-12-11T12:34:53.637 回答