Rust playground - provide command line argument - rust

I am using the Rust Playground to test a piece of code, sample:
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let query = args.get(1).unwrap();
// do something ...
}
Playground link
How do I provide a command-line argument for running a program in Rust Playground? The sample drop-down next to the run button does not have any link or perhaps I am missing it?
Thanks!

You can't, there is an open issue for this feature

As #Stargateur correctly answered, it's currently impossible to provide input for the playground code itself. However, there's a little trick which can work in relatively simple cases: we can execute std::process::Command, which starts bash, which can execute arbitrary code - including cargo.
Here's how it can look like, for example:
// This is your real `fn main`, which would use the input.
// It can contain everything that's usually possible in the playground.
#[cfg(real_main)]
fn main() {
let args: Vec<String> = std::env::args().collect();
println!("Args: {:?}", args);
}
// This is the wrapper-function, directly executed by the playground.
#[cfg(not(real_main))]
fn main() {
// We're shelling out to `bash`, to execute `cargo run` with additional config.
let _ = std::process::Command::new("/bin/bash")
.args(&[
"-c",
concat!(
r##"{
"##,
// In case we have any kind of error, we want to exit loudly.
r##"
set -euo pipefail
"##,
// `cargo rustc` allows one to pass additional compiler flags.
// It's important that this will recompile the current crate only,
// since, if we had to build the whole dependency tree
// (which is quite large), playground will inevitably timeout.
r##"
cargo rustc -q -- --cfg real_main
"##,
// When building in release mode, replace `target/debug`
// with `target/release`.
r##"
./target/debug/playground arg1 arg2 arg3
"##,
// Finally, we rediirect the stderr of the whole script to stdout,
// to show it in the playground output.
r##"
} 2>&1"##
),
])
// On running `Command::status`, output is piped by default,
// so it will be shown as usual.
.status();
}
Playground link

Related

How do I execute a Move script on Aptos using the Rust SDK?

I want to execute this Move script, e.g. at sources/top_up.move:
script {
use std::signer;
use aptos_framework::aptos_account;
use aptos_framework::aptos_coin;
use aptos_framework::coin;
fun main(src: &signer, dest: address, desired_balance: u64) {
let src_addr = signer::address_of(src);
let balance = coin::balance<aptos_coin::AptosCoin>(src_addr);
if (balance < desired_balance) {
aptos_account::transfer(src, dest, desired_balance - balance);
};
}
}
This is calling functions on the aptos_coin.move module, which is deployed on chain. What it does isn't so important for this question, but in short, it checks that the balance of the destination account is less than desired_balance, and if so, tops it up to desired_balance.
I can execute this Move script via the CLI easily like this:
aptos move compile
aptos move run-script --compiled-script-path build/MyModule/bytecode_scripts/main.mv
Or even just this:
aptos move run-script --script-path sources/top_up.move
What I want to know is whether I can do this using the Rust SDK?
First, you need to compile the script, as you did above. Imagine you have a project layout like this:
src/
main.rs
move/
Move.toml
sources/
top_up.mv
You would want to go in to move/ and run aptos move compile, like you said above. From there, you can depend on the compiled script in your code (see below).
With that complete, here is a minimal code example demonstrating how to execute a Move script using the Rust SDK.
Cargo.toml:
[package]
name = "my-example"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1"
aptos-sdk = { git = "https://github.com/aptos-labs/aptos-core", branch = "mainnet" }
src/main.rs:
use aptos_sdk::crypto::ed25519::Ed25519PublicKey;
use aptos_sdk::types::transaction::authenticator::AuthenticationKey;
use aptos_sdk::{
rest_client::Client,
transaction_builder::TransactionFactory,
types::{
account_address::AccountAddress,
chain_id::ChainId,
transaction::{Script, SignedTransaction, TransactionArgument},
LocalAccount,
},
};
static SCRIPT: &[u8] =
include_bytes!("../../move/build/MyModule/bytecode_scripts/main.mv");
fn main() -> anyhow::Result<()> {
// Prior to the follow code we assume you've already acquired the necessary
// information such as chain_id, the private key of the account submitting
// the transaction, arguments for the Move script, etc.
// Build a transaction factory.
let txn_factory = TransactionFactory::new(chain_id);
// Build a local representation of an account.
let account = LocalAccount::new(
AuthenticationKey::ed25519(&Ed25519PublicKey::from(&private_key)).derived_address()
private_key,
0,
);
// Build an API client.
let client = Client::new("https://fullnode.mainnet.aptoslabs.com");
// Create a builder where the payload is the script.
let txn_builder = transaction_factory.script(Script::new(
SCRIPT.to_vec(),
// type args
vec![],
// args
vec![
TransactionArgument::Address(dest_address),
TransactionArgument::U64(desired_balance),
],
)));
// Build the transaction request and sign it.
let signed_txn = account.sign_with_transaction_builder(
txn_builder
);
// Submit the transaction.
client.submit_and_wait_bcs(&signed_transaction).await?;
}

What is the best way to check if an executable exists for `std::process::Command`?

I want to create a std::process::Command and check whether an executable actually exists at that location before actually spawning the Command later. What would be the pragmatic way to do this?
I have this code:
let c = std::process::Command::new("my_exe");
// something here
c.spawn().unwrap();
I want to be able to validate the my_exe path when creating the Command and then spawn way later.
check whether an executable actually exists at that location before actually spawning the Command.
Don't as that's a time-of-check to time-of-use race condition. Instead, check the error value from executing the Command: Check if a command is in PATH/executable as process.
If you want to check if a file is present in the working directory, you can use Path::exists, as described in How to check whether a path exists?.
Also, Command::spawn() takes a mutable reference to self so c needs to be mutable.
use std::path::Path;
use std::process::Command;
if Path::new("PATH_TO_EXECUTABLE").exists() {
let mut c = Command::new("PATH_TO_EXECUTABLE");
// do something
c.spawn().unwrap();
}
Use the is_executable crate:
use is_executable::IsExecutable;
use std::fs;
let paths = fs::read_dir("./").unwrap();
for path in paths {
let file_path = path.unwrap().path();
if file_path.is_executable() {
println!("File: {:?} is executable!", file_path);
} else {
println!("File: {:?} is _not_ executable!", file_path);
}
}

Tests fail when renaming identifiers, etc

I've got a large repo in which I noticed that some tests started failing after I added a dependency to Cargo.toml, despite the dependency never being referenced. I began to investigate, and was able to reproduce the problem consistently in this repo. I'll reproduce the code of the main file here:
mod test {
pub fn b<T>(db: *mut libsqlite3_sys::sqlite3, _: T) {
let rc = unsafe {
libsqlite3_sys::sqlite3_create_function(
db, // db
"x".as_ptr() as _, // zFunction
0, // nArg
0, // eTextRep
std::ptr::null_mut(), // pApp
None, // xFunc
None, // xStep
None, // xFinal
)
};
match rc {
libsqlite3_sys::SQLITE_MISUSE => (),
x => panic!("Wanted SQLITE_MISUSE, got {:?}", x),
}
}
}
#[test]
#[ignore]
fn z() {
format!("{:?}", &[1, 2, 3, 4]);
panic!("not run");
}
#[test]
fn a() {
const FILENAME: &[u8] = b":memory:\0";
let mut db: *mut libsqlite3_sys::sqlite3 = std::ptr::null_mut();
let rc = unsafe { libsqlite3_sys::sqlite3_open(FILENAME.as_ptr() as _, &mut db) };
assert_eq!(rc, libsqlite3_sys::SQLITE_OK);
test::b(db, 0);
}
On my computer, these tests pass, meaning that sqlite3_create_function is returning SQLITE_MISUSE.
$ cargo test --lib --features=static
Finished test [unoptimized + debuginfo] target(s) in 0.52s
Running unittests src/lib.rs (target/debug/deps/sqlite3_ext-5449511dde1f34ef)
running 2 tests
test z ... ignored
test a ... ok
test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.01s
Now, it shouldn't be returning MISUSE, because as far as I can tell everything about this code is valid. However, here's where it gets weird:
If I don't use --features=static, the test fails. Note that nothing references this feature whatsoever.
If I remove the format! line, the test fails. Note that the code is never called.
If I add or remove any dependencies to Cargo.toml, the test fails. None of the changes are referenced anywhere in the code.
If I rename the feature "static" to anything else, the test fails.
If I rename the module "test" to anything else, the test fails.
If I run this code on Linux, the test fails.
I am able to add [features] joke = [] to Cargo.toml, and then I get this behavior:
cargo test --lib --features=joke fails (no MISUSE)
cargo test --lib --features=static passes (MISUSE)
cargo test --lib --features=static,joke fails (no MISUSE)
I am at my wit's end. I am running macOS 10.14.6 (18G9323), rustc 1.61.0 (fe5b13d68 2022-05-18). Any help would be greatly appreciated. I've also uploaded binaries to GitHub for investigation if it helps.
Thanks to #thomcc who responded on the rusqlite Discord:
you’re not passing a nul-terminated string to c for one
This was the issue. In most cases the only problem this caused was that my application-defined function was never removed, but in this particular case it resulted in an SQLITE_MISUSE being returned. Properly converting my &str to CString resolves the issue.

Lazy once_cell causes stack overflow

The code:
use once_cell::sync::Lazy;
fn main() {
const TEST: Lazy<[[u64; 64]; 512]> = Lazy::new(|| unimplemented!());
TEST[0];
}
Results in the output:
thread 'main' has overflowed its stack
error: process didn't exit successfully: `target\debug\chess_ai.exe` (exit code: 0xc00000fd, STATUS_STACK_OVERFLOW)
Weirdly enough only on windows. On Linux (WSL Debian GNU/Linux 9), the output is the expected:
Finished dev [unoptimized + debuginfo] target(s) in 23.38s
Running `target/debug/chess_ai`
thread 'main' panicked at 'not implemented', src/main.rs:4:56
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Am I being a banana, lol? I don't understand at all what's going on here. This is also a pretty hard roadblock for me right now, so I really appreciate responses!
Playground version works as expected.
Versions
once_cell: "1.12.0"
rustc (both windows and Linux): "1.61.0"
So after some testing it seems like the stack is just not big enough to contain my variable, since this, plain, piece of code also results in a stackoverflow:
fn main() {
let test: [[u64; 64]; 3000] = [[0; 64]; 3000];
test[0];
}
Given that the const in the question is not really "generated"/"created" (lazy initialization) at compile time, it happens inside a stack-frame and most likely causes the stackoverflow.
Moving the data to the heap fixes the issue:
use once_cell::sync::Lazy;
fn main() {
static TEST: Lazy<Box<[[u64; 64]; 512]>> = Lazy::new(|| unimplemented!());
TEST[0];
}
Seems like windows and Linux versions have different stack sizes, or the code is optimized differently.

oxipng throwing RuntimeError: unreachable when called

I'm trying to create a small WASM project for image compression.
After some search in github, I noticed that oxipng 2.2.2 has a target for wasm32-unknown-unknown, hence why I'm using that.
I'm using wasm-pack for creating the wasm file + JS bindings with target -t web
This is the code:
extern crate oxipng;
mod utils;
use std::error::Error;
use wasm_bindgen::prelude::*;
use oxipng::*;
#[wasm_bindgen]
extern "C" {
// Use `js_namespace` here to bind `console.log(..)` instead of just
// `log(..)`
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
// Next let's define a macro that's like `println!`, only it works for
// `console.log`. Note that `println!` doesn't actually work on the wasm target
// because the standard library currently just eats all output. To get
// `println!`-like behavior in your app you'll likely want a macro like this.
#[macro_export]
macro_rules! console_log {
// Note that this is using the `log` function imported above during
// `bare_bones`
($($t:tt)*) => (crate::log(&format_args!($($t)*).to_string()))
}
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
pub fn compress(data: &[u8]) -> Vec<u8> {
console_log!("{}", data.len());
let opts = Options::from_preset(6);
console_log!("after options");
let res = match optimize_from_memory(data, &&opts) {
Ok(res) => Ok(res),
Err(err) => Err(err),
};
match &res {
Ok(_) => console_log!("Optimized"),
Err(err) => console_log!("Error: {}", err),
}
return res.unwrap();
}
I don't ever get an error message, the last log I have is "after options".
In a nutshell, I'm using a Flutter web application that gets a PNG file, converts it into a Uint8List, and I send it as an integer List to the JS bindings.
When called, the following error happens:
RuntimeError: unreachable
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[1019]:0x5c6be
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[414]:0x4cd37
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[619]:0x54c96
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[915]:0x5b4ba
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[986]:0x5c139
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[645]:0x55885
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[569]:0x5324b
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[594]:0x53ff1
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[2]:0x554f
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[84]:0x2cbf2
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[73]:0x2a501
at http://localhost:3000/pkg/rust_png_module_bg.wasm:wasm-function[563]:0x52eaa
at compress (http://localhost:3000/pkg/rust_png_module.js:49:14)
at compressImage (http://localhost:3000/packages/rust_wasm/ui/screens/home/home_page.dart.lib.js:568:72)
at compressImage.next (<anonymous>)
at http://localhost:3000/dart_sdk.js:38640:33
at _RootZone.runUnary (http://localhost:3000/dart_sdk.js:38511:59)
at _FutureListener.thenAwait.handleValue (http://localhost:3000/dart_sdk.js:33713:29)
at handleValueCallback (http://localhost:3000/dart_sdk.js:34265:49)
at Function._propagateToListeners (http://localhost:3000/dart_sdk.js:34303:17)
at _Future.new.[_completeWithValue] (http://localhost:3000/dart_sdk.js:34151:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:3000/dart_sdk.js:34172:35)
at Object._microtaskLoop (http://localhost:3000/dart_sdk.js:38778:13)
at _startMicrotaskLoop (http://localhost:3000/dart_sdk.js:38784:13)
at http://localhost:3000/dart_sdk.js:34519:9
Since this version is old, I don't know if I should revert back to an older version of Rust
$ rustup --version
rustup 1.24.3 (ce5817a94 2021-05-31)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.55.0 (c8dfcfe04 2021-09-06)`
Thank you in advance
The problem is you're using a very old version of oxipng (v2.2.2) that didn't support wasm yet. I believe wasm support was added in v2.3.0 (link to issue that was fixed). Anyways, you should be able to use the latest version just fine with wasm, just make sure you disable the default features when adding the crate to your Cargo.toml:
[dependencies]
oxipng = { version = "5", default-features = false }

Resources