Skip to content

Migrating from Rust to Gossamer

Gossamer deliberately feels Rust-shaped: fn, struct, enum, impl, trait, match, modules, attributes, and Result<T, E> all look familiar. The important differences are ownership, borrowing, concurrency, and which Rust features are intentionally absent.

Quick Map

Rust Gossamer
fn f(x: i64) -> i64 { x + 1 } Same.
struct Point { x: i64, y: i64 } Same declaration.
Point { x: 1, y: 2 } Same named literal.
tuple structs and enum variants use Name(...) Same.
named struct positional shorthand is unavailable Point { 1, 2 } is allowed.
Option<T> and Result<T, E> Same core shape.
? Same propagation model.
async fn and .await Use go expr plus channels or blocking calls.
std::thread::spawn go fn() { ... }()
Box<dyn Trait> Prefer generics or an enum.
cargo build gos build
cargo test gos test
cargo fmt gos fmt

Entry files may omit fn main. Bare statements at file scope become an implicit fn main().

Ownership And References

Gossamer does not expose Rust's ownership-by-move model or lifetime syntax. Heap aggregates are runtime-managed, primitives copy by value, and references are ordinary aliases.

let a = [1, 2, 3]
let b = a
println!("{} {}", a.len(), b.len())

&mut still means the callee may write through the reference, but the compiler does not implement Rust's lifetime or non-lexical-borrow analysis. As in Rust, a writable place must be passed explicitly as &mut value; function(value) never creates a mutable reference. An existing &mut T reference can be forwarded directly. It rejects a second simple named &mut to the same root while the first is in lexical scope, overlapping temporary mutable references, and duplicate mutable roots in one call. More complex aliases remain a correctness hazard as they are in a language with shared mutable objects.

Traits

Traits are nominal and implemented explicitly:

trait Area {
    fn area(&self) -> f64;
}

struct Circle { r: f64 }

impl Area for Circle {
    fn area(&self) -> f64 { 3.14159 * self.r * self.r }
}

fn total<T: Area>(xs: [T]) -> f64 {
    let mut out = 0.0
    for x in xs {
        out += x.area()
    }
    out
}

There is no unsafe in Gossamer source.

Derives And Value Operations

The supported user derives are intentionally small. Use derives for compiler-provided formatting, defaults, and ordering or equality when the type needs those generated implementations.

#[derive(Debug, PartialEq, Eq)]
struct User {
    name: String,
    age: i64,
}

Do not port Rust derives mechanically. Clone, Copy, Hash, Serialize, and Deserialize are not Rust-compatible derive surfaces in Gossamer source. For JSON, use std::encoding::json APIs and the shapes that module supports.

Aggregate values can be used directly in vectors and ordinary structs. HashMap and HashSet support is strongest for scalar and string keys; aggregate map keys have tier-specific limits, so prefer stable scalar keys when code must run across all tiers.

Async Code

Rust:

let response = reqwest::get(url).await?;

Gossamer:

use std::{errors, http}

fn fetch(url: &String) -> Result<String, errors::Error> {
    let response = http::get(url, [])?
    Ok(response.body)
}

For fan-out, spawn goroutines and collect through channels:

let (tx, rx) = channel()

for url in urls {
    let tx = tx.clone()
    go fn() {
        tx.send(http::get(&url, []))
    }()
}

let mut responses = []
for _ in urls {
    responses.push(rx.recv().unwrap())
}

Blocking IO is acceptable. The runtime parks goroutines around blocking operations where the standard library provides integration.

Collections And Pipelines

Rust iterator method chains become std::iter pipelines. Gossamer's pipe operator sends the left-hand value to the last argument.

let total: i64 = xs.iter()
    .filter(|n| **n % 2 == 0)
    .map(|n| n * n)
    .sum();
use std::iter

let total = xs
    |> iter::filter(|n: i64| n % 2 == 0)
    |> iter::sum_by(|n: i64| n * n)

Mutating collection helpers such as push, sort, insert, and remove stay as methods.

Standard Library Map

Rust Gossamer
std::fs::read_to_string(path) fs::read_to_string(path)
std::fs::read(path) fs::read(path)
std::fs::write(path, data) fs::write(path, data)
std::env::args() env::args()
std::env::var(name).ok() env::var(name)
std::process::Command process::run(program, &args)
std::process::exit(code) process::exit(code)
Path::join path::join(base, part)
std::sync::Mutex sync::Mutex
std::time::Duration::from_millis time::Duration::from_millis
reqwest::blocking::get(url) http::get(url, [])
serde_json encoding::json