← Dolaima← Docs indexRust原文中文

Rust

Usable, but do not expect the full standard library.

How to run it on your phone

vml run examples/rust/test/sysinfo.rs

Compiling takes a while (one to two minutes for C, a few seconds for scripting languages). Once the program is running, the gamepad is at the bottom of the screen - the D-pad and the four action buttons are all there. Tap the back arrow in the top-right corner to return to the Shell.

What to know before you write

Examples

FileWhat it shows
app/breakout.rsBreakout (iterating a 24-brick array plus rectangle collision)
test/sysinfo.rsDevice information

Also in this folder: app/minesweeper.rs, app/snake.rs, demo/demo_std.rs, test/libs.rs, tty/demo_tty.rs, ui/demo_ui.rs

Pitfalls we hit on real devices


The rest of this page is taken straight from the VML source (third_party/vml/VMLPrepares/RustCompiler/): the README covers what this front end supports and how to compile it, and the language reference covers the syntax itself. When upstream changes, regenerating this page brings it up to date.

Language reference

Rust language compiler specification

Version: v1.0 | Date: 2026-07-06 | Revised by: Shenzhen Tanso Intelligent Technology Co., Ltd.

Specification standard

FieldValue
Target standardRust 2018 subset (1.31+)
Release year2018
Completeness~93%
MCU completeness~90%
Tests0 (the test directory is yet to be created)
Updates2026-05-18: corrected the target standard version (to include 2018+ features such as async/await/dyn), the completeness and the test counts

Keywords

as break const continue crate else enum extern false fn for if impl in let loop match mod move mut pub ref return self Self static struct super trait true type unsafe use where while async await dyn

Overview

This compiler compiles a subset of the Rust language into VML (Virtual Machine Language) assembly. Rust is a systems programming language that emphasizes memory safety, concurrency and zero-cost abstractions.

Language features

1. Basic Rust syntax
Variable declaration
let x = 10;              // immutable variable
let mut y = 20;          // mutable variable
const MAX_SIZE: i32 = 100; // constant
static COUNTER: i32 = 0;   // static variable
Type annotations
let x: i32 = 10;
let y: f64 = 3.14;
let name: &str = "Rust";
let flag: bool = true;
2. Data types
Literals
Scalar types
Compound types
3. Control flow
Conditionals
let number = 7;

if number < 5 {
    println!("less than 5");
} else if number < 10 {
    println!("less than 10");
} else {
    println!("10 or greater");
}

// if expression
let result = if number > 0 { "positive" } else { "non-positive" };
Loops
// loop (an infinite loop)
let mut count = 0;
loop {
    count += 1;
    if count == 10 {
        break;
    }
}

// while loop
let mut number = 3;
while number != 0 {
    println!("{}!", number);
    number -= 1;
}

// for loop
for i in 1..=5 {
    println!("{}", i);
}

let arr = [10, 20, 30, 40];
for element in arr.iter() {
    println!("{}", element);
}
match expressions
let value = 42;

match value {
    1 => println!("one"),
    2 | 3 => println!("two or three"),
    4..=10 => println!("four through ten"),
    _ => println!("something else"),
}

// pattern matching
let pair = (0, -2);
match pair {
    (0, y) => println!("x is 0, y = {}", y),
    (x, 0) => println!("x = {}, y is 0", x),
    _ => println!("neither is 0"),
}
4. Functions
Function definition
fn add(x: i32, y: i32) -> i32 {
    x + y  // implicit return (no semicolon)
}

// explicit return
fn subtract(x: i32, y: i32) -> i32 {
    return x - y;
}

// function with no return value
fn print_hello() {
    println!("Hello!");
}
Function parameters
// value parameter
fn by_value(mut x: i32) {
    x += 1;
    println!("Inside: {}", x);
}

// reference parameter
fn by_reference(x: &mut i32) {
    *x += 1;
    println!("Inside: {}", x);
}

// slice parameter
fn print_slice(slice: &[i32]) {
    for &item in slice {
        print!("{} ", item);
    }
    println!();
}
5. The ownership system
Ownership rules
let s1 = String::from("hello");
let s2 = s1;  // s1's ownership moves to s2
// println!("{}", s1);  // error! s1 is no longer valid

// clone (a deep copy)
let s3 = s2.clone();
println!("s2 = {}, s3 = {}", s2, s3);

// references (borrowing)
let len = calculate_length(&s3);
println!("Length of '{}' is {}", s3, len);
Reference rules
fn calculate_length(s: &String) -> usize {
    s.len()
}

// mutable reference
fn change(s: &mut String) {
    s.push_str(", world");
}

let mut s = String::from("hello");
change(&mut s);
println!("{}", s);  // "hello, world"
6. Structs and enums
Structs
struct Point {
    x: i32,
    y: i32,
}

impl Point {
    // associated function (a static method)
    fn new(x: i32, y: i32) -> Point {
        Point { x, y }
    }
    
    // method
    fn distance_from_origin(&self) -> f64 {
        ((self.x * self.x + self.y * self.y) as f64).sqrt()
    }
}

let p = Point::new(3, 4);
println!("Distance: {}", p.distance_from_origin());
Enums
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));

// the Option enum
fn divide(numerator: f64, denominator: f64) -> Option<f64> {
    if denominator == 0.0 {
        None
    } else {
        Some(numerator / denominator)
    }
}

match divide(10.0, 2.0) {
    Some(result) => println!("Result: {}", result),
    None => println!("Cannot divide by zero"),
}
7. Error handling
The Result type
use std::fs::File;
use std::io::Error;

fn read_file(path: &str) -> Result<String, Error> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

// handling a Result
match read_file("data.txt") {
    Ok(contents) => println!("File contents: {}", contents),
    Err(e) => println!("Error reading file: {}", e),
}

// unwrap and expect
let contents = read_file("data.txt").unwrap();  // panics on error
let contents = read_file("data.txt").expect("Failed to read file");
panic and recovery
fn risky_operation(x: i32) -> i32 {
    if x < 0 {
        panic!("Negative value not allowed");
    }
    x * 2
}

// catch_unwind (an unstable API)
let result = std::panic::catch_unwind(|| {
    risky_operation(-5)
});
8. Module system
Module definition
// src/lib.rs or a module file
pub mod math {
    pub fn add(x: i32, y: i32) -> i32 {
        x + y
    }
    
    pub fn subtract(x: i32, y: i32) -> i32 {
        x - y
    }
    
    // private function
    fn internal_helper() {
        // ...
    }
}
Using modules
// using an absolute path
use crate::math::add;

// using a relative path
use self::math::subtract;

// renaming
use std::fmt::Result as FmtResult;

fn main() {
    let sum = add(10, 5);
    let diff = subtract(10, 5);
    println!("Sum: {}, Difference: {}", sum, diff);
}
9. Traits
Trait definition
trait Shape {
    fn area(&self) -> f64;
    fn perimeter(&self) -> f64;
    
    // default implementation
    fn description(&self) -> String {
        String::from("A shape")
    }
}
Trait implementation
struct Circle {
    radius: f64,
}

impl Shape for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
    
    fn perimeter(&self) -> f64 {
        2.0 * std::f64::consts::PI * self.radius
    }
    
    fn description(&self) -> String {
        format!("A circle with radius {}", self.radius)
    }
}

struct Rectangle {
    width: f64,
    height: f64,
}

impl Shape for Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
    
    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }
}
Trait bounds
fn print_area<T: Shape>(shape: &T) {
    println!("Area: {}", shape.area());
}

// using a where clause
fn compare_shapes<T, U>(shape1: &T, shape2: &U) 
where
    T: Shape,
    U: Shape,
{
    println!("Shape1 area: {}", shape1.area());
    println!("Shape2 area: {}", shape2.area());
}
10. Generics
Generic functions
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    
    largest
}

let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);
println!("The largest number is {}", result);
Generic structs
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

// implementing methods for a specific type
impl Point<f64> {
    fn distance_from_origin(&self) -> f64 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}
11. VML code generation conventions
Implementing the ownership system

Rust's ownership system is implemented in VML with reference counting:

String structure:
offset 0: reference count
offset 4: capacity
offset 8: length
offset 12: data pointer
Function calling convention
fn add(x: i32, y: i32) -> i32 {
    x + y
}

VML code:
LABEL add
    ; save the frame pointer
    PUSH R14
    MOVE R14, R13
    
    ; access the arguments
    MOVE R0, [R14+12]   ; x
    MOVE R1, [R14+8]    ; y
    ADD R0, R0, R1      ; x + y
    
    ; the return value is in R0
    POP R14
    RET
Implementing error handling
Result<T, E> enum implementation:
value 0: Ok variant tag
value 4: Ok value (if the tag is Ok)
value 8: Err variant tag
value 12: Err value (if the tag is Err)
12. Example programs
Factorial
fn factorial(n: u64) -> u64 {
    match n {
        0 | 1 => 1,
        _ => n * factorial(n - 1),
    }
}

fn main() {
    println!("5! = {}", factorial(5));  // 120
}
Fibonacci sequence
fn fibonacci(n: u32) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

fn main() {
    for i in 0..10 {
        println!("fib({}) = {}", i, fibonacci(i));
    }
}
A small vector library
struct Vector3 {
    x: f64,
    y: f64,
    z: f64,
}

impl Vector3 {
    fn new(x: f64, y: f64, z: f64) -> Vector3 {
        Vector3 { x, y, z }
    }
    
    fn dot(&self, other: &Vector3) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
    
    fn cross(&self, other: &Vector3) -> Vector3 {
        Vector3 {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x,
        }
    }
    
    fn magnitude(&self) -> f64 {
        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
    }
}

fn main() {
    let v1 = Vector3::new(1.0, 2.0, 3.0);
    let v2 = Vector3::new(4.0, 5.0, 6.0);
    
    println!("Dot product: {}", v1.dot(&v2));
    println!("Magnitude v1: {}", v1.magnitude());
}
Floating-point and 64-bit compilation modes

The VML toolchain controls how floating point and 64-bit integers are handled through three compilation flags:

FlagPossible valuesDefaultDescription
--float32hard / soft / nonehard32-bit float (f32) handling mode
--float64hard / soft / nonesoft64-bit float (f64) handling mode
--int64hard / soft / nonesoft64-bit integer (i64/u64) handling mode
32-bit float (float32)

The 32-bit single-precision float type f32 in this language compiles as follows:

64-bit float (double)

The 64-bit double-precision float type f64 in this language compiles as follows:

64-bit integer (int64)

The 64-bit integer types i64 / u64 in this language compile as follows:

Software emulation libraries

The software emulation libraries above all live in the Lib/shared/ directory, are written in C, are compiled to VML by the C compiler, and are shared by every language:

Library filePurposeCore functions
softfloat.cQ15.16 fixed-point 32-bit float emulation__vml_float_add/sub/mul/div/neg/abs/cmp, __vml_int2float/float2int
softdouble.cIEEE 754 double-precision 64-bit float emulation__vml_double_add/sub/mul/div/neg/abs/cmp, __vml_int2double/double2int, __vml_float2double/double2float
softint64.c64-bit integer dual-register emulation__vml_i64_add/sub/neg/and/or/xor/not/shl/shr
13. Compilation limitations
Current implementation status
Implemented
Core features yet to be implemented
  1. Ownership and borrow checker (a simplified version)
  2. Pattern matching (match) code generation
  3. struct/enum/trait/impl
  4. Generic support
  5. Error handling (Result/Option)
  6. async/await (skipped in MCU mode)
Technical challenges
  1. Ownership system: Rust's core feature, requiring static analysis (the simplified VML version does not implement a borrow checker for now)
  2. Lifetimes: the static checking of reference validity
  3. Pattern matching: complex pattern destructuring
  4. Traits/generics: the monomorphization compilation strategy
14. Integration with the VML runtime

Rust programs interact with the VML runtime through system calls:

Rust's memory-safety characteristics and high performance make it suited to systems programming and embedded development. Through the VML compiler, Rust programs can run in resource-constrained environments.


🆕 String encoding (v1.65.19)

This language compiler uses the VML string system indirectly through the shared library (Lib/shared/).

DirectiveWidthEncodingC type
.string8-bitUTF-8char*
.wstring16-bitUTF-16LEwchar_t*
.ustring32-bitUTF-32LEchar32_t*

MCU mode (default): strings are output as UTF-8 (.string) OS mode: the encoding can be determined through the VML_WSTRING macro

The shared library already provides wide-string conversion functions (wchar.h/uchar.h), which each language compiler can use as needed.

Compiler README

Rust compiler

Path: VMLPrepares/RustCompiler/ Completeness: ~93% | 🟢 production ready Standard library: Lib/rust/

Features

Compilation modes

MCU mode (default --mode mcu)

MCU mode is tuned for microcontrollers and bare-metal environments (Arduino/STM32/8051 and so on), and automatically skips features that are incompatible with an operating system.

Skipped (no code is generated for this syntax):

Kept (implemented underneath by the BIOS):

OS mode (--mode os, reserved)

OS mode targets environments that have an operating system (such as embedded Linux or an RTOS), and will support every language feature (file system, threads, asynchronous I/O, exceptions, reflection and so on).

RAM levels
MCU-safe coding tips

Usage

dotnet run --project VMLPrepares/RustCompiler input.Ru -o output.vml

Tests

Test/Ru/ — 0 test files (the test directory is yet to be created)