Public release v1.8.0 · Spec v0.2.0-draft · Star on GitHub

Use cases

No production case studies yet. These are popular Rust domains where Crisp’s compact syntax and global inference are meant to make the same jobs easier to write and read — while still emitting Rust that rustc checks. Each card links to live examples on GitHub.

CLI tools

Shapes, implicit generics, and interpolation — without spelling every type and borrow up front. Emit stays a normal Rust binary.

-- examples/hello/src/main.crp
shape Named = {
    name: str
}

type Guest = {
    name: str = "world"
}

id(x: T) = x

greet(who: Named) = "hello {who.name}"

pub main() = {
    world := Guest {}
    print(id(greet(world)))
}

-- run: crisp run examples/hello

Config & services

Structs with defaults, modules, and sealed APIs for small services that would otherwise drown in boilerplate.

-- examples/defaults/src/main.crp
type ServerConfig = {
    host: str  = "127.0.0.1"
    port: uint = 9000
    debug: bool = false
}

test "default port constant" = {
    assert_eq(9000, 9000)
}

pub main() = {
    cfg := ServerConfig { port: 3000 }
    log("port={cfg.port}")
}

Async workers

Tokio-backed async / await with Crisp’s lighter surface for spawn and sleep-style workflows.

-- examples/async_spawn/src/main.crp
worker() = async {
    sleep_ms(2)
    print("worker-done")
}

pub main() = async {
    spawn worker()
    sleep_ms(5)
    print("main-done")
}

FFI bridges

Call C with extern "C" and unsafe. Rust crates use rust = true + use serde_json { … } (see Interop).

-- examples/ffi/src/main.crp
extern "C" {
    abs(x: int) -> int
}

pub main() = {
    r := unsafe { abs(7) }
    print("ffi-result={r}")
}

Data pipelines

Vec operations, fallible IO, and chained transforms with ambient ! error sets instead of noisy Result at every step.

-- examples/fallible/src/main.crp
type IoError = { message: str }
type ParseError = { line: int }
type Config = { port: int }

read_file(path) -> str ! IoError =
    throw IoError { message: "not found" }

parse_config(text) -> Config ! ParseError =
    throw ParseError { line: 0 }

read_config(path) = {
    text := read_file(path)
    parse_config(text)
}

pub main() = {
    cfg := read_config("app.toml") catch _ -> Config { port: 3000 }
    print(cfg)
}

Multi-module design

Organize GoF-style patterns across files with Crisp modules — good practice for larger programs before sealed publish.

-- examples/vec2_methods/src/math/vector.crp
pub type Vec2 = {
    x: float
    y: float
}

impl Vec2 = {
    pub new(x: float, y: float) = Vec2 {
        x: x
        y: y
    }
    pub magnitude(self) =
        (self.x ** 2.0 + self.y ** 2.0) ** 0.5
}

-- see also examples/design_patterns

Rust crate interop

Depend on Cargo crates with rust = true, then import APIs TypeScript-style. Scalar signatures go in extern rust / .crpi (#116). Known Result APIs become Crisp ambient errors (?).

-- examples/rust_import (crisp.toml: serde_json rust = true)
use serde_json { from_str, to_string }

pub main() = {
    v := from_str("[1, true, \"crisp\"]")
    s := to_string(v)
    print(s)
}

-- failures → CrispError::Thrown + ? (v1.5)
-- also: examples/net_http (ureq::get)

Traits, shapes & methods

Nominal trait / impl Trait for, data shapes, inherent impl Type, and prelude Show / Eq / Ord shims.

-- examples/show_trait/src/main.crp
trait Show = {
    show(self) -> str
}

type Point = {
    x: int
    y: int
}

impl Point = {
    pub new(x: int, y: int) = Point {
        x: x
        y: y
    }
}

impl Show for Point = {
    show(self) = "({self.x},{self.y})"
}

pub main() = {
    p := Point.new(3, 4)
    log("p={p.show()}")
}

Enums & match

Unit and tuple variants with match — a core systems-language pattern without Rust ceremony.

-- examples/enums/src/main.crp
type Color =
    | Red
    | Green
    | Blue
    | Custom(int, int, int)

describe(color) = match color {
    Color.Red -> "red"
    Color.Green -> "green"
    Color.Blue -> "blue"
    Color.Custom(r, g, b) -> "rgb({r},{g},{b})"
}

is_primary(color) = match color {
    Color.Red -> true
    Color.Green -> true
    Color.Blue -> true
    _ -> false
}

pub main() = {
    print(describe(Color.Red))
    print(describe(Color.Custom(1, 2, 3)))
    print(is_primary(Color.Blue))
}

Repo examples

Open any folder on GitHub, or run from a clone:

crisp run examples/hello
crisp run examples/enums
crisp run examples/show_trait
crisp run examples/shapes
crisp run examples/rust_import
crisp run examples/path_dep
crisp test examples/math
crisp check examples/design_patterns

All examples on GitHub → · Tutorial → · Install →

Feature snippets

Same patterns as the home gallery — copyable Crisp.

Enums + matchexamples/enums
type Color =
    | Red
    | Custom(int, int, int)

describe(color) = match color {
    Color.Red -> "red"
    Color.Custom(r, g, b) -> "rgb({r},{g},{b})"
}
Rust importexamples/rust_import
use serde_json { from_str, to_string }

pub main() = {
    v := from_str("[1, true, \"crisp\"]")
    print(to_string(v))
}
Traitsexamples/show_trait
trait Show = { show(self) -> str }

impl Show for Point = {
    show(self) = "({self.x},{self.y})"
}

label(x: T) = x.show()
Shapesexamples/shapes
shape HasPosition = {
    x: float
    y: float
}

distance(a: HasPosition, b: HasPosition) -> float = {
    dx := a.x - b.x
    dy := a.y - b.y
    dx * dx + dy * dy
}
Async spawnexamples/async_spawn
worker() = async {
    sleep_ms(2)
    print("worker-done")
}

pub main() = async {
    spawn worker()
    sleep_ms(5)
    print("main-done")
}