Math, Process & IPC
These modules are small, but useful.
They are not the first things most beginners need, but they become handy quickly once you start writing real tools.
std.math
Use std.math for small integer helpers.
import std.math as math;Current API:
math.abs(int) -> intmath.sign(int) -> intmath.square(int) -> intmath.cube(int) -> intmath.is_even(int) -> boolmath.is_odd(int) -> boolmath.min(int, int) -> intmath.max(int, int) -> intmath.clamp(int, int, int) -> intmath.gcd(int, int) -> intmath.lcm(int, int) -> intmath.distance(int, int) -> intmath.between(int, int, int) -> bool
Small example
import std.math as math;
fn:int main() {
let sample:int = 20;
let remainder:int = sample % 6;
let bounded:int = math.clamp(20, 0, 7);
if math.is_even(remainder + bounded) == false {
return 1;
}
print(math.gcd(54, 24));
return 0;
}integer-only for now
std.math currently works on int. There is no floating-point surface yet, and u8 arithmetic is still intentionally excluded.
std.process
Use std.process for small facts about the running target/process.
import std.process as process;Current API:
process.platform() -> strprocess.arch() -> strprocess.exit(int) -> void
Small example
import std.process as process;
fn:int main() {
let platform:str = process.platform();
let arch:str = process.arch();
print(platform);
print(arch);
free platform;
free arch;
return 0;
}What to notice:
platform()andarch()return owned strings- that is why both are freed
std.ipc
Use std.ipc when you want to talk to another program without FFI.
import std.ipc as ipc;Current API:
ipc.Child { handle:ptr u8 }ipc.spawn(str, slice str) -> result ptr ipc.Childipc.stdin_write(ptr ipc.Child, str) -> result intipc.stdin_write_line(ptr ipc.Child, str) -> result intipc.stdin_close(ptr ipc.Child) -> result boolipc.stdout_read(ptr ipc.Child, int) -> result stripc.stdout_read_line(ptr ipc.Child, int) -> result stripc.request_line(ptr ipc.Child, str, int) -> result stripc.stderr_read(ptr ipc.Child, int) -> result stripc.stderr_read_line(ptr ipc.Child, int) -> result stripc.wait(ptr ipc.Child) -> result intipc.kill(ptr ipc.Child) -> result boolipc.release(ptr ipc.Child) -> result bool
Why this matters
This is the first cross-language interop layer in cnegative.
You can:
- spawn Python, Go, Rust, Node, or shell-style helper programs
- send text to their stdin
- read raw text chunks from stdout and stderr
- read one protocol line at a time for JSON-lines or line-based tools
- do a one-line request / one-line reply exchange with
request_line(...) - wait for exit status
The current slice is intentionally:
- blocking
- text-first
- explicit
program + args, not one big shell command string
Small example
import std.env as env;
import std.ipc as ipc;
import std.process as process;
import std.strings as strings;
fn:result str python_program() {
if env.has("CNEG_SMOKE_PYTHON") {
return env.get("CNEG_SMOKE_PYTHON");
}
let platform:str = process.platform();
if strings.eq(platform, "windows") {
free platform;
return ok "python.exe";
}
free platform;
return ok "python3";
}
fn:result int run() {
try program = python_program();
let args:str[2] = [
"-c",
`import sys; line=sys.stdin.readline(); sys.stdout.write(line.upper()); sys.stderr.write(line)`
];
try child = ipc.spawn(program, args);
try out = ipc.request_line(child, "hello", 256);
if ipc.stdin_close(child).ok == false {
free out;
ipc.release(child);
return err;
}
try err_text = ipc.stderr_read_line(child, 64);
try status = ipc.wait(child);
free err_text;
free out;
ipc.release(child);
return ok status;
}Ownership note
stdout_read(...)andstdout_read_line(...)return ownedstrrequest_line(...)also returns an ownedstrstderr_read(...)andstderr_read_line(...)return ownedstrrelease(...)frees the child handle and closes the pipes- call
wait(...)beforerelease(...)when you care about the exit code
Beginner recommendation
Start with:
math.min(...)math.max(...)math.clamp(...)process.platform()
Come back to std.ipc when you start building tools that need to call other programs.
Those are the simplest helpers on this page.