rokdocs
v0.1

3.6. env:: - environment variables / args / directories

The rok::std::env module provides a consistent entry point for accessing the process environment. Command-line arguments, environment variables and standard directory paths are gathered in one place, hiding OS differences.

3.6.1. API

The functions and types the module exposes, at a glance:

// command-line arguments
fn args() -> List<str>;                        // [0] = program name - the runtime captures argc/argv at startup
fn args_os() -> List<RawStr>;                  // non-UTF-8 preserved (rare)

// process exit
fn exit(code: i32) -> !;                       // exits immediately - calls the runtime's rok_exit; entry point rules in refs-lang 4.16

// environment variables
fn var(name: str) throws (VarError) -> str;
fn var_os(name: str) -> RawStr | none;
fn vars() -> Vars;                             // implements Iterator<Item = (str, str)>
fn vars_os() -> VarsOs;                        // implements Iterator<Item = (RawStr, RawStr)>

fn set_var(name: str, value: str);            // caution - races under multithreading
fn remove_var(name: str);

// directories
fn current_dir() throws (IoError) -> Path;
fn set_current_dir(path: Path) throws (IoError);
fn home_dir() -> Path | none;
fn temp_dir() -> Path;
fn config_dir() -> Path | none;               // macOS ~/Library/Application Support, otherwise $XDG_CONFIG_HOME / ~/.config
fn cache_dir() -> Path | none;                // macOS ~/Library/Caches, otherwise $XDG_CACHE_HOME / ~/.cache
fn data_dir() -> Path | none;                 // macOS ~/Library/Application Support, otherwise $XDG_DATA_HOME / ~/.local/share

// splitting the PATH environment variable (OS-specific separator)
fn split_paths(paths: str) -> List<Path>;     // ":" on unix, ";" on windows
fn join_paths<I: Iterator<Item = Path>>(paths: I) throws (JoinPathsError) -> str;

// the executable itself
fn current_exe() throws (IoError) -> Path;

// process ID
fn pid() -> u32;
fn parent_pid() -> u32 | none;

enum VarError {
    NotPresent,                                 // the variable does not exist
    NotUnicode,                                 // the value is not UTF-8 (read with var_os)
}

RawStr is a string holding the bytes exactly as the OS provided them (possibly not UTF-8). JoinPathsError occurs when one of the paths contains the separator (: / ;).

struct RawStr { /* OS bytes */ }

impl RawStr {
    fn len(self) -> usize;                       // byte length
    fn is_empty(self) -> bool;
    fn to_str(self) throws (Utf8Error) -> str;   // throws if not UTF-8
    fn as_bytes(self) -> List<u8>;
}
impl PartialEq for RawStr { ... }
impl Debug for RawStr { ... }

struct JoinPathsError { path: str; }             // the path containing the separator

On Windows the bytes are the OS's UTF-16 as WTF-8; there:

impl RawStr {
    fn from_wide(wide: List<u16>) -> RawStr;
    fn as_wide(self) -> List<u16>;
}

3.6.2. Examples

How these APIs work together in a real program. The following example shows the typical flow of command-line arguments, environment variables and PATH search in one go.

use rok::std::env;

// CLI tool
fn main() {
    let args = env::args();
    if args.len() < 2 {
        eprintln("usage: tool <input>");
        env::exit(1);
    }
    let input = args[1];
    process(input);
}

// environment variables
let log_level = (try? env::var("LOG_LEVEL")) ?? "info";
let home = env::home_dir() ?? panic("HOME not set");
let config = home / ".config" / "myapp.toml";

// PATH search
let path_str = try env::var("PATH");
for dir in env::split_paths(path_str) {
    let candidate = dir / "myprog";
    if fs::exists(candidate) {
        log("found at {candidate:?}");
    }
}

3.6.3. Multithreading hazard of set_var

set_var, provided for convenience, has one pitfall: if another thread reads or writes environment variables at the same time, a race can occur.

// dangerous - races if another thread calls var at the same time
thread::spawn(|| { env::set_var("X", "1"); });
thread::spawn(|| { env::var("X"); });

POSIX setenv / getenv are not guaranteed thread-safe. The rok standard library attempts to protect them with a global mutex, but races remain possible inside FFI calls or signal handlers.

The recommended pattern is therefore simple: call set_var only at program start, as the first thing in main. That avoids silent corruption later in a multithreaded environment.

3.6.4. impl / target

How each platform implements the same semantics:

Itemlinux/macos/windowswasi
argsargc/argv / GetCommandLinewasi:cli
var / varsgetenv / GetEnvironmentVariablewasi:cli
home_dir$HOME / SHGetKnownFolderPathwasi (no concept)
temp_dir$TMPDIR / GetTempPathwasi
config_dirXDG / AppData(no)
current_exe/proc/self/exe / _NSGetExecutablePath / GetModuleFileNameUnsupported (wasm32)

Standard paths use ~/Library/... on macOS, the XDG Base Directory spec on other Unix systems ($XDG_*_HOME is used only when it is an absolute path; otherwise ~/.config and so on), and Known Folders on Windows. If the home directory cannot be determined, the result is none.

Edit this page on GitHub