CochranBlock
cochranblock.org/railgun-rosetta · the cochran block, llc

RAILGUN ROSETTA

Translation key · Python · C · Rust
The railgun's native tongue is Rust. This is the key that gets you here from any other language. Start where you are. Translate one row at a time.

Why this exists

Every Cochran Block product (runsible, r8r, exopack, others in the Manual) is shipped as a single Rust binary. Most working developers don't write Rust. They write Python, JavaScript, Go, C, Java, C#, Ruby. The Rosetta is the translation between the language you already know and the language the railgun speaks.

It is not a complete reference. It is a working alternative to "I'd love to use that crate but I don't know Rust." Read one row, copy the right column into your editor, ship.

Python C Go (coming) JavaScript / TS (coming) Java / Kotlin (coming) C++ (coming) C# (coming) Ruby (coming) Bash (coming)

Python ↔ Rust

The first translation, because Michael's mental model is Python-procedural. Concurrency-focused, no OOP. Most rows here are 1-for-1.

PatternPythonRust
Print a line
print("hello, world")
println!("hello, world");
Variable (immutable by default in Rust)
name = "Michael"
age  = 38
let name = "Michael";
let age: u32 = 38;
Mutable variable
count = 0
count += 1
let mut count = 0;
count += 1;
String formatting
msg = f"hi {name}, age {age}"
let msg = format!("hi {name}, age {age}");
List / Vec
xs = [1, 2, 3]
xs.append(4)
for x in xs:
    print(x)
let mut xs: Vec<i32> = vec![1, 2, 3];
xs.push(4);
for x in &xs {
    println!("{x}");
}
Dict / HashMap
m = {"a": 1, "b": 2}
m["c"] = 3
for k, v in m.items():
    print(k, v)
use std::collections::HashMap;
let mut m: HashMap<&str, i32> = HashMap::new();
m.insert("a", 1);
m.insert("b", 2);
m.insert("c", 3);
for (k, v) in &m {
    println!("{k} {v}");
}
Function
def add(a: int, b: int) -> int:
    return a + b
fn add(a: i32, b: i32) -> i32 {
    a + b
}
Error handling
try:
    result = risky()
except IOError as e:
    print(f"oops: {e}")
match risky() {
    Ok(result) => { /* use result */ }
    Err(e)     => eprintln!("oops: {e}"),
}
// or with ?:
let result = risky()?;
Read a file
with open("notes.txt") as f:
    text = f.read()
let text = std::fs::read_to_string("notes.txt")?;
Write a file
with open("out.txt", "w") as f:
    f.write("done\n")
std::fs::write("out.txt", "done\n")?;
JSON parse
import json
data = json.loads(s)
name = data["name"]
// Cargo.toml: serde_json = "1"
let data: serde_json::Value =
    serde_json::from_str(&s)?;
let name = data["name"].as_str().unwrap();
JSON struct (typed)
from dataclasses import dataclass
@dataclass
class User:
    name: str
    age:  int

import json
u = User(**json.loads(s))
// Cargo.toml: serde = { version="1", features=["derive"] }
//             serde_json = "1"
use serde::Deserialize;
#[derive(Deserialize)]
struct User { name: String, age: u32 }
let u: User = serde_json::from_str(&s)?;
HTTP GET
import requests
r = requests.get("https://api.example.com/x")
data = r.json()
// Cargo.toml: reqwest = { version="0.12", features=["json"] }
let data: serde_json::Value =
    reqwest::blocking::get("https://api.example.com/x")?.json()?;
HTTP server (FastAPI ↔ axum)
from fastapi import FastAPI
app = FastAPI()

@app.get("/hello")
def hello():
    return {"msg": "hi"}
// Cargo.toml: axum = "0.8", tokio = { version="1", features=["full"] }
use axum::{Router, routing::get, Json};
use serde_json::json;

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/hello", get(|| async { Json(json!({"msg": "hi"})) }));
    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}
Async coroutine
import asyncio

async def fetch(url):
    await asyncio.sleep(1)
    return url

asyncio.run(fetch("x"))
// Cargo.toml: tokio = { version="1", features=["full"] }
async fn fetch(url: &str) -> &str {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    url
}

#[tokio::main]
async fn main() {
    let _ = fetch("x").await;
}
Run a subprocess
import subprocess
out = subprocess.run(
    ["ls", "-la"],
    capture_output=True, text=True
).stdout
let out = std::process::Command::new("ls")
    .arg("-la")
    .output()?;
let stdout = String::from_utf8(out.stdout)?;
Regex
import re
m = re.match(r"(\d+)-(\w+)", "42-foo")
if m: print(m.group(1), m.group(2))
// Cargo.toml: regex = "1"
use regex::Regex;
let re = Regex::new(r"(\d+)-(\w+)")?;
if let Some(c) = re.captures("42-foo") {
    println!("{} {}", &c[1], &c[2]);
}
CLI args
import argparse
p = argparse.ArgumentParser()
p.add_argument("--name", required=True)
args = p.parse_args()
print(args.name)
// Cargo.toml: clap = { version="4", features=["derive"] }
use clap::Parser;
#[derive(Parser)]
struct Args { #[arg(long)] name: String }
fn main() {
    let args = Args::parse();
    println!("{}", args.name);
}
Test
def test_add():
    assert add(2, 3) == 5

# pytest tests/test_x.py
#[test]
fn test_add() {
    assert_eq!(add(2, 3), 5);
}

// cargo test
Common pivots from Python. Three concepts that change shape on the way to Rust: ownership (Python garbage collects, Rust tracks who owns each value), match (Rust's pattern match replaces Python's if/elif chains and structural unpacking), and cargo (one tool replaces pip + venv + setuptools + pytest + tox). None of these require new mental models so much as new muscle memory.

C ↔ Rust

For the systems crowd. Rust keeps everything C gives you (no GC, predictable layout, FFI), and adds the ownership rules that make refactoring safe.

PatternCRust
Print a line
#include <stdio.h>
printf("hello, world\n");
println!("hello, world");
Heap allocation
int *p = malloc(sizeof(int));
*p = 42;
free(p);
let p = Box::new(42_i32);
// dropped automatically at end of scope
Pointer / reference
void incr(int *x) { (*x)++; }
int v = 1;
incr(&v);
fn incr(x: &mut i32) { *x += 1; }
let mut v = 1;
incr(&mut v);
Strings
const char *name = "Michael";
char buf[64];
snprintf(buf, sizeof buf,
         "hi %s", name);
let name = "Michael";
let buf  = format!("hi {name}");
Struct
struct Point { float x, y; };
struct Point p = { .x = 1.0, .y = 2.0 };
struct Point { x: f32, y: f32 }
let p = Point { x: 1.0, y: 2.0 };
Enum / tagged union
enum Shape { CIRCLE, SQUARE };
struct ShapeVal {
    enum Shape kind;
    union { float r; float side; };
};
enum Shape {
    Circle { r: f32 },
    Square { side: f32 },
}
Read a file
FILE *f = fopen("notes.txt", "r");
char buf[1024];
size_t n = fread(buf, 1, 1023, f);
buf[n] = '\0';
fclose(f);
let text = std::fs::read_to_string("notes.txt")?;
Dynamic array
int *xs = malloc(4 * sizeof(int));
xs[0] = 1; xs[1] = 2; xs[2] = 3; xs[3] = 4;
// realloc, track length, free, etc.
free(xs);
let xs = vec![1, 2, 3, 4];
// length tracked, dropped automatically
Error handling
int rc = do_thing();
if (rc != 0) {
    fprintf(stderr, "fail: %s\n", strerror(errno));
    return rc;
}
do_thing()?;
// or with full match:
match do_thing() {
    Ok(_)  => {},
    Err(e) => eprintln!("fail: {e}"),
}
Function pointer / closure
typedef int (*Fn)(int);
int apply(int x, Fn f) { return f(x); }
int sq(int x) { return x * x; }
int y = apply(3, sq);
fn apply<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) }
let y = apply(3, |n| n * n);
Build & run
cc -O2 -o app main.c
./app
cargo run --release
Static link to libc / FFI
// you ARE libc
extern int getpid(void);
extern "C" { fn getpid() -> i32; }
unsafe { let _ = getpid(); }
The big swap from C. You stop writing memory plumbing. Box, Vec, String, Result, and the borrow checker take over the work that used to be malloc/realloc/free + length tracking + error codes + segfault hunts. Most C programs become shorter in Rust.

Coming next

Translations are added in a deliberate order: Python first (above), then C (above), then Go, JavaScript / TypeScript, Java / Kotlin, C++, C#, Ruby, Bash. Each language gets the same row pattern so your eye learns the shape once.

Source for this page lives in the cochranblock crate at github.com/cochranblock/cochranblock. Pull requests adding rows or whole languages are welcome and will be folded into the next manual revision.

The Cochran Block, LLC · EIN 41-3835237 · CAGE 1CQ66 · UEI W7X3HAQL9CF9 · SDVOSB Pending · Maryland CSB Approved

Home · Manual · crates.io · docs.rs · GitHub · Email