I'm interested in learning Rust. I cheated a little to start off. I used this CodeConvert AI - Convert code with a click of a button online conversion tool to convert JavaScript to Rust.
It's an algorithm from here Permutations without recursive function call.
The online tool spit this out
use std::collections::HashMap;
fn main() {
if !global::has_console() {
global::set_console();
}
for prop in global::get_properties() {
console_log(&prop);
}
// const input = [0,1,2,3,4], lex = 5;
let _ = array_nth_permutation(vec![0, 1, 2, 3, 4], 5);
}
mod global {
use std::collections::HashMap;
pub fn has_console() -> bool {
// Check if console exists in global context
false // Placeholder for actual implementation
}
pub fn set_console() {
// Set up console logging
}
pub fn get_properties() -> Vec<String> {
// Return properties of global context
vec![] // Placeholder for actual implementation
}
}
fn console_log(args: &str) {
println!("{}", args);
}
// https://stackoverflow.com/a/34238979
fn array_nth_permutation(a: Vec<i32>, n: usize) -> i32 {
let mut lex = n;
let mut b: Vec<i32> = a.clone();
let len = a.len();
let mut res: Vec<i32> = Vec::new();
let mut f = (1..=len).product::<usize>();
if n >= 0 && n < f {
let mut n = n;
let mut len = len;
while len > 0 {
f /= len;
let i = (n - n % f) / f;
res.push(b.remove(i));
n %= f;
len -= 1;
}
console_log(&format!("[{}] {:?}", lex, res));
} else {
console_log(&format!("{} >= 0 && {} < {}: {}", n, n, f, n >= 0 && n < f));
}
0
}
I manually edited the code to this
#![feature(str_split_whitespace_remainder)]
use std::io::{self, BufRead};
// https://stackoverflow.com/a/34238979
fn array_nth_permutation(t: usize, n: usize) -> usize {
if t < 2 || n == usize::MAX {
println!("Expected n > 2, m >= 0, got {}, {}", t, n);
return 1;
}
let a: Vec<usize> = (0..t).collect();
let lex = n;
let mut b: Vec<usize> = a.clone(); // copy of the set
let mut len = a.len(); // length of the set
let mut res: Vec<usize> = Vec::new(); // return value, undefined
let mut f = 1;
let mut m = n;
// compute f = factorial(len)
for i in 1..=len {
f *= i;
}
let fac = f;
// if the permutation number is within range
if m < f {
// start with the empty set, loop for len elements
for _ in 0..len {
// determine the next element:
// there are f/len subsets for each possible element,
f /= len;
// a simple division gives the leading element index
let i = (m - m % f) / f; // Math.floor(n / f);
res.push(b.remove(i));
// reduce n for the remaining subset:
// compute the remainder of the above division
m %= f;
len -= 1;
}
println!(
"{} of {} (0-indexed, factorial {}) => {:?}",
lex,
fac - 1,
fac,
res
);
} else {
println!("{} >= 0 && {} < {}: {}", n, n, f, n < f);
}
// return the permutated set or undefined if n is out of range
0
}
fn main() {
let stdin = io::stdin();
let mut iterator = stdin.lock().lines();
let line = iterator.next().unwrap().unwrap();
let mut split = line.split_whitespace();
let a: usize = split
.next()
.unwrap()
.trim()
.parse()
.expect("Input not an integer");
let n: usize = split
.next()
.unwrap()
.trim()
.parse()
.expect("Input not an integer");
array_nth_permutation(a, n);
}
This works up to a point
CARGO_HOME=/media/user/123/rust/.cargo RUSTUP_HOME=/media/user/123/rust/.rustup rustc permutations.rs -o permutations
echo '12 9' | ./permutations
9 of 479001599 (0-indexed, factorial 479001600) => [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 8]
CARGO_HOME=/media/user/123/.cargo RUSTUP_HOME=/media/user/123/rust/.rustup rustc --target wasm32-wasip1 permutations.rs -o permutations-rust.wasm
echo '4 5' | wasmtime permutations-rust.wasm
5 of 23 (0-indexed, factorial 24) => [0, 3, 2, 1]
However, the WASM version of the code code panics when factorial 13!
is input.
echo '13 2' | wasmtime permutations-rust.wasm
thread 'main' panicked at permutations.rs:21:5:
attempt to multiply with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Error: failed to run main module `permutations-rust.wasm`
Caused by:
0: failed to invoke command default
1: error while executing at wasm backtrace:
0: 0xe918 - permutations-rust.wasm!__rust_start_panic
1: 0xe83f - permutations-rust.wasm!rust_panic
2: 0xe812 - permutations-rust.wasm!std::panicking::rust_panic_with_hook::h1ead75d7eace2784
3: 0xdbd4 - permutations-rust.wasm!std::panicking::begin_panic_handler::{{closure}}::he44d57a6b952509a
4: 0xdb0e - permutations-rust.wasm!std::sys::backtrace::__rust_end_short_backtrace::h0b4e9296dec8b10d
5: 0xe1a6 - permutations-rust.wasm!rust_begin_unwind
6: 0x132f5 - permutations-rust.wasm!core::panicking::panic_fmt::h9cf85a86c30a3523
7: 0x1732c - permutations-rust.wasm!core::panicking::panic_const::panic_const_mul_overflow::hf20ebbd79badb656
8: 0x5b4d - permutations-rust.wasm!permutations::array_nth_permutation::h93f1f81f912c4943
9: 0x5fe2 - permutations-rust.wasm!permutations::main::h52e0aee3e982e29f
10: 0x664e - permutations-rust.wasm!core::ops::function::FnOnce::call_once::hb243900555505583
11: 0x6625 - permutations-rust.wasm!std::sys::backtrace::__rust_begin_short_backtrace::h87e777f30e6a49a0
12: 0xd1b - permutations-rust.wasm!std::rt::lang_start::{{closure}}::h3dd0c64a3ec98083
13: 0xb9de - permutations-rust.wasm!std::rt::lang_start_internal::h1b3a8c98b33cbfb4
14: 0xce1 - permutations-rust.wasm!std::rt::lang_start::hce049f2007367618
15: 0x6049 - permutations-rust.wasm!__main_void
16: 0x3e4 - permutations-rust.wasm!_start
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
2: wasm trap: wasm `unreachable` instruction executed
From experimenting with AssemblyScript I think this has to do with usize
usage, instead of i64
.
What changes need to be made to use i64
, and otherwise improve the code so the same output is produced executing the native executable and the Rust source code compiled to WASM with WASI support?