velt/native
import { IoResult, IoStatus, unwrapIo, checkIo } from "velt/native". What the Velt side of a
package with native code binds its Rust functions with. Programs
that don't wrap a native library never import it.
IoResult<T>: the C layout a native function that produces aTreturns (in Rust,Result<T, Error>), a struct ofcode(0 on success),messageandvalue.IoStatusis the one for a function that produces nothing (Result<(), Error>), withcodeandmessage.unwrapIo(r): the value of a successfulIoResult; throws anIoError{ code, message }otherwise.checkIo(s)throws for a failedIoStatus.ioError(code, message): theIoErrorfor a failed result.errorCodeName(code): the Node-style name of a failure code ("ENOENT","ECONNREFUSED","ETIMEDOUT"), for a package that throws an error class of its own.
The package declares each Rust function with the signature its library exports, and wraps it in
a Velt API. velt checks every declare against the library, so a mismatch is a compile error at
the declare, not a crash at run time:
src/lib.vlt
import { IoResult, unwrapIo } from "velt/native";
declare function velt_greet__parse(text: string): IoResult<i64>;
export function parse(text: string): i64 {
return unwrapIo(velt_greet__parse(text));
}A package with an error class of its own builds it from the code's name:
src/errors.vlt
import { errorCodeName, IoStatus } from "velt/native";
export class GreetError extends Error {
code: string;
constructor(code: string, message: string) {
super(message);
this.code = code;
}
}
export function check(s: IoStatus) {
if (s.code != 0) {
throw new GreetError(errorCodeName(s.code), s.message);
}
}The first example is an excerpt: a declare function compiles only in a package whose native
library exports it. A database driver hands its rows and parameters across with
velt/db instead.