pyroxide 0.1.1

Zero-copy FFI bridge between Rust and Mojo
Documentation
  • Coverage
  • 31.62%
    43 out of 136 items documented0 out of 87 items with examples
  • Size
  • Source code size: 55.15 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 12.01 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2m 26s Average build duration of successful builds.
  • all releases: 2m 26s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • honeyspoon/pyroxide
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • honeyspoon

pyroxide

crates.io docs.rs CI License: MIT Rust

Warning: This is AI slop. Built in one session with Claude. Use at your own risk and peril.

Zero-copy FFI bridge between Rust and Mojo — the glowing bridge between oxidation and fire.

use pyroxide::prelude::*;

mojo_type! {
    pub struct Vec3 { pub x: f64, pub y: f64, pub z: f64 }
}

unsafe extern "C" {
    fn vec3_length(addr: isize) -> f64;
}

let v = Vec3 { x: 3.0, y: 4.0, z: 0.0 };
let len = unsafe { vec3_length(v.as_raw()) };

Overview

Pyroxide lets Rust and Mojo share data with zero copies. Define types once in Rust, pass pointers to Mojo, get results back — no serialization, no allocation.

Crate Purpose
pyroxide Core bridge: types, traits, handles, error handling
max-sys Raw bindgen bindings to the Modular MAX C API

Why no mojo-sys? Mojo has no C SDK. You call Mojo via @export → shared library → extern "C". max-sys is for the MAX inference engine, which does have a C API.

Module What
bridge IntoMojo, FromMojo, MojoRef, MojoMut, MojoSlice, MojoSliceMut
abi ABI type mapping docs, OutParam
trampoline catch_mojo_call (panic-safe FFI)
string MojoStr (ptr+len for FFI)
types::max DType, Tensor<T>, TensorView<T>, TensorDescriptor, TensorShape

Prerequisites

  • Rust 1.85+ (edition 2024)
  • Mojo via pixi: pixi global install mojo

Quick start

Add to your Cargo.toml:

[dependencies]
pyroxide = "0.1"

Or with MAX tensor types:

[dependencies]
pyroxide = { version = "0.1", features = ["max"] }

Run the examples:

git clone https://github.com/honeyspoon/pyroxide
cd pyroxide
cargo run -p pyroxide-examples --example 01_hello     # simplest possible call
cargo run -p pyroxide-examples --example 07_embeddings # real HuggingFace model
make test                                             # run all 26 examples

Mojo files are compiled automatically by build.rs — no manual steps.

Examples

Progressive tutorial — each builds on the previous.

# Example What you learn
01 hello Raw FFI: call one Mojo function
02 structs Pass #[repr(C)] structs, read and mutate
03 tensors TensorDescriptor, sum, dot, matmul
04 simd Mojo's explicit SIMD: ~8x speedup
05 dtype_generic One Mojo template → f32/f64/i32
06 comptime Compile-time unrolling, baked constants
07 embeddings HuggingFace model → Mojo inference → similarity matrix
08 abi_edge_cases Bool, Int boundaries, Float64 specials, OutParam
09 image_blur Large mutable buffer, MojoSliceMut
10 tokenizer MojoStr string passing, variable-length output
11 neural_layer Linear + ReLU + softmax, 4 TensorDescriptors
12 accumulator Stateful struct, repeated MojoMut across calls
13 sorting In-place sort + reverse, verify against Rust
14 mandelbrot Compute-heavy grid, ASCII visualization
15 nested_structs Line (2 Points), Triangle (3 Points), centroid
16 struct_arrays &[Point], particle simulation, kinetic energy
17 mixed_args 6 args: pointers + scalars + bools in one call
18 padding u8 + f64 + i32 struct with alignment padding
19 bytes u8/i64 arrays, XOR, prefix sum
20 call_overhead Noop/identity benchmark, pointer stability
21 edge_cases Zero-length, NaN in structs, byte roundtrip
22 large_data 1M-element dot, scale-add, reduce-max
23 chained Normalize→argmax pipeline, NaN/-1 sentinels, histogram
24 matrix Transpose, Hadamard product, trace
25 catch_panic catch_mojo_call, string output, panic recovery
26 pipeline Enum-like dispatch, multi-step transforms

How it works

Rust side

use pyroxide::prelude::*;

mojo_type! {
    pub struct Particle {
        pub pos: [f64; 3],
        pub vel: [f64; 3],
        pub mass: f64,
    }
}

unsafe extern "C" {
    fn compute_energy(addr: isize) -> f64;
}

let p = Particle { pos: [0.0; 3], vel: [1.0; 3], mass: 2.0 };
let energy = unsafe { compute_energy(p.as_raw()) };

Mojo side

@export
def compute_energy(addr: Int) -> Float64:
    var p = UnsafePointer[Float64, MutExternalOrigin](unsafe_from_address=addr)
    var vx = p[3]
    var vy = p[4]
    var vz = p[5]
    var mass = p[6]
    return 0.5 * mass * (vx*vx + vy*vy + vz*vz)

Cost

Operation Overhead
v.as_raw() ~1ns (pointer cast)
v.as_raw_mut() ~1ns
MojoSlice::new(&data).as_raw() 0 copies (read-only slice)
MojoSliceMut::new(&mut data).as_raw() 0 copies (mutable slice)
MojoStr::new(s).as_raw() 0 copies (string → ptr+len)
TensorDescriptor 0 copies
OutParam::call2(|| ...) 0ns overhead (MaybeUninit)
catch_mojo_call(|| ...) 0ns on success

Safety

  • Dangling pointers: MojoRef<'a, T> ties pointer lifetime to the Rust borrow
  • Panics across FFI: catch_mojo_call catches panics (unwinding across extern "C" is UB)
  • Layout mismatch: mojo_type! enforces #[repr(C)] at compile time
  • Ownership: Rust owns, Mojo borrows — documented and enforced by types

Feature flags

Flag Enables
max DType, TensorShape, TensorDescriptor, Tensor<T>, TensorView<T>, MojoDType

Status

Early stage. API will change.

Component Status
mojo_type!, IntoMojo/FromMojo 31 unit tests + 26 examples
MojoSlice / MojoSliceMut Tested across 15+ examples
MojoStr Tested (tokenizer, string output)
OutParam Tested (divmod, ABI edge cases)
catch_mojo_call Tested (panic recovery example)
Tensor<T> / TensorView<T> Tested with HuggingFace + neural layer
abi module Empirically verified against Mojo 0.26
Proc macros (#[mojo_fn]) Not implemented — deferred to 0.2.0

Non-goals

  • Async bridging. Incompatible runtimes. Use spawn_blocking for async Rust.
  • GIL / runtime token. Mojo has no GIL. Thread safety is your responsibility.
  • Mojo codegen. No .mojo generation from Rust types. Write both sides by hand.

Project layout

pyroxide/           Core library (31 unit tests)
max-sys/            Bindgen from MAX C headers (8 headers, 131 bindings)
examples/
  mojo/             Mojo source files (auto-compiled by build.rs)
  examples/         26 Rust example binaries
design/             13 Architecture Decision Records
scripts/
  fetch-headers.sh  Download MAX C headers from GitHub
  pre-commit        Git pre-commit hook
  check-docs.sh     Verify docs stay in sync

License

MIT