ⓘ Radiance is in early development. Some of the features described here are still in the design phase.
Radiance is a small statically-typed systems programming language designed for the Radiant platform, targeting the RISC-V RV64GC architecture. Radiance features a modern syntax and design inspired by Rust, Swift and Zig.
use std;
default fn main(env: *std::sys::Env) -> void {
for _ in 0..3 {
std::io::printLn("Hello, Radiant!");
}
}
The Radiance standard library ships with first-class audio, graphics, text and input primitives, specifically tailored to the Radiant hardware and platform.
Development of Radiance is currently happening within R’, the lower-level subset of Radiance.
Programs specify in their types which capabilities they require from the OS. The OS won’t load the program if it asks for capabilities that weren’t authorized by the user.
// This program requests the `Root` capability, and delegates
// sub-capabilities to internal procedures.
default fn main(env: *sys::Env<Root>) throws (sys::SystemError) {
let home = try env.fileSystem().path("/home/").acquire();
let memory = try env.heapMemory(4096).acquire();
// This function only has access to one path hierarchy
// and can allocate at most 4096 bytes on the heap.
doFileSystemWork(home, memory);
let gfx = try env.graphics().acquire();
let snd = try env.sound().acquire();
// This function has access to graphics and sound. Without heap memory,
// it has to allocate on the stack or use static memory.
uiLoop(gfx, snd);
}
Software Transactional Memory (STM) is a concurrency control model that lets threads coordinate access to shared memory using atomic, composable transactions instead of locks. Each transaction runs speculatively on a snapshot of memory and automatically retries or commits depending on whether the data it read has changed.
// Selects between different concurrent variables, executing
// one of the clauses atomically, ie. either all the statements
// in the clause execute, or none do.
let job = select atomic {
case let j = <-jobsRecv => {
let q = try stm::read(quota); // These will retry the select
try stm::check(q > 0); // if they fail.
try stm::write(quota, q - 1);
break j; // Return `j` if this block executes.
}
case <-doneRecv => {
break nil; // Break out without a job.
}
default => {
continue; // Retry the transaction.
}
};
Radiance lets you describe hardware devices as typed memory maps, where registers and bitfields are declared with precise addresses, access policies, and semantics. This turns raw MMIO into a safe, statically-checked interface that the compiler can reason about and expose as capabilities.
/// Description of a UART hardware device located at address `0x4000C000`.
device Uart: 0x4000C000 {
register Rx: u8 at 0x00 (Policy::ReadOnly),
register Tx: u8 at 0x01 (Policy::WriteOnly),
register Status: byte at 0x02 (Policy::ReadOnly) {
rxReady: bit 0,
txEmpty: bit 1,
rxError: bit 2,
reserved: bit 7..3,
}
}