Skip to content

Commit

Permalink
Attempt to package rust for the browser
Browse files Browse the repository at this point in the history
Note that this was done in an environment where I cannot test
So a failure is not that unexpected
  • Loading branch information
LivInTheLookingGlass committed Aug 14, 2024
1 parent 53e36c3 commit bf8eba7
Show file tree
Hide file tree
Showing 20 changed files with 287 additions and 82 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ jobs:
with:
node-version: 22

- uses: actions-rs/toolchain@v1
with:
toolchain: stable

- run: |
rustup default stable
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
- name: Install git, linguist
uses: awalsh128/cache-apt-pkgs-action@latest
with:
Expand Down
5 changes: 4 additions & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ _static/dist/bundle.js:
@mkdir -p _static/dist
@cp ../javascript/dist/bundle-js.js _static/dist/bundle-js.js

_static/dist/rust_bg.js:
@cd ../rust && build --target web --out-dir ../docs/dist/

_static/dist/python.tar.gz:
@$(MAKE) -C ../python webpack $(MFLAGS)

.PHONY: html
html:
@$(MAKE) _static/dist/bundle.js _static/dist/python.tar.gz $(MFLAGS) -j
@$(MAKE) _static/dist/bundle.js _static/dist/python.tar.gz _static/dist/rust_bg.js $(MFLAGS) -j
@$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

# Catch-all target: route all unknown targets to Sphinx using the new
Expand Down
73 changes: 73 additions & 0 deletions docs/_static/test-rs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!-- test/support/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript Tests (Packaged with WebPack + Babel)</title>

<link href="https://npmcdn.com/[email protected]/mocha.css" rel="stylesheet" />
<script src="https://npmcdn.com/[email protected]/mocha.js"></script>
</head>
<body>

<!-- A container element for the visual Mocha results -->
<div id="mocha"></div>

<!-- Mocha setup and initiation code -->
<script>
mocha.setup('bdd');
window.onload = function() {
var runner = mocha.run();
var failedTests = [];

runner.on('end', function() {
window.mochaResults = runner.stats;
window.mochaResults.reports = failedTests;
});

runner.on('fail', logFailure);

function logFailure(test, err){
var flattenTitles = function(test){
var titles = [];
while (test.parent.title){
titles.push(test.parent.title);
test = test.parent;
}
return titles.reverse();
};

failedTests.push({
name: test.title,
result: false,
message: err.message,
stack: err.stack,
titles: flattenTitles(test)
});
};
};
</script>
<script type="module">
import init, { get_problems, run_problem, get_js_answer } from './dist/rust_bg.js';
async function runTests() {
await init();
for (const p of get_problems()) {
const expected = await get_js_answer(p);
describe(`run test ${p}`, function() {
this.timeout(Infinity);
it(`should return ${expected}`, async () => {
const answer = await run_problem(p);
console.log(p, answer, expected);
if (answer !== expected) {
throw new Error();
}
});
});
}
}

runTests();
</script>

</body>
</html>
9 changes: 9 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ itertools = "0.13.0"
num-traits = "0.2.19"
rstest = "0.21.0"
seq-macro = "0.3.5"
js-sys = { version = "0.3", optional = true }
wasm-bindgen = { version = "0.2", optional = true }

[lib]
crate-type = ["cdylib"] # Necessary for WebAssembly builds

[features]
default = []
wasm = ["wasm-bindgen", "js-sys"]

[profile.dev.package."*"]
# Set the default for dependencies in Development mode.
Expand Down
1 change: 1 addition & 0 deletions rust/src/include/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod math;
pub mod primes;
pub mod problems;
pub mod triangles;
pub mod utils;
67 changes: 67 additions & 0 deletions rust/src/include/problems.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use seq_macro::seq;

use crate::include::utils::Answer;
seq!(N in 0001..=0020 {
use crate::p~N::p~N;
});
use crate::p0022::p0022;
use crate::p0024::p0024;
use crate::p0027::p0027;
use crate::p0034::p0034;
use crate::p0069::p0069;
use crate::p0076::p0076;
use crate::p0077::p0077;
use crate::p0087::p0087;
use crate::p0357::p0357;
use crate::p0836::p0836;

type ProblemType = fn() -> Answer;
type ProblemRef<'a> = (&'a usize, ProblemType, bool);

pub fn get_problem<'b>(n: usize) -> Option<ProblemRef<'b>> {
return match n {
1 => Some(( &1, p0001, false)),
2 => Some(( &2, p0002, false)),
3 => Some(( &3, p0003, false)),
4 => Some(( &4, p0004, false)),
5 => Some(( &5, p0005, false)),
6 => Some(( &6, p0006, false)),
7 => Some(( &7, p0007, false)),
8 => Some(( &8, p0008, false)),
9 => Some(( &9, p0009, false)),
10 => Some(( &10, p0010, false)),
11 => Some(( &11, p0011, false)),
12 => Some(( &12, p0012, false)),
13 => Some(( &13, p0013, false)),
14 => Some(( &14, p0014, false)),
15 => Some(( &15, p0015, false)),
16 => Some(( &16, p0016, false)),
17 => Some(( &17, p0017, false)),
18 => Some(( &18, p0018, false)),
19 => Some(( &19, p0019, false)),
20 => Some(( &20, p0020, false)),
22 => Some(( &22, p0022, false)),
24 => Some(( &24, p0024, false)),
27 => Some(( &27, p0027, false)),
34 => Some(( &34, p0034, false)),
69 => Some(( &69, p0069, false)),
76 => Some(( &76, p0076, false)),
77 => Some(( &77, p0077, false)),
87 => Some(( &87, p0087, false)),
357 => Some((&357, p0357, true)),
836 => Some((&836, p0836, false)),
_ => None,
};
}


pub fn generate_supported_problems() -> Vec<usize> {
let mut supported_problems = Vec::new();
for n in 1..10000 {
if get_problem(n).is_some() {
supported_problems.push(n);
}
}

return supported_problems;
}
23 changes: 23 additions & 0 deletions rust/src/include/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[cfg(not(feature = "wasm"))]
use std::fs::read_to_string;
#[cfg(not(feature = "wasm"))]
use std::path::Path;

#[derive(Debug, PartialEq, Eq)]
Expand All @@ -7,6 +9,27 @@ pub enum Answer {
Int(i128),
}

#[cfg(feature = "wasm")]
const ANSWERS_TSV: &str = include_str!("../../../_data/answers.tsv");
#[cfg(feature = "wasm")]
const P0022_NAMES_TXT: &str = include_str!("../../../_data/p0022_names.txt");
#[cfg(feature = "wasm")]
const P0042_WORDS_TXT: &str = include_str!("../../../_data/p0042_words.txt");
#[cfg(feature = "wasm")]
const P0067_TRIANGLE_TXT: &str = include_str!("../../../_data/p0067_triangle.txt");

#[cfg(feature = "wasm")]
pub fn get_data_file(name: &str) -> String {
return match name {
"answers.tsv" => ANSWERS_TSV.to_string(),
"p0022_names.txt" => P0022_NAMES_TXT.to_string(),
"p0042_words.txt" => P0042_WORDS_TXT.to_string(),
"p0067_triangle.txt" => P0067_TRIANGLE_TXT.to_string(),
_ => panic!("Unknown file name: {}", name),
}
}

#[cfg(not(feature = "wasm"))]
pub fn get_data_file(name: &str) -> String {
let data_file = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().join("_data").join(name);
return read_to_string(&data_file).unwrap();
Expand Down
59 changes: 59 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#![allow(unused_imports)]
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

#[cfg(feature = "wasm")]
use js_sys::Array;

use seq_macro::seq;
seq!(N in 0001..=0020 {
pub mod p~N;
});
pub mod p0022;
pub mod p0024;
pub mod p0027;
pub mod p0034;
pub mod p0069;
pub mod p0076;
pub mod p0077;
pub mod p0087;
pub mod p0357;
pub mod p0836;

pub mod include;
pub use crate::include::problems::{generate_supported_problems,get_problem};
pub use crate::include::utils::{Answer,get_answer};

#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn run_problem(n: usize) -> JsValue {
let Some((_, problem_function, _)) = get_problem(n) else { panic!() };
let answer = problem_function();
return match answer {
Answer::String(e) => JsValue::from_str(&e),
Answer::Int(e) => JsValue::from(e),
}
}

#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn get_problems() -> JsValue {
let problems = generate_supported_problems();
let js_array = Array::new_with_length(problems.len() as u32);

for (i, &item) in problems.iter().enumerate() {
js_array.set(i as u32, item.into());
}

return JsValue::from(js_array);
}

#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn get_js_answer(n: usize) -> JsValue {
let answer = get_answer(n);
return match answer {
Answer::String(e) => JsValue::from_str(&e),
Answer::Int(e) => JsValue::from(e),
}
}
Loading

0 comments on commit bf8eba7

Please sign in to comment.