2023-05-22 08:06:09 +00:00
|
|
|
---
|
|
|
|
title: Rust + Boa
|
|
|
|
pagination_prev: demos/bigdata/index
|
|
|
|
pagination_next: solutions/input
|
|
|
|
---
|
|
|
|
|
|
|
|
import current from '/version.js';
|
|
|
|
import CodeBlock from '@theme/CodeBlock';
|
|
|
|
|
2024-04-14 07:40:38 +00:00
|
|
|
:::danger pass
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
In a production application, it is strongly recommended to use a binding for a
|
|
|
|
more performant engine like [`v8`](/docs/demos/engines/v8#rust)
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-10-29 03:22:50 +00:00
|
|
|
[Boa](https://boajs.dev/) is a JavaScript engine written in Rust.
|
2023-05-22 08:06:09 +00:00
|
|
|
|
2023-10-29 03:22:50 +00:00
|
|
|
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
|
|
|
data from spreadsheets.
|
|
|
|
|
2024-04-12 01:04:37 +00:00
|
|
|
The ["Complete Example"](#complete-example) section creates a command-line tool
|
|
|
|
for reading data from spreadsheets and generating CSV rows.
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
## Integration Details
|
|
|
|
|
2023-10-29 03:22:50 +00:00
|
|
|
### Initialize Boa
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
A JS context can be constructed in one line:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use boa_engine::Context;
|
|
|
|
|
|
|
|
/* initialize */
|
|
|
|
let context = &mut Context::default();
|
|
|
|
```
|
|
|
|
|
|
|
|
The following helper function evaluates strings as JS code:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use std::string::String;
|
|
|
|
use boa_engine::{Context, Source, JsError};
|
|
|
|
|
|
|
|
/* simple wrapper to evaluate code snippets */
|
|
|
|
fn eval_code(c: &mut Context, code: &str) -> Result<String, JsError> {
|
|
|
|
let src = Source::from_bytes(code);
|
2023-06-05 20:12:53 +00:00
|
|
|
match c.eval(src) {
|
2023-05-22 08:06:09 +00:00
|
|
|
Ok(res) => { return Ok(res.to_string(c).unwrap().to_std_string_escaped()); }
|
|
|
|
Err(e) => { return Err(e); }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-10-29 03:22:50 +00:00
|
|
|
### Load SheetJS Scripts
|
|
|
|
|
|
|
|
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
|
|
|
can be parsed and evaluated in a Boa context.
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
Boa provides a special helper to read source code from a path:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use std::path::Path;
|
|
|
|
use std::string::String;
|
2024-03-16 16:04:18 +00:00
|
|
|
use boa_engine::{js_string, Context, Source, JsError};
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
/* simple wrapper to evaluate an entire script file */
|
|
|
|
fn eval_file(c: &mut Context, path: &str) -> Result<String, JsError> {
|
|
|
|
let src = Source::from_filepath(Path::new(path)).unwrap();
|
2023-06-05 20:12:53 +00:00
|
|
|
match c.eval(src) {
|
2023-05-22 08:06:09 +00:00
|
|
|
Ok(res) => { return Ok(res.to_string(c).unwrap().to_std_string_escaped()); }
|
|
|
|
Err(e) => { return Err(e); }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// ...
|
|
|
|
/* load library */
|
|
|
|
match eval_file(context, "./xlsx.full.min.js") {
|
|
|
|
Ok(_res) => {}
|
|
|
|
Err(e) => { return eprintln!("Uncaught {e}"); }
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
To confirm the library is loaded, `XLSX.version` can be inspected:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
/* get version string */
|
|
|
|
match eval_code(context, "XLSX.version") {
|
|
|
|
Ok(res) => { println!( "SheetJS library version {}", res); }
|
|
|
|
Err(e) => { return eprintln!("Uncaught {e}"); }
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Reading Files
|
|
|
|
|
|
|
|
Boa supports `ArrayBuffer` natively. This snippet reads data from a file into
|
|
|
|
`Vec<u8>` and stores the data as an `ArrayBuffer` in global scope:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
/* read file */
|
|
|
|
let data: Vec<u8> = fs::read("pres.xlsx").unwrap();
|
|
|
|
let array: JsArrayBuffer = JsArrayBuffer::from_byte_block(data, context).unwrap();
|
|
|
|
let attrs = Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE;
|
2024-03-16 16:04:18 +00:00
|
|
|
context.register_global_property(js_string!("buf"), array, attrs);
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
/* parse with SheetJS */
|
|
|
|
match eval_code(context, "void (globalThis.wb = XLSX.read(buf))") {
|
|
|
|
Ok(_res) => { }
|
|
|
|
Err(e) => { return eprintln!("Uncaught {e}"); }
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
`wb` will be a variable in the JS environment that can be inspected using the
|
|
|
|
various SheetJS API functions.
|
|
|
|
|
|
|
|
## Complete Example
|
|
|
|
|
2023-11-13 11:17:25 +00:00
|
|
|
:::note Tested Deployments
|
2023-05-22 08:06:09 +00:00
|
|
|
|
2023-06-05 20:12:53 +00:00
|
|
|
This demo was tested in the following deployments:
|
|
|
|
|
2024-03-16 16:04:18 +00:00
|
|
|
| Architecture | Boa | Date |
|
|
|
|
|:-------------|:---------|:-----------|
|
2024-04-26 04:16:13 +00:00
|
|
|
| `darwin-x64` | `0.18.0` | 2024-04-25 |
|
2024-03-16 16:04:18 +00:00
|
|
|
| `darwin-arm` | `0.17.3` | 2023-10-20 |
|
2024-04-26 04:16:13 +00:00
|
|
|
| `win10-x64` | `0.18.0` | 2024-04-25 |
|
2024-03-16 16:04:18 +00:00
|
|
|
| `win11-arm` | `0.17.3` | 2023-12-01 |
|
2024-03-22 04:45:40 +00:00
|
|
|
| `linux-x64` | `0.18.0` | 2024-03-21 |
|
2024-03-16 16:04:18 +00:00
|
|
|
| `linux-arm` | `0.17.3` | 2023-12-01 |
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
1) Create a new project:
|
|
|
|
|
|
|
|
```bash
|
2023-07-06 07:21:41 +00:00
|
|
|
cargo new sheetjs-boa
|
|
|
|
cd sheetjs-boa
|
2023-05-22 08:06:09 +00:00
|
|
|
cargo run
|
|
|
|
```
|
|
|
|
|
2023-07-21 09:17:32 +00:00
|
|
|
2) Add the `boa_engine` crate:
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
```bash
|
2023-07-21 09:17:32 +00:00
|
|
|
cargo add boa_engine
|
2023-05-22 08:06:09 +00:00
|
|
|
```
|
|
|
|
|
2024-04-26 04:16:13 +00:00
|
|
|
3) Download the SheetJS Standalone script and test file. Save both files in the
|
|
|
|
project directory:
|
2023-09-22 06:32:55 +00:00
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
2024-04-26 04:16:13 +00:00
|
|
|
<li><a href="https://docs.sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
2023-09-22 06:32:55 +00:00
|
|
|
</ul>
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
<CodeBlock language="bash">{`\
|
2024-04-26 04:16:13 +00:00
|
|
|
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
|
|
|
|
curl -LO https://docs.sheetjs.com/pres.xlsx`}
|
2023-05-22 08:06:09 +00:00
|
|
|
</CodeBlock>
|
|
|
|
|
|
|
|
4) Download [`main.rs`](pathname:///boa/main.rs) and replace `src/main.rs`:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
curl -L -o src/main.rs https://docs.sheetjs.com/boa/main.rs
|
|
|
|
```
|
|
|
|
|
2024-04-26 04:16:13 +00:00
|
|
|
5) Build and run the app in release mode:
|
2023-05-22 08:06:09 +00:00
|
|
|
|
|
|
|
```bash
|
2023-08-31 22:09:08 +00:00
|
|
|
cargo run --release
|
2023-05-22 08:06:09 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
After a short wait, the contents will be displayed in CSV form.
|
2023-08-31 22:09:08 +00:00
|
|
|
|
|
|
|
:::caution pass
|
|
|
|
|
|
|
|
The default debug build is not optimized and can elicit stack overflow errors.
|
|
|
|
It is strongly encouraged to use `--release` when possible.
|
|
|
|
|
|
|
|
:::
|