Duktape Rust demo

This commit is contained in:
SheetJS 2025-03-31 00:42:42 -04:00
parent 19b9f5b122
commit 7ceb6c5143
5 changed files with 165 additions and 6 deletions

@ -244,7 +244,7 @@
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Bindings">
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="17" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="20" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
<Column ss:Index="3" ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
@ -297,6 +297,16 @@
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#rust"><Data ss:Type="String">Duktape</Data></Cell>
<Cell><Data ss:Type="String">Rust</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#zig"><Data ss:Type="String">Duktape</Data></Cell>
<Cell><Data ss:Type="String">Zig</Data></Cell>

@ -24,7 +24,7 @@ This demo was tested in the following deployments:
| Browser | Version | Date |
|:-------------|:--------|:-----------|
| Chromium 125 | `6.2.1` | 2024-06-13 |
| Chromium 133 | `6.3.1` | 2025-03-31 |
:::
@ -45,7 +45,7 @@ installation instructions for projects using a framework.
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
<!-- Tabulator must be loaded after SheetJS scripts -->
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.3.1/dist/js/tabulator.min.js"></script>
```
:::
@ -139,7 +139,7 @@ function export_xlsx() {
</script>
```
[The official documentation](https://tabulator.info/docs/6.2/download#xlsx)
[The official documentation](https://tabulator.info/docs/6.3/download#xlsx)
covers supported options.
#### Post-processing

@ -1093,5 +1093,99 @@ sudo cpan install File::Slurp
:::
### Rust
[`ducc`](https://crates.io/crates/ducc) is a Rust binding to the Duktape engine.
It provides a number of convenience methods for exchanging data with the engine.
:::note pass
When this demo was last tested, there were issues passing `Uint8Array` objects
back to Rust. Instead, this demo generates a Base64-encoded string, passes the
string back to Rust, and decodes using the `base64` crate.
:::
#### Rust Demo
:::note Tested Deployments
This demo was tested in the following deployments:
| Architecture | Version | Date |
|:-------------|:--------|:-----------|
| `darwin-arm` | `2.2.1` | 2025-03-31 |
:::
1) Create a new project:
```bash
cargo new sheetjs-duk-rs
cd sheetjs-duk-rs
cargo run
```
2) Download the SheetJS Standalone script and shim to the `src` folder:
<ul>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
</ul>
<CodeBlock language="bash">{`\
curl -L -o src/shim.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js
curl -L -o src/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
</CodeBlock>
3) Download the test file. Move the file to the project directory:
<ul>
<li><a href="https://docs.sheetjs.com/pres.numbers">pres.numbers</a></li>
</ul>
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
</TabItem>
<TabItem value="win" label="Windows">
:::caution pass
If the `curl` command fails, run the commands within WSL `bash`.
:::
</TabItem>
</Tabs>
<CodeBlock language="bash">{`\
curl -LO https://docs.sheetjs.com/pres.numbers`}
</CodeBlock>
4) Download [`main.rs`](pathname:///duk/main.rs) and replace `src/main.rs`:
```bash
curl -L -o src/main.rs https://docs.sheetjs.com/duk/main.rs
```
5) Install dependencies:
```bash
cargo add ducc base64
```
6) Build and run the app:
```bash
cargo run pres.numbers
```
If the program succeeded, the CSV contents will be printed to console and the
file `sheetjsw.xlsb` will be created. That file can be opened with a spreadsheet
editor that supports XLSB spreadsheets.
[^1]: See [Foreign Function Interface](https://www.php.net/manual/en/book.ffi.php) in the PHP documentation.
[^2]: See [`ctypes`](https://docs.python.org/3/library/ctypes.html) in the Python documentation.

55
docz/static/duk/main.rs Normal file

@ -0,0 +1,55 @@
fn doit(ctx: &ducc::Ducc, code: &str) { ctx.compile(code, None).unwrap().call::<(), ()>(()).unwrap(); }
fn get_string(str: ducc::Value) -> String { str.as_string().unwrap().to_string().unwrap() }
fn main() {
let ctx = ducc::Ducc::new();
/* initialize */
doit(&ctx, "var global = (function(){ return this; }).call(null);");
/* load library */
{
doit(&ctx, include_str!("shim.min.js"));
doit(&ctx, include_str!("xlsx.full.min.js"));
}
/* get version string */
{
let vers: ducc::Value = ctx.compile("XLSX.version", None).unwrap().call(()).unwrap();
println!("SheetJS library version {}", get_string(vers));
}
/* read file */
{
let mut iter = std::env::args();
let path: String = iter.nth(1).expect("must specify a file name");
let file: Vec<u8> = std::fs::read(path.clone()).unwrap();
/* push data to duktape (creates a Uint8Array) */
let bytes = ctx.create_bytes(file.as_slice()).unwrap();
/* assign to global `buf` */
let _ = ctx.globals().set("buf", bytes);
}
/* parse workbook */
{
doit(&ctx, "wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});");
doit(&ctx, "ws = wb.Sheets[wb.SheetNames[0]]");
}
/* print CSV */
{
let csv: ducc::Value = ctx.compile("XLSX.utils.sheet_to_csv(ws)", None).unwrap().call(()).unwrap();
println!("{}", get_string(csv));
}
/* write file */
{
/* due to issues with the duktape crate, it is easier to pass a base64-encoded string and decode in Rust */
let xlsb: ducc::Value = ctx.compile("XLSX.write(wb, {type:'base64', bookType:'xlsb'})", None).unwrap().call(()).unwrap();
let _ = std::fs::write("sheetjsw.xlsb", base64::Engine::decode(&base64::engine::general_purpose::STANDARD, get_string(xlsb)).unwrap());
}
}

@ -19,7 +19,7 @@
a { text-decoration: none }
</style>
<!-- tabulator stylesheet -->
<link href="https://unpkg.com/tabulator-tables@6.2.1/dist/css/tabulator.min.css" rel="stylesheet">
<link href="https://unpkg.com/tabulator-tables@6.3.1/dist/css/tabulator.min.css" rel="stylesheet">
</head>
<body>
<pre>
@ -32,7 +32,7 @@ a { text-decoration: none }
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
<!-- Tabulator must be loaded after SheetJS scripts -->
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.3.1/dist/js/tabulator.min.js"></script>
<script>
/*jshint browser:true */
/* eslint-env browser */