diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 3d758ca6..98a35d99 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -43,6 +43,14 @@ jobs:
with:
node-version: 22
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+
+ - run: |
+ rustup default stable
+ rustup target add wasm32-unknown-unknown
+
- name: Install git, linguist
uses: awalsh128/cache-apt-pkgs-action@latest
with:
diff --git a/docs/Makefile b/docs/Makefile
index b85cde3a..380f6f45 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -40,12 +40,16 @@ _static/dist/bundle.js:
@mkdir -p _static/dist
@cp ../javascript/dist/bundle-js.js _static/dist/bundle-js.js
+_static/dist/rust.js:
+ @cd ../rust && cargo build --target wasm32-unknown-unknown --features "wasm" && \
+ wasm-bindgen target/wasm32-unknown-unknown/release/rust.wasm --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.js $(MFLAGS) -j
@$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
# Catch-all target: route all unknown targets to Sphinx using the new
diff --git a/docs/_static/test-rs.html b/docs/_static/test-rs.html
new file mode 100644
index 00000000..8481e39a
--- /dev/null
+++ b/docs/_static/test-rs.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ JavaScript Tests (Packaged with WebPack + Babel)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 55664d99..be8fd41f 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -9,6 +9,18 @@ itertools = "0.13.0"
num-traits = "0.2.19"
rstest = "0.21.0"
seq-macro = "0.3.5"
+serde = "1.0"
+
+[dependencies.wasm-bindgen]
+version = "0.2"
+optional = true
+
+[lib]
+crate-type = ["cdylib"] # Necessary for WebAssembly builds
+
+[features]
+default = []
+wasm = ["wasm-bindgen"]
[profile.dev.package."*"]
# Set the default for dependencies in Development mode.
diff --git a/rust/src/include/mod.rs b/rust/src/include/mod.rs
index ca12a900..5f05ec37 100644
--- a/rust/src/include/mod.rs
+++ b/rust/src/include/mod.rs
@@ -1,4 +1,5 @@
pub mod math;
pub mod primes;
+pub mod problems;
pub mod triangles;
pub mod utils;
diff --git a/rust/src/include/problems.rs b/rust/src/include/problems.rs
new file mode 100644
index 00000000..d523e467
--- /dev/null
+++ b/rust/src/include/problems.rs
@@ -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> {
+ 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 {
+ let mut supported_problems = Vec::new();
+ for n in 1..10000 {
+ if get_problem(n).is_some() {
+ supported_problems.push(n);
+ }
+ }
+
+ return supported_problems;
+}
\ No newline at end of file
diff --git a/rust/src/include/utils.rs b/rust/src/include/utils.rs
index 67eccacd..f6c5103d 100644
--- a/rust/src/include/utils.rs
+++ b/rust/src/include/utils.rs
@@ -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)]
@@ -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();
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
new file mode 100644
index 00000000..9ee60824
--- /dev/null
+++ b/rust/src/lib.rs
@@ -0,0 +1,49 @@
+#![allow(unused_imports)]
+#[cfg(feature = "wasm")]
+use wasm_bindgen::prelude::*;
+
+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 {
+ return (generate_supported_problems() as Vec).into();
+}
+
+#[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),
+ }
+}
diff --git a/rust/src/main.rs b/rust/src/main.rs
index d3f0a36a..2da8f947 100644
--- a/rust/src/main.rs
+++ b/rust/src/main.rs
@@ -15,59 +15,26 @@ use itertools::Itertools;
pub mod include;
use include::math;
use include::primes;
-use include::utils::{Answer,get_answer};
+#[cfg(not(test))]
+use include::problems::generate_supported_problems;
+use include::problems::get_problem;
+#[cfg(not(test))]
+use include::utils::Answer;
+use include::utils::get_answer;
seq!(N in 0001..=0020 {
-mod p~N;
+pub mod p~N;
});
-mod p0022;
-mod p0024;
-mod p0027;
-mod p0034;
-mod p0069;
-mod p0076;
-mod p0077;
-mod p0087;
-mod p0357;
-mod p0836;
+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;
-type ProblemType = fn() -> Answer;
-type ProblemRef<'a> = (&'a usize, ProblemType, bool);
-
-fn get_problem<'b>(n: usize) -> ProblemRef<'b> {
- return match n {
- 1 => ( &1, p0001::p0001, false),
- 2 => ( &2, p0002::p0002, false),
- 3 => ( &3, p0003::p0003, false),
- 4 => ( &4, p0004::p0004, false),
- 5 => ( &5, p0005::p0005, false),
- 6 => ( &6, p0006::p0006, false),
- 7 => ( &7, p0007::p0007, false),
- 8 => ( &8, p0008::p0008, false),
- 9 => ( &9, p0009::p0009, false),
- 10 => ( &10, p0010::p0010, false),
- 11 => ( &11, p0011::p0011, false),
- 12 => ( &12, p0012::p0012, false),
- 13 => ( &13, p0013::p0013, false),
- 14 => ( &14, p0014::p0014, false),
- 15 => ( &15, p0015::p0015, false),
- 16 => ( &16, p0016::p0016, false),
- 17 => ( &17, p0017::p0017, false),
- 18 => ( &18, p0018::p0018, false),
- 19 => ( &19, p0019::p0019, false),
- 20 => ( &20, p0020::p0020, false),
- 22 => ( &22, p0022::p0022, false),
- 24 => ( &24, p0024::p0024, false),
- 27 => ( &27, p0027::p0027, false),
- 34 => ( &34, p0034::p0034, false),
- 69 => ( &69, p0069::p0069, false),
- 76 => ( &76, p0076::p0076, false),
- 77 => ( &77, p0077::p0077, false),
- 87 => ( &87, p0087::p0087, false),
- 357 => (&357, p0357::p0357, true),
- 836 => (&836, p0836::p0836, false),
- _ => panic!(),
- };
-}
#[cfg(not(test))]
fn main() {
@@ -75,25 +42,20 @@ fn main() {
for i in sieve {
println!("{}", i);
}
- let mut answers: Vec = (1..=20).collect();
- answers.push(22);
- answers.push(24);
- answers.push(27);
- answers.push(34);
- answers.push(69);
- answers.push(76);
- answers.push(77);
- answers.push(87);
- answers.push(357);
+ let supported = generate_supported_problems();
- for id in answers {
- let (_, func, _) = get_problem(id);
- let answer = get_answer(id);
- let result = func();
- match (answer, result) {
- (Answer::String(e), Answer::String(r)) => println!("Problem {} should return {}. Returned {}!", id, e, r),
- (Answer::Int(e), Answer::Int(r)) => println!("Problem {} should return {}. Returned {}!", id, e, r),
- _ => panic!("Type mismatch in answer return"),
+ for id in supported {
+ match get_problem(id) {
+ Some((_, func, _)) => {
+ let answer = get_answer(id);
+ let result = func();
+ match (answer, result) {
+ (Answer::String(e), Answer::String(r)) => println!("Problem {} should return {}. Returned {}!", id, e, r),
+ (Answer::Int(e), Answer::Int(r)) => println!("Problem {} should return {}. Returned {}!", id, e, r),
+ _ => panic!("Type mismatch in answer return"),
+ }
+ }
+ None => panic!("Problem not found"),
}
}
}
@@ -115,7 +77,7 @@ seq!(N in 01..=20 {
// #[case::problem_357(357)]
#[case::problem_836(836)]
fn test_problem(#[case] id: usize) -> Result<(), String> {
- let (_, func, _slow) = get_problem(id);
+ let Some((_, func, _slow)) = get_problem(id) else { panic!() };
let answer = get_answer(id);
let start = Instant::now();
let result = func();
diff --git a/rust/src/p0003.rs b/rust/src/p0003.rs
index e524c376..188b9eb8 100644
--- a/rust/src/p0003.rs
+++ b/rust/src/p0003.rs
@@ -9,7 +9,7 @@ The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
*/
-use crate::primes::prime_factors;
+use crate::include::primes::prime_factors;
use crate::include::utils::Answer;
pub fn p0003() -> Answer {
diff --git a/rust/src/p0007.rs b/rust/src/p0007.rs
index 489e756d..f52e1fe2 100644
--- a/rust/src/p0007.rs
+++ b/rust/src/p0007.rs
@@ -9,7 +9,7 @@ By listing the first six prime numbers: 2, 3, 5, 7, >
What is the 10 001st prime number?
*/
-use crate::primes::primes;
+use crate::include::primes::primes;
use crate::include::utils::Answer;
pub fn p0007() -> Answer {
diff --git a/rust/src/p0010.rs b/rust/src/p0010.rs
index 3a927524..88447c1e 100644
--- a/rust/src/p0010.rs
+++ b/rust/src/p0010.rs
@@ -10,7 +10,7 @@ The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
*/
-use crate::primes::primes;
+use crate::include::primes::primes;
use crate::include::utils::Answer;
pub fn p0010() -> Answer {
diff --git a/rust/src/p0012.rs b/rust/src/p0012.rs
index 29cf7fa1..2f2304b1 100644
--- a/rust/src/p0012.rs
+++ b/rust/src/p0012.rs
@@ -27,7 +27,7 @@ We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred
divisors?
*/
-use crate::primes;
+use crate::include::primes;
use crate::include::utils::Answer;
pub fn p0012() -> Answer {
diff --git a/rust/src/p0015.rs b/rust/src/p0015.rs
index 60c53aec..a286f565 100644
--- a/rust/src/p0015.rs
+++ b/rust/src/p0015.rs
@@ -10,7 +10,7 @@ The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
Find the sum of all the primes below two million.
*/
-use crate::math;
+use crate::include::math;
use crate::include::utils::Answer;
pub fn p0015() -> Answer {
diff --git a/rust/src/p0027.rs b/rust/src/p0027.rs
index 7662242e..ae42eee3 100644
--- a/rust/src/p0027.rs
+++ b/rust/src/p0027.rs
@@ -27,7 +27,7 @@ Find the product of the coefficients, a and b, for the quadratic expression
that produces the maximum number of primes for consecutive values of n,
starting with n=0.
*/
-use crate::primes::{is_prime,primes_until};
+use crate::include::primes::{is_prime,primes_until};
use crate::include::utils::Answer;
pub fn p0027() -> Answer {
diff --git a/rust/src/p0034.rs b/rust/src/p0034.rs
index 679b88b4..e0859247 100644
--- a/rust/src/p0034.rs
+++ b/rust/src/p0034.rs
@@ -14,7 +14,7 @@ their digits.
Note: as 1! = 1 and 2! = 2 are not sums they are not included.
*/
-use crate::math::factorial;
+use crate::include::math::factorial;
use crate::include::utils::Answer;
pub fn p0034() -> Answer {
diff --git a/rust/src/p0069.rs b/rust/src/p0069.rs
index b7299f14..1c951041 100644
--- a/rust/src/p0069.rs
+++ b/rust/src/p0069.rs
@@ -25,7 +25,7 @@ It can be seen that n=6 produces a maximum n/φ(n) for n ≤ 10.
Find the value of n ≤ 1,000,000 for which n/φ(n) is a maximum.
*/
-use crate::primes::primes;
+use crate::include::primes::primes;
use crate::include::utils::Answer;
pub fn p0069() -> Answer {
diff --git a/rust/src/p0077.rs b/rust/src/p0077.rs
index c9ec53ba..4c9f38ad 100644
--- a/rust/src/p0077.rs
+++ b/rust/src/p0077.rs
@@ -17,7 +17,7 @@ What is the first value which can be written as the sum of primes in over five t
*/
use core::iter::zip;
-use crate::primes::primes_until;
+use crate::include::primes::primes_until;
use crate::include::utils::Answer;
diff --git a/rust/src/p0087.rs b/rust/src/p0087.rs
index d9a629f6..6d75f49e 100644
--- a/rust/src/p0087.rs
+++ b/rust/src/p0087.rs
@@ -26,7 +26,7 @@ square, prime cube, and prime fourth power?
*/
use std::collections::HashSet;
-use crate::primes::primes_until;
+use crate::include::primes::primes_until;
use crate::include::utils::Answer;
diff --git a/rust/src/p0357.rs b/rust/src/p0357.rs
index 501f2abb..63193c7f 100644
--- a/rust/src/p0357.rs
+++ b/rust/src/p0357.rs
@@ -13,7 +13,7 @@ such that for every divisor d of n, d+n/d is prime.
*/
use std::collections::HashSet;
-use crate::primes::{is_prime,primes_until,proper_divisors};
+use crate::include::primes::{is_prime,primes_until,proper_divisors};
use crate::include::utils::Answer;
pub fn p0357() -> Answer {