10 Prompts for Rust: System Programming, CLI, and WebAssembly

Introduction

Rust has solidified its position as one of the most reliable languages for systems programming, command-line tools, and WebAssembly. Its ownership model, zero-cost abstractions, and strong type system make it a top choice for performance-critical applications. However, writing efficient and safe Rust code requires more than just understanding the syntax — it demands a systematic approach to common tasks like memory management, error handling, concurrency, and interop with C or JavaScript.

This article provides 10 specific, copy-paste-ready prompts that you can use with AI assistants (like ChatGPT, Claude, or Gemini) to accelerate your Rust development workflow. Each prompt is designed for a particular task — from writing a safe API wrapper to generating a CLI with clap, or compiling Rust to WebAssembly. You'll also find a usage example for each prompt, so you can immediately see how it works in practice.

Whether you are building a low-level system utility, a high-performance CLI, or a WASM module for the browser, these prompts will save you hours of boilerplate and debugging. Let's dive in.


1. Writing a Safe API Wrapper for a C Library

Task: Generate a Rust crate that wraps a C library using FFI (Foreign Function Interface) while ensuring memory safety and proper error handling.

Prompt:

You are an expert Rust systems programmer. Write a safe Rust wrapper for the following C library:
- Library name: example_lib
- Header file: example_lib.h (attached)
- Key functions: example_init(), example_do_work(input: *const c_char) -> i32, example_cleanup()
- Requirements:
  - Use `libc` and `std::ffi::CString`/`CStr` for string handling.
  - Wrap unsafe FFI calls in safe functions with `unsafe` blocks.
  - Return `Result<T, Error>` where Error is a custom enum with variants for null pointers, invalid input, and library errors.
  - Implement `Drop` for any struct that owns resources (e.g., a handle).
  - Provide documentation comments on all public items.
- Output only the Rust code (no explanations).

Usage Example:
After running the prompt with the actual header content, you get a complete lib.rs file with safe functions like:
- ExampleContext::new() -> Result<Self, Error>
- ctx.do_work(input: &str) -> Result<i32, Error>
- Automatic cleanup via Drop.


2. Building a CLI with clap (Derive Macros)

Task: Generate a command-line interface using the clap crate with derive macros, including subcommands, optional flags, and positional arguments.

Prompt:

You are a Rust CLI expert. Generate a complete CLI application using clap v4 with derive macros. The CLI should:
- Have a main binary named `myapp`.
- Support three subcommands: `run`, `config`, `version`.
- `run` takes a required positional argument `input_file: PathBuf` and an optional flag `--verbose`.
- `config` takes a subcommand `set` (with `--key` and `--value`) and `show`.
- `version` prints the crate version from Cargo.toml.
- Use `anyhow` for error handling.
- Include a main function that matches subcommands and calls separate handler functions.
- Output only the Rust code in a single file `main.rs`.

Usage Example:
The generated code lets you run:

cargo run -- run input.txt --verbose
cargo run -- config set --key timeout --value 30
cargo run -- version

3. Parsing a Custom Binary Format

Task: Write a parser for a binary file format using nom or byteorder with minimal allocations.

Prompt:

You are a Rust systems programmer specializing in binary parsing. Write a parser for a custom binary format:
- Format: 4-byte magic (0xDEADBEEF), 4-byte version (u32), 2-byte header size, then payload (variable length).
- Payload contains: 8-byte timestamp (i64), 4-byte count (u32), then `count` records each with 4-byte id (u32) and 4-byte value (f32).
- Use `nom` 7.x for parsing. Define structs `Header`, `Record`, and `Payload`.
- Implement `From<&[u8]>` for `Header` and `Payload` that returns `Result<Self, nom::Err<nom::error::Error<&[u8]>>>`.
- Add unit tests with sample binary data.
- Output only the Rust code.

Usage Example:

let data: &[u8] = &[0xDE, 0xAD, 0xBE, 0xEF, /* ... */];
let payload = Payload::from(data)?;
println!("Records: {:?}", payload.records);

4. Generating a Thread-Safe Singleton

Task: Create a global configuration struct that can be accessed from multiple threads without locks (using OnceLock).

Prompt:

You are a Rust concurrency expert. Write a thread-safe singleton configuration using `std::sync::OnceLock` (stable since Rust 1.70). The config should:
- Be defined as a struct `AppConfig` with fields: `db_url: String`, `max_connections: u32`, `log_level: String`.
- Implement `From<&str>` that parses JSON input.
- Provide a public `init(config_json: &str) -> Result<(), String>` function that sets the global config once.
- Provide a public `get_config() -> &'static AppConfig` that panics if not initialized.
- Use `serde_json` for deserialization.
- Output only the Rust code.

Usage Example:

AppConfig::init(r#"{"db_url":"postgres://...", "max_connections":10, "log_level":"info"}"#).unwrap();
let config = AppConfig::get_config();
println!("DB URL: {}", config.db_url);

5. Compiling Rust to WebAssembly (WASM) with wasm-pack

Task: Generate a minimal Rust library that compiles to WASM and can be called from JavaScript.

Prompt:

You are a Rust WebAssembly expert. Write a Rust library that:
- Uses `wasm-bindgen` and `js-sys`.
- Exports a function `add(a: i32, b: i32) -> i32`.
- Exports a function `fibonacci(n: u32) -> u32` that computes the nth Fibonacci number iteratively.
- Exports a function `greet(name: &str) -> String` that returns a greeting.
- The crate type must be `cdylib`.
- Include a `Cargo.toml` with correct dependencies.
- Output only the Rust code and Cargo.toml in separate code blocks.

Usage Example:
After running wasm-pack build --target web, you can call from JavaScript:

import init, { add, fibonacci, greet } from './pkg/mywasm.js';
await init();
console.log(add(2, 3)); // 5
console.log(greet("Alice")); // "Hello, Alice!"

6. Creating an Async HTTP Client with reqwest

Task: Generate an async HTTP client that fetches JSON from an API and deserializes it into a struct.

Prompt:

You are a Rust async programming expert. Write an async HTTP client using `reqwest` and `tokio` that:
- Defines a struct `ApiResponse` with fields `id: u32`, `name: String`, `email: String` (all fields are optional).
- Has a function `fetch_user(user_id: u32) -> Result<ApiResponse, reqwest::Error>` that sends a GET request to `https://jsonplaceholder.typicode.com/users/{user_id}`.
- Uses `#[tokio::main]` for the main function.
- Handles network errors gracefully (e.g., timeout, connection refused).
- Prints the result.
- Output only the Rust code.

Usage Example:

let user = fetch_user(1).await?;
println!("User name: {:?}", user.name);

7. Writing a Zero-Copy Parser with &str

Task: Parse a CSV line without allocating new strings, using only slices of the original input.

Prompt:

You are a Rust performance expert. Write a zero-copy CSV line parser that:
- Takes a `&str` line (comma-separated, no quoting).
- Returns `Vec<&str>` of fields.
- Uses `split` and avoids `String` allocations.
- Handles empty fields (two consecutive commas) correctly.
- Includes a test case with sample CSV line.
- Output only the Rust code.

Usage Example:

let fields = parse_csv_line("a,b,,c");
assert_eq!(fields, vec!["a", "b", "", "c"]);

8. Generating a Procedural Macro (derive macro)

Task: Write a custom derive macro that automatically implements a trait (e.g., ToJson) for a struct.

Prompt:

You are a Rust macro expert. Write a procedural derive macro called `ToJson` that:
- Is defined in a separate crate `my_macros`.
- The macro generates an implementation of a trait `ToJson` with method `fn to_json(&self) -> String`.
- The generated code uses `serde_json::to_string` on the struct.
- The struct must implement `serde::Serialize` (use `#[derive(Serialize)]` in the generated code).
- Include `Cargo.toml` for both the macro crate and a test crate.
- Output only the Rust code and Cargo.toml files.

Usage Example:

use my_macros::ToJson;

#[derive(ToJson)]
struct Person {
    name: String,
    age: u8,
}

let p = Person { name: "Alice".into(), age: 30 };
println!("{}", p.to_json());

9. Implementing a Custom Iterator

Task: Create an iterator over a tree data structure (e.g., binary tree) that traverses in-order without recursion.

Prompt:

You are a Rust data structures expert. Write a binary tree with an in-order iterator that:
- Defines `enum Tree<T>` with variants `Empty` and `Node(Box<Node<T>>)`.
- `Node` contains `value: T`, `left: Tree<T>`, `right: Tree<T>`.
- Implements `IntoIterator` for `Tree<T>` that returns an in-order iterator.
- The iterator uses an explicit stack (Vec) to avoid recursion.
- The iterator yields `&T` references.
- Include a test that builds a small tree and checks the traversal order.
- Output only the Rust code.

Usage Example:

let tree: Tree<i32> = /* build tree */;
for val in &tree {
    println!("{}", val);
}

10. Creating a Simple Actor System with tokio

Task: Build a lightweight actor pattern using tokio::mpsc channels for message passing.

Prompt:

You are a Rust concurrent systems expert. Write an actor system where:
- An `Actor` struct holds a receiver (tokio::mpsc::UnboundedReceiver<Message>) and internal state (e.g., a counter).
- `Message` is an enum with variants: `Increment(u32)`, `GetValue(tokio::sync::oneshot::Sender<u32>)`, `Stop`.
- The actor runs in a tokio task spawned with `tokio::spawn`.
- Provide a `ActorHandle` struct that holds a sender (UnboundedSender<Message>) and methods `increment`, `get_value`, `stop`.
- `get_value` returns `impl Future<Output = u32>` using oneshot channel.
- Include a main function that spawns the actor, sends messages, and prints the final value.
- Output only the Rust code.

Usage Example:

let handle = ActorHandle::new();
handle.increment(5).await;
let val = handle.get_value().await; // 5
handle.stop().await;

Conclusion

These 10 prompts cover the most common Rust development scenarios — from safe FFI and CLI building to WebAssembly and concurrent actors. By using them as templates, you can dramatically reduce the time spent on boilerplate and focus on the unique logic of your project.

Remember that AI-generated code should always be reviewed for correctness, especially in systems programming where memory safety is critical. Use these prompts as a starting point, adapt them to your specific needs, and always run cargo clippy and cargo test before shipping.

For those looking to integrate Rust with external services like databases or cloud APIs, ASI Biont supports connecting to various data sources through its integration platform — learn more at asibiont.com/courses.

Happy coding in Rust!

← All posts

Comments