feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

+125
View File
@@ -0,0 +1,125 @@
[package]
name = "dever-backend-bridge"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
publish.workspace = true
autotests = false
[lib]
crate-type = ["rlib", "staticlib"]
# Deliberately do not inherit workspace forbid: only src/ffi.rs may allow it.
[lints.rust]
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "deny"
[features]
default = []
embedded = ["dep:cc", "dep:rustix"]
runtime-abi = ["dep:dever-runtime", "dever-runtime/crypto", "dever-runtime/wire", "dep:libc"]
runtime-database = ["runtime-abi", "dever-runtime/database"]
runtime-api = ["runtime-abi", "dever-runtime/api"]
runtime-external = ["runtime-abi", "dever-runtime/external"]
runtime-sqlite = ["runtime-database", "dever-runtime/sqlite"]
runtime-postgres = ["runtime-database", "dever-runtime/postgres"]
[dependencies]
dever-runtime = { workspace = true, optional = true }
[target.'cfg(unix)'.dependencies]
libc = { version = "=0.2.189", optional = true }
rustix = { version = "=1.1.2", features = ["process"], optional = true }
[dev-dependencies]
dever-core.workspace = true
serde_json.workspace = true
sha2.workspace = true
[build-dependencies]
cc = { version = "=1.4.5", optional = true }
[[test]]
name = "backend_bridge"
path = "../../test/backend_bridge.rs"
required-features = ["embedded"]
[[test]]
name = "native_runtime_abi"
path = "../../test/native_runtime_abi.rs"
required-features = ["runtime-abi"]
[[test]]
name = "native_runtime_link"
path = "../../test/native_runtime_link.rs"
required-features = ["runtime-abi"]
[[test]]
name = "llvm_database_source"
path = "../../test/llvm_database_source.rs"
required-features = ["embedded", "runtime-sqlite"]
[[test]]
name = "llvm_api_source"
path = "../../test/llvm_api_source.rs"
required-features = ["embedded", "runtime-api"]
[[test]]
name = "llvm_job_test_source"
path = "../../test/llvm_job_test_source.rs"
required-features = ["embedded", "runtime-api", "runtime-sqlite"]
[[test]]
name = "llvm_native"
path = "../../test/llvm_native.rs"
required-features = ["embedded"]
[[test]]
name = "llvm_managed_native"
path = "../../test/llvm_managed_native.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_result_native"
path = "../../test/llvm_result_native.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_resource_native"
path = "../../test/llvm_resource_native.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_async_native"
path = "../../test/llvm_async_native.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_async_source"
path = "../../test/llvm_async_source.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_stream_network_source"
path = "../../test/llvm_stream_network_source.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_http_system_source"
path = "../../test/llvm_http_system_source.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_application_source"
path = "../../test/llvm_application_source.rs"
required-features = ["embedded", "runtime-abi"]
[[test]]
name = "llvm_external_source"
path = "../../test/llvm_external_source.rs"
required-features = ["embedded", "runtime-external"]
[[test]]
name = "llvm_process_entry_source"
path = "../../test/llvm_process_entry_source.rs"
required-features = ["embedded"]
+50
View File
@@ -0,0 +1,50 @@
fn main() {
#[cfg(feature = "embedded")]
build();
}
#[cfg(feature = "embedded")]
fn build() {
use std::path::PathBuf;
// Private authoring SDK, never a runtime PATH lookup or app setting.
// Release builders prepare these headers/libraries before enabling embedded.
let root =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../target/backend-sdk/usr/lib/llvm-18");
let include = root.join("include");
let lib = root.join("lib");
for input in [include.join("lld/Common/Driver.h"), lib.join("liblldELF.a")] {
assert!(
input.is_file(),
"private LLVM 18 SDK is missing: {}",
input.display()
);
}
println!("cargo:rerun-if-changed=src/bridge.cpp");
println!("cargo:rerun-if-changed={}", root.display());
cc::Build::new()
.cpp(true)
.std("c++17")
// Upstream headers are system headers; warnings remain enabled for ours.
.flag("-isystem")
.flag(include.to_str().expect("SDK include path must be UTF-8"))
.file("src/bridge.cpp")
.flag_if_supported("-fno-rtti")
.compile("dever_backend_bridge");
println!("cargo:rustc-link-search=native={}", lib.display());
let multiarch = match std::env::var("TARGET").as_deref() {
Ok("x86_64-unknown-linux-gnu") => "x86_64-linux-gnu",
Ok("aarch64-unknown-linux-gnu") => "aarch64-linux-gnu",
_ => panic!("the embedded author SDK currently requires a Linux GNU target"),
};
println!(
"cargo:rustc-link-search=native={}",
root.join("..").join(multiarch).display()
);
for name in ["lldELF", "lldCOFF", "lldMachO", "lldCommon"] {
println!("cargo:rustc-link-lib=static={name}");
}
println!("cargo:rustc-link-lib=dylib=LLVM-18");
println!("cargo:rustc-link-lib=dylib=z");
println!("cargo:rustc-link-lib=static=zstd");
}
@@ -0,0 +1,909 @@
#ifndef DEVER_RUNTIME_ABI_V1_H
#define DEVER_RUNTIME_ABI_V1_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint8_t *ptr;
uint64_t len;
} DeverRtBuffer;
typedef struct {
uint64_t low;
uint64_t high;
} DeverRtDecimal;
/* Compiler-emitted callbacks have the C ABI and live for the entire process.
* They operate on fully initialized values of exactly this concrete type.
* clone initializes uninitialized destination storage, drop destroys one
* initialized value, and equal/hash are consistent for Map keys. They must
* not fail or unwind. hash is optional except for Map key descriptors.
*/
typedef struct {
uint64_t size;
uint64_t align;
void (*clone)(const void *source, void *destination);
void (*drop)(void *value);
uint8_t (*equal)(const void *left, const void *right);
uint64_t (*hash)(const void *value);
} DeverRtType;
/* Callbacks initialize one complete ReadEvent in uninitialized storage.
* The Bytes/Text handle is borrowed only during the callback; retain it to
* keep it in the constructed event. All fields live for the process lifetime.
*/
typedef struct {
const DeverRtType *type;
void (*chunk)(const void *borrowed_bytes, void *out_event);
void (*failed)(const void *borrowed_text, void *out_event);
} DeverRtReadEvent;
enum {
DEVER_RT_OK = 0,
DEVER_RT_RUNTIME_ERROR = 1,
DEVER_RT_INVALID_INPUT = 2,
};
/* Internal compiler/runtime ABI, not a Dever source-language FFI.
* All targets are 64-bit. Inputs are borrowed only until the call returns.
* A nonzero input length requires that many live immutable bytes; null is
* accepted only with zero length. Input memory must not overlap an output.
* Each output pointer must be live, writable, correctly aligned, and distinct
* from every other output. An out buffer is reset to {NULL, 0} on every call
* with a valid pointer; release a previous value before reusing that slot.
* Status 0 initializes the numeric out value or owns the output bytes.
* Status 1 leaves numeric out unchanged and returns the original runtime
* error text. Status 2 reports an invalid ABI pointer or length; a null out
* buffer cannot receive an error message. Do not inspect numeric out on error.
* Every non-null returned buffer is allocated by the Rust runtime ABI and
* must be passed once, with its exact length, to dever_rt_v1_buffer_free.
* Do not use C free or the compiler bridge's C++ allocator for these bytes.
*/
uint32_t dever_rt_v1_version(void);
void dever_rt_v1_buffer_free(uint8_t *ptr, uint64_t len);
uint32_t dever_rt_v1_int_add(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_int_sub(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_int_mul(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_int_div(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_int_rem(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_int_neg(int64_t input, int64_t *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_add(double left, double right, double *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_sub(double left, double right, double *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_mul(double left, double right, double *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_div(double left, double right, double *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_rem(double left, double right, double *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_neg(double input, double *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_from_int(int64_t input, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_add(uint64_t left_low, uint64_t left_high, uint64_t right_low, uint64_t right_high, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_sub(uint64_t left_low, uint64_t left_high, uint64_t right_low, uint64_t right_high, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_mul(uint64_t left_low, uint64_t left_high, uint64_t right_low, uint64_t right_high, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_div(uint64_t left_low, uint64_t left_high, uint64_t right_low, uint64_t right_high, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_neg(uint64_t low, uint64_t high, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_round(uint64_t low, uint64_t high, int64_t places, DeverRtDecimal *out, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_int_to_text(int64_t input, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_float_to_text(double input, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_to_text(uint64_t low, uint64_t high, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_decimal_compare(uint64_t left_low, uint64_t left_high, uint64_t right_low, uint64_t right_high, int32_t *out, DeverRtBuffer *error);
/* Compiler-checked finite Decimal operands only; numeric, not bitwise equality. */
uint8_t dever_rt_v1_decimal_equal(uint64_t left_low, uint64_t left_high, uint64_t right_low, uint64_t right_high);
uint32_t dever_rt_v1_decimal_parse(const void *text, DeverRtDecimal *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_copy_utf8(const uint8_t *input, uint64_t len, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_bytes_copy(const uint8_t *input, uint64_t len, DeverRtBuffer *buffer);
uint32_t dever_rt_v1_bytes_to_text(const uint8_t *input, uint64_t len, DeverRtBuffer *buffer);
/* Synchronous checked time.sleep: Unit uses one byte (0) on success. Negative
* duration returns the original runtime error without initializing out.
*/
uint32_t dever_rt_v1_time_sleep(int64_t milliseconds, uint8_t *out, DeverRtBuffer *error);
/* Managed values are private, typed Arc handles. Each returned handle is owned;
* retain returns another owner and release consumes one. Only retain/release
* accept NULL as a no-op. Id uses the Text representation and owner functions.
* All other handle arguments are borrowed unless the symbol ends in _take.
* A _take call consumes its non-NULL input handle even when it returns error.
* Source element pointers and descriptor pointers are borrowed, not consumed.
* A successful element extraction initializes previously uninitialized,
* aligned output storage with a new owned value; absent output is untouched.
* The caller must destroy extracted values with its concrete drop callback.
* Every fallible call resets a valid error buffer; status 1 contains the
* original runtime error and status 2 reports an invalid ABI argument.
*/
void *dever_rt_v1_text_retain(const void *handle);
void dever_rt_v1_text_release(void *handle);
uint32_t dever_rt_v1_text_new(const uint8_t *input, uint64_t len, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_export(const void *handle, DeverRtBuffer *buffer);
uint8_t dever_rt_v1_text_equal(const void *left, const void *right);
uint64_t dever_rt_v1_text_hash(const void *handle);
uint32_t dever_rt_v1_text_compare(const void *left, const void *right, int32_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_concat(const void *left, const void *right, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_length(const void *handle, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_trim(const void *handle, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_lower(const void *handle, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_upper(const void *handle, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_codepoint(const void *handle, int64_t *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_from_codepoint(int64_t value, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_at(const void *handle, int64_t index, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_slice(const void *handle, int64_t start, int64_t end, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_index_of(const void *handle, const void *pattern, int64_t *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_contains(const void *handle, const void *pattern, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_starts_with(const void *handle, const void *pattern, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_ends_with(const void *handle, const void *pattern, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_replace(const void *handle, const void *pattern, const void *replacement, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_text_split(const void *handle, const void *separator, const DeverRtType *text_type, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_int_parse(const void *text, int64_t *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_float_parse(const void *text, double *out, uint8_t *present, DeverRtBuffer *error);
void *dever_rt_v1_bytes_retain(const void *handle);
void dever_rt_v1_bytes_release(void *handle);
uint32_t dever_rt_v1_bytes_new(const uint8_t *input, uint64_t len, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_export(const void *handle, DeverRtBuffer *buffer);
uint8_t dever_rt_v1_bytes_equal(const void *left, const void *right);
uint32_t dever_rt_v1_bytes_length(const void *handle, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_at(const void *handle, int64_t index, int64_t *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_concat(const void *left, const void *right, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_slice(const void *handle, int64_t start, int64_t end, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_from_text(const void *text, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_to_text_handle(const void *bytes, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_bytes_from_ints(const void *list, void **out, DeverRtBuffer *error);
/* Arrays of element pointers are borrowed for the duration of construction.
* count=0 accepts NULL arrays. map_new preserves insertion order and rejects
* duplicate keys exactly as the existing Map::new implementation does.
*/
void *dever_rt_v1_list_retain(const void *handle);
void dever_rt_v1_list_release(void *handle);
uint32_t dever_rt_v1_list_new(const DeverRtType *element_type, const void *const *values, uint64_t count, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_list_append_take(void *list, const void *element, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_list_first_take(void *list, void *out_element, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_list_length(const void *list, int64_t *out, DeverRtBuffer *error);
uint8_t dever_rt_v1_list_equal(const void *left, const void *right);
uint32_t dever_rt_v1_list_cursor_take(void *list, void **out_cursor, DeverRtBuffer *error);
uint32_t dever_rt_v1_list_cursor_next(void *cursor, void *out_element, uint8_t *present, DeverRtBuffer *error);
void dever_rt_v1_list_cursor_release(void *cursor);
void *dever_rt_v1_map_retain(const void *handle);
void dever_rt_v1_map_release(void *handle);
uint32_t dever_rt_v1_map_new(const DeverRtType *key_type, const DeverRtType *value_type, const void *const *keys, const void *const *values, uint64_t count, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_map_put_take(void *map, const void *key, const void *value, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_map_remove_take(void *map, const void *key, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_map_get_take(void *map, const void *key, void *out_value, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_map_length(const void *map, int64_t *out, DeverRtBuffer *error);
uint8_t dever_rt_v1_map_equal(const void *left, const void *right);
uint32_t dever_rt_v1_map_cursor_take(void *map, void **out_cursor, DeverRtBuffer *error);
uint32_t dever_rt_v1_map_cursor_next(void *cursor, void *out_key, void *out_value, uint8_t *present, DeverRtBuffer *error);
void dever_rt_v1_map_cursor_release(void *cursor);
/* Async values have one concrete compiler-emitted owner. move_init transfers
* an initialized source into uninitialized destination storage; the caller
* disarms the source after the callback. Neither callback may unwind.
*/
typedef struct {
uint64_t size;
uint64_t align;
void (*move_init)(void *source, void *destination);
void (*drop)(void *value);
uint8_t transferable;
} DeverRtOwnedType;
typedef struct DeverRtPollState DeverRtPollState;
typedef struct DeverRtAsyncOp DeverRtAsyncOp;
typedef struct DeverRtAsyncTask DeverRtAsyncTask;
typedef struct DeverRtAsyncGroup DeverRtAsyncGroup;
typedef struct DeverRtAsyncChannel DeverRtAsyncChannel;
/* create clones borrowed inputs into the coroutine frame before its initial
* suspension. The frame exclusively owns those copies until destroy. The
* output/fault slots remain live until the future completes or is destroyed.
* resume cannot retain the current poll context between calls.
*/
typedef struct {
const DeverRtOwnedType *output_type;
const DeverRtOwnedType *fault_type;
void *(*create)(DeverRtPollState *state, const void *input, void *output, void *fault);
void (*resume)(void *frame);
void (*destroy)(void *frame);
uint8_t (*done)(void *frame);
uint8_t send_safe;
} DeverRtAsyncFunction;
/* invoke is a checked synchronous function; it runs only in the bounded
* blocking pool. Non-null operation creation transfers input to the runtime.
* invoke only borrows that runtime-owned input and must not drop it; the
* runtime releases it after invoke returns or the operation is cancelled.
* Status 0 initializes output, 1 initializes fault, and neither callback
* nor owned-value callback may unwind through this C boundary.
*/
typedef struct {
const DeverRtOwnedType *input_type;
const DeverRtOwnedType *output_type;
const DeverRtOwnedType *fault_type;
uint32_t (*invoke)(void *input, void *output, void *fault);
uint8_t send_safe;
} DeverRtSyncFunction;
enum {
DEVER_RT_ASYNC_PENDING = 0,
DEVER_RT_ASYNC_READY_OK = 1,
DEVER_RT_ASYNC_READY_FAULT = 2,
DEVER_RT_ASYNC_READY_RUNTIME_ERROR = 3,
DEVER_RT_ASYNC_INVALID_INPUT = 4,
};
/* root starts the one bounded task Scope. Completion status is reported by
* the coroutine through complete; only the matching ready output is moved.
* The caller owns output/fault after a matching ready status and error bytes
* after a runtime error. No output is initialized on Pending or invalid input.
* op_poll only borrows its operation until op_release. A ready OK moves its
* concrete output into an uninitialized slot; a ready typed fault moves the
* concrete fault into an uninitialized slot. For receive, present separately
* describes Channel exhaustion, even when the element itself is Nullable.
* Pending initializes none of these slots. The error buffer is reset on each
* poll and must be freed with dever_rt_v1_buffer_free when non-null.
*
* Task and Group retain create another wrapper owner, not another task or
* group. wait/stop consume one wrapper owner and take the inner affine value
* exactly once; release consumes one wrapper owner without waiting. Group run
* borrows a wrapper; Channel retain clones an alias to the same queue. A
* non-null Channel send operation moves the input value and disarms its old
* slot before polling, including if delivery later fails or is cancelled.
*/
uint32_t dever_rt_v1_async_root(const DeverRtAsyncFunction *function,
const void *input, void *output, void *fault,
DeverRtBuffer *error);
void dever_rt_v1_async_complete(DeverRtPollState *state, uint32_t status);
DeverRtAsyncOp *dever_rt_v1_async_sleep(int64_t milliseconds);
DeverRtAsyncOp *dever_rt_v1_async_call(const DeverRtAsyncFunction *function,
const void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_blocking(const DeverRtSyncFunction *function,
void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_parallel(const DeverRtSyncFunction *function,
void *input, DeverRtBuffer *error);
uint32_t dever_rt_v1_async_op_poll(DeverRtPollState *state, DeverRtAsyncOp *operation,
void *output, uint8_t *present, void *fault,
DeverRtBuffer *error);
void dever_rt_v1_async_op_release(DeverRtAsyncOp *operation);
DeverRtAsyncOp *dever_rt_v1_async_task_run(const DeverRtAsyncFunction *function,
const void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_task_run_sync(const DeverRtSyncFunction *function,
void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_task_wait(DeverRtAsyncTask *task);
DeverRtAsyncOp *dever_rt_v1_async_task_stop(DeverRtAsyncTask *task);
DeverRtAsyncTask *dever_rt_v1_async_task_retain(const DeverRtAsyncTask *task);
void dever_rt_v1_async_task_release(DeverRtAsyncTask *task);
uint32_t dever_rt_v1_async_group_new(int64_t limit, DeverRtAsyncGroup **output,
DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_group_run(DeverRtAsyncGroup *group,
const DeverRtAsyncFunction *function,
const void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_group_run_sync(DeverRtAsyncGroup *group,
const DeverRtSyncFunction *function,
void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_group_wait(DeverRtAsyncGroup *group);
DeverRtAsyncOp *dever_rt_v1_async_group_stop(DeverRtAsyncGroup *group);
DeverRtAsyncGroup *dever_rt_v1_async_group_retain(const DeverRtAsyncGroup *group);
void dever_rt_v1_async_group_release(DeverRtAsyncGroup *group);
uint32_t dever_rt_v1_async_channel_new(int64_t capacity, DeverRtAsyncChannel **output,
DeverRtBuffer *error);
DeverRtAsyncChannel *dever_rt_v1_async_channel_retain(const DeverRtAsyncChannel *channel);
void dever_rt_v1_async_channel_release(DeverRtAsyncChannel *channel);
DeverRtAsyncOp *dever_rt_v1_async_channel_send(DeverRtAsyncChannel *channel,
const DeverRtOwnedType *element_type,
void *element, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_channel_receive(DeverRtAsyncChannel *channel);
DeverRtAsyncOp *dever_rt_v1_async_channel_close(DeverRtAsyncChannel *channel);
/* Stream constructors borrow their source. Descriptors describe the exact
* element and must be transferable before a producer may cross a thread.
* All aliases share one cursor and close state; pull uses the separate present
* slot (including Nullable rows), and emits a terminal Failed exactly once.
*/
uint32_t dever_rt_v1_async_stream_from_list(const void *list, const DeverRtOwnedType *element_type, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_async_stream_from_bytes(const void *bytes, const DeverRtOwnedType *int_type, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_async_ticks(int64_t milliseconds, const DeverRtOwnedType *int_type, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_async_channel_stream(const DeverRtAsyncChannel *channel, void **out, DeverRtBuffer *error);
void *dever_rt_v1_async_stream_retain(const void *stream);
void dever_rt_v1_async_stream_release(void *stream);
DeverRtAsyncOp *dever_rt_v1_async_stream_pull(const void *stream);
uint32_t dever_rt_v1_async_stream_close(const void *stream, uint8_t *out, DeverRtBuffer *error);
/* TCP operations reuse the runtime's independent read/write locks, deadlines
* and cancellation. Async operation output is Socket, Listener, Socket,
* optional Bytes, or Bool respectively. String I/O errors use async status 3.
* chunks/connections callbacks initialize the original full event Choice;
* connections uses chunk for the borrowed accepted Socket handle.
*/
DeverRtAsyncOp *dever_rt_v1_async_net_connect(const void *host, int64_t port);
DeverRtAsyncOp *dever_rt_v1_async_net_connect_timeout(const void *host, int64_t port, int64_t milliseconds);
DeverRtAsyncOp *dever_rt_v1_async_net_listen(const void *host, int64_t port);
DeverRtAsyncOp *dever_rt_v1_async_net_accept(const void *listener);
DeverRtAsyncOp *dever_rt_v1_async_net_read(const void *socket, int64_t limit);
DeverRtAsyncOp *dever_rt_v1_async_net_write(const void *socket, const void *bytes);
void *dever_rt_v1_socket_retain(const void *socket);
void dever_rt_v1_socket_release(void *socket);
void *dever_rt_v1_listener_retain(const void *listener);
void dever_rt_v1_listener_release(void *listener);
uint32_t dever_rt_v1_net_port(const void *listener, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_net_timeout(const void *socket, int64_t milliseconds, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_socket_close(const void *socket, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_listener_close(const void *listener, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_net_chunks(const void *socket, int64_t limit, const DeverRtReadEvent *event, const DeverRtOwnedType *element_type, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_net_connections(const void *listener, const DeverRtReadEvent *event, const DeverRtOwnedType *element_type, void **out, DeverRtBuffer *error);
/* wait_timeout consumes one task wrapper, returns the entire task output row
* with present=1, or present=0 after cancellation and descendant draining.
* race requires distinct unconsumed tasks of the exact same output type. A
* non-null result consumes every supplied wrapper; NULL consumes none and
* reports a creation error. Typed faults remain intact through both paths.
*/
DeverRtAsyncOp *dever_rt_v1_async_task_wait_timeout(DeverRtAsyncTask *task, int64_t milliseconds);
DeverRtAsyncOp *dever_rt_v1_async_task_race(DeverRtAsyncTask *const *tasks, uint64_t count, DeverRtBuffer *error);
/* Exactly one function is present. pack clones borrowed element/context into
* one complete input row. A null context_type means no context. Descriptors
* and callbacks are process-static; send_safe covers packed inputs/context.
* Source kinds: 0 List, 1 Bytes, 2 synchronous Stream, 3 AsyncStream.
* The synchronous entry accepts only a synchronous handler and kinds 0..2;
* the async entry accepts kinds 0,1,3. Both preserve runtime dispatch policy.
* Synchronous completion also uses ASYNC_READY_* statuses (no Pending).
*/
typedef struct {
const DeverRtAsyncFunction *async_function;
const DeverRtSyncFunction *sync_function;
const DeverRtOwnedType *input_type;
const DeverRtType *context_type;
void (*pack)(const void *element, const void *context, void *out_input);
} DeverRtParallelFunction;
DeverRtAsyncOp *dever_rt_v1_async_parallel_each(const void *source, uint32_t source_kind, int64_t limit, const DeverRtParallelFunction *function, const void *context, DeverRtBuffer *error);
uint32_t dever_rt_v1_parallel_each(const void *source, uint32_t source_kind, int64_t limit, const DeverRtParallelFunction *function, const void *context, void *fault, DeverRtBuffer *error);
/* Successful allocation is non-null and must be paired with frame_free using
* the exact coro.size/coro.align. Invalid layout or OOM terminates the process
* before coro.begin can observe a null allocation.
*/
void *dever_rt_v1_async_frame_alloc(uint64_t size, uint64_t align);
void dever_rt_v1_async_frame_free(void *frame, uint64_t size, uint64_t align);
/* File aliases share one close state. create uses create-new and never replaces
* an existing path. File read returns absent at EOF. A stream alias shares one
* cursor; pull returns the terminal Failed event once, then absent. Closing a
* Stream is idempotent; closing a File twice returns the runtime error text.
*/
void *dever_rt_v1_file_retain(const void *handle);
void dever_rt_v1_file_release(void *handle);
uint32_t dever_rt_v1_file_open(const void *path, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_file_create(const void *path, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_file_read(const void *file, int64_t limit, void **out_bytes, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_file_write(const void *file, const void *bytes, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_file_close(const void *file, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_file_chunks(const void *file, int64_t limit, const DeverRtReadEvent *event, void **out_stream, DeverRtBuffer *error);
void *dever_rt_v1_stream_retain(const void *handle);
void dever_rt_v1_stream_release(void *handle);
uint32_t dever_rt_v1_stream_pull(const void *stream, void *out_element, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_stream_close(const void *stream, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_unix_millis(int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_now(int64_t *out, DeverRtBuffer *error);
/* Invocation-owned Clock: virtual time affects Job scheduling and drain only. */
uint32_t dever_rt_v1_job_clock_new(uint8_t test, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_job_clock_now(const void *clock, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_job_clock_advance(const void *clock, int64_t millis, DeverRtBuffer *error);
void dever_rt_v1_job_clock_release(void *clock);
uint32_t dever_rt_v1_time_monotonic_nanos(int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_parse_datetime(const void *text, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_format_datetime(int64_t value, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_parse_date(const void *text, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_format_date(int64_t value, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_parse_time(const void *text, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_format_time(int64_t value, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_add(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_subtract(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_time_difference(int64_t left, int64_t right, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_crypto_token(int64_t length, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_crypto_password_hash(const void *password, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_crypto_password_verify(const void *password, const void *encoded, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_crypto_sha256(const void *bytes, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_crypto_hmac_sha256(const void *secret, const void *bytes, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_crypto_constant_time_eq(const void *left, const void *right, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_secret_from_text(const void *text, void **out, DeverRtBuffer *error);
void *dever_rt_v1_uuid_retain(const void *handle);
void dever_rt_v1_uuid_release(void *handle);
uint8_t dever_rt_v1_uuid_equal(const void *left, const void *right);
uint32_t dever_rt_v1_uuid_parse(const void *text, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_uuid_to_text(const void *uuid, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_process_arguments(const DeverRtType *text_type, void **out, DeverRtBuffer *error);
/* Terminal entry adapters: stderr borrows bytes; test_index consumes no argv
* storage and writes out only for exactly one unsigned decimal index < count. */
/* Call once from process main before threads; preserves EPIPE diagnostics on
* Unix. Embedded callable roots must not alter their host's signal policy. */
uint32_t dever_rt_v1_process_init(void);
uint32_t dever_rt_v1_process_stderr(const uint8_t *bytes, uint64_t len);
uint32_t dever_rt_v1_process_test_index(int32_t argc, const char *const *argv, uint64_t count, uint64_t *out);
/* Borrow Text and report through the same configured logger as application errors. */
uint32_t dever_rt_v1_process_error(const void *text);
uint32_t dever_rt_v1_stdout_write(const void *text, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_log_write(uint32_t level, const void *message, const void *fields, uint8_t *out, DeverRtBuffer *error);
void dever_rt_v1_log_flush(void);
/* Protocol records have canonical layouts independent of source declaration order.
* Inputs borrow handles. Field getters return owned handles. Builders clone inputs.
* All asynchronous protocol operations use async_op_poll; success is one handle
* (response/client/socket), Bool byte for mutations, or Unit for servers.
* Poll validates protocol output slots before advancing I/O. Invalid slots
* return status 4 without completing or polling the operation; retry is allowed.
*/
typedef struct { int64_t streams, stream_window_bytes, connection_window_bytes; } DeverRtHttp2Limits;
typedef struct { int64_t header_bytes, body_bytes, timeout_ms, connections; const DeverRtHttp2Limits *http2; } DeverRtHttpLimits;
typedef struct { int64_t idle_ms, chunk_bytes, read_ms; } DeverRtHttpPoolLimits;
typedef struct { int64_t chunk_bytes, idle_ms, heartbeat_ms; } DeverRtHttpLiveLimits;
typedef struct { int64_t message_bytes, idle_ms, write_ms; } DeverRtWsLimits;
typedef struct { void *method, *target, *headers, *body; } DeverRtHttpRequestFields;
typedef struct { int64_t status; void *headers, *body; } DeverRtHttpResponseFields;
typedef struct { void *name, *value; } DeverRtHttpHeaderFields;
typedef struct { uint32_t kind; void *payload; } DeverRtWsMessageFields; /* Text=0 Binary=1 Ping=2 Pong=3 */
typedef struct { const void *event, *data, *id; int64_t retry_ms; uint8_t has_retry; } DeverRtSseEvent;
#define DEVER_RT_PROTOCOL_OWNER(name) void *dever_rt_v1_##name##_retain(const void *handle); void dever_rt_v1_##name##_release(void *handle)
DEVER_RT_PROTOCOL_OWNER(http_headers);
DEVER_RT_PROTOCOL_OWNER(http_request);
DEVER_RT_PROTOCOL_OWNER(http_response);
DEVER_RT_PROTOCOL_OWNER(http_stream_request);
DEVER_RT_PROTOCOL_OWNER(http_stream_response);
DEVER_RT_PROTOCOL_OWNER(client_tls);
DEVER_RT_PROTOCOL_OWNER(server_tls);
DEVER_RT_PROTOCOL_OWNER(http_client);
DEVER_RT_PROTOCOL_OWNER(http_reply);
DEVER_RT_PROTOCOL_OWNER(websocket);
DEVER_RT_PROTOCOL_OWNER(ws_message);
DEVER_RT_PROTOCOL_OWNER(secret);
#undef DEVER_RT_PROTOCOL_OWNER
uint32_t dever_rt_v1_http_headers_new(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_headers_push(void *headers, const void *name, const void *value, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_headers_length(const void *headers, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_headers_get(const void *headers, int64_t index, DeverRtHttpHeaderFields *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_request_new(const DeverRtHttpRequestFields *fields, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_request_fields(const void *request, DeverRtHttpRequestFields *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_response_new(const DeverRtHttpResponseFields *fields, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_response_fields(const void *response, DeverRtHttpResponseFields *out, DeverRtBuffer *error);
/* Stream upload decoder borrows source event; returns 0 Chunk or 1 Failed and
* initializes an owned Bytes/Text handle. Download uses existing ReadEvent callbacks. */
uint32_t dever_rt_v1_http_stream_request_new(const DeverRtHttpRequestFields *fields, uint32_t (*decode)(const void *, void **), void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_http_stream_response_fields(const void *response, const DeverRtReadEvent *event, const DeverRtOwnedType *type, DeverRtHttpResponseFields *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_tls_system(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_tls_client(const void *ca, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_tls_server(const void *cert, const void *key, void **out, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_http_send(const void *host, int64_t port, const void *request, const DeverRtHttpLimits *limits);
DeverRtAsyncOp *dever_rt_v1_async_http_client(const void *origin, const void *tls, const DeverRtHttpLimits *limits, const DeverRtHttpPoolLimits *pool);
DeverRtAsyncOp *dever_rt_v1_async_http_request(const void *client, const void *request);
DeverRtAsyncOp *dever_rt_v1_async_http_open(const void *client, const void *request);
DeverRtAsyncOp *dever_rt_v1_async_http_open_stream(const void *client, const void *request);
DeverRtAsyncOp *dever_rt_v1_async_http_close_client(const void *client);
typedef struct {
const DeverRtAsyncFunction *asynchronous;
const DeverRtSyncFunction *synchronous;
const DeverRtOwnedType *input_type;
const DeverRtType *context_type;
uint32_t (*pack)(const void *request, const void *reply, const void *context, void *out, DeverRtBuffer *error);
uint32_t (*response)(const void *output, void **out, DeverRtBuffer *error);
uint32_t (*fault_message)(const void *fault, void **out, DeverRtBuffer *error);
} DeverRtHttpHandler;
/* live=null means buffered; tls=null means plaintext. Context is cloned before
* returning. Handler faults remain typed until the terminal request-log callback. */
DeverRtAsyncOp *dever_rt_v1_async_http_serve(const void *listener, const DeverRtHttpLimits *limits, const DeverRtHttpLiveLimits *live, const void *tls, const DeverRtHttpHandler *handler, const void *context, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_http_respond(const void *reply, const void *response);
DeverRtAsyncOp *dever_rt_v1_async_http_start(const void *reply, int64_t status, const void *headers);
DeverRtAsyncOp *dever_rt_v1_async_http_write(const void *reply, const void *bytes);
DeverRtAsyncOp *dever_rt_v1_async_http_finish(const void *reply);
DeverRtAsyncOp *dever_rt_v1_async_sse_start(const void *reply, const void *headers);
DeverRtAsyncOp *dever_rt_v1_async_sse_send(const void *reply, const DeverRtSseEvent *event);
DeverRtAsyncOp *dever_rt_v1_async_ws_accept(const void *reply, const DeverRtWsLimits *limits);
DeverRtAsyncOp *dever_rt_v1_async_ws_connect(const void *host, int64_t port, const void *target, const DeverRtWsLimits *limits);
DeverRtAsyncOp *dever_rt_v1_async_ws_open(const void *url, const void *tls, const DeverRtWsLimits *limits);
uint32_t dever_rt_v1_ws_message_new(uint32_t kind, const void *payload, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_ws_message_fields(const void *message, DeverRtWsMessageFields *out, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_ws_send(const void *socket, const void *message);
/* receive success writes a message handle only when present=1. */
DeverRtAsyncOp *dever_rt_v1_async_ws_receive(const void *socket);
typedef struct {
const DeverRtType *element_type;
void (*read)(uint32_t kind, const void *payload, void *out);
void (*failed)(const void *text, void *out);
} DeverRtWsEvent;
uint32_t dever_rt_v1_ws_messages(const void *socket, const DeverRtWsEvent *event, const DeverRtOwnedType *type, void **out, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_async_ws_close(const void *socket, int64_t code, const void *reason);
/* Synchronous typed wire codecs. Nodes and the encoder are borrowed only for
* the enclosing callback, including child nodes returned by field/list getters.
* They have no retain/release operation and must never enter a business value,
* coroutine frame or other persistent storage. The concrete type is process-
* static; decode validates its destination before parsing or calling the codec.
* A decoder initializes out only on success and cleans every partial owner on
* failure. An encoder only borrows its concrete input. Callbacks return regular
* status 0/1/2 and own any error Buffer they return, following the common ABI.
* Text/Uuid/Secret getters return normal owned handles; raw returns exact JSON.
* Names are borrowed UTF-8 byte slices. Missing optional fields set present=0
* without initializing out; required fields use the original wire diagnostic.
*/
typedef struct { const uint8_t *ptr; uint64_t len; } DeverRtWireName;
/* runtime-external: compiler metadata is copied into one invocation owner.
* Resource paths/digests/bytes are immutable for the process lifetime; the
* descriptor arrays themselves are borrowed only during each call. No host
* runtime or PATH search is performed. Every invocation stops Workers before
* cancelling its remaining tasks, then closes application/database resources.
*/
typedef struct {
DeverRtWireName key, ecosystem, entry, port, adapter, schema;
const DeverRtWireName *capabilities;
uint64_t capability_count;
const DeverRtWireName *operations;
uint64_t operation_count;
uint64_t timeout_ms;
} DeverRtExternalDefinition;
typedef struct {
DeverRtWireName path;
const uint8_t *bytes;
uint64_t len;
DeverRtWireName sha256;
uint8_t executable;
} DeverRtExternalResource;
uint32_t dever_rt_v1_external_prepare(const DeverRtWireName *digest,
const DeverRtExternalResource *resources,
uint64_t count, DeverRtBuffer *error);
/* start borrows an optional Text setting. call borrows three Text handles.
* Async poll uses the existing statuses; call success owns one Reply handle.
*/
DeverRtAsyncOp *dever_rt_v1_external_start(const DeverRtExternalDefinition *definition,
const void *setting, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_external_call(const void *key, const void *operation,
const void *payload, DeverRtBuffer *error);
/* Consumes Reply even on failure. Success owns identity and payload Texts.
* kind=0 is a result (empty identity), kind=1 is a declared-error candidate;
* the concrete compiler decoder still validates its exact identity/payload.
*/
uint32_t dever_rt_v1_external_reply_take(void *reply, uint8_t *kind,
void **identity, void **payload,
DeverRtBuffer *error);
void dever_rt_v1_external_reply_release(void *reply);
DeverRtAsyncOp *dever_rt_v1_external_shutdown(void);
void dever_rt_v1_external_cause_append(void **cause, const void *message);
uint32_t dever_rt_v1_external_root(const DeverRtAsyncFunction *function,
const void *input, void *output, void *fault,
void (*append_cause)(void *, const void *),
DeverRtBuffer *error);
typedef uint32_t (*DeverRtWireDecode)(const void *node, void *out, DeverRtBuffer *error);
typedef uint32_t (*DeverRtWireEncode)(const void *value, void *encoder, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_decode(const void *text, const DeverRtType *type, DeverRtWireDecode decode, void *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encode(const void *value, const DeverRtType *type, DeverRtWireEncode encode, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_is_null(const void *node, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_bool(const void *node, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_int(const void *node, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_float(const void *node, double *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_text(const void *node, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_bytes(const void *node, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_raw(const void *node, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_decimal(const void *node, DeverRtDecimal *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_uuid(const void *node, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_secret(const void *node, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_datetime(const void *node, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_date(const void *node, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_time(const void *node, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_fields(const void *node, const DeverRtWireName *names, uint64_t count, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_field(const void *node, const DeverRtWireName *name, uint8_t required, const void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_list_len(const void *node, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_node_list_at(const void *node, int64_t index, const void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_null(void *encoder, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_bool(void *encoder, uint8_t value, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_int(void *encoder, int64_t value, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_float(void *encoder, double value, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_text(void *encoder, const void *text, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_bytes(void *encoder, const void *bytes, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_json(void *encoder, const void *text, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_decimal(void *encoder, uint64_t low, uint64_t high, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_uuid(void *encoder, const void *uuid, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_datetime(void *encoder, int64_t value, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_date(void *encoder, int64_t value, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_time(void *encoder, int64_t value, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_begin_array(void *encoder, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_begin_object(void *encoder, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_key(void *encoder, const DeverRtWireName *name, DeverRtBuffer *error);
uint32_t dever_rt_v1_wire_encoder_end(void *encoder, DeverRtBuffer *error);
/* CMD top-level input uses the existing Inputs contract: fields are consumed
* in checked parameter order, with unknown names rejected after decoding.
* Inputs is an exclusive callback-scoped borrow and has no owner operations.
* cmd_input_field returns owned raw-JSON Text; it validates all output slots
* before removing a field, so a rejected call may be retried. cmd_decode drops
* a fully initialized concrete output if the final unknown-field check fails.
* Partial output cleanup on callback failure remains the decoder's duty. */
typedef uint32_t (*DeverRtCmdDecode)(void *inputs, void *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_cmd_decode(const void *text, const DeverRtType *type, DeverRtCmdDecode decode, void *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_cmd_input_field(void *inputs, const DeverRtWireName *name, uint8_t required, void **out, uint8_t *present, DeverRtBuffer *error);
/* Settings are private entry owners, loaded beside the executable through the
* existing setting.json contract. Select validates every output before lookup;
* only present=1 initializes the owned setting Text. No unselected Setting is
* decoded here. The caller releases Settings on every entry exit path. */
uint32_t dever_rt_v1_adapter_settings_load(void **out, DeverRtBuffer *error);
void dever_rt_v1_adapter_settings_release(const void *settings);
uint32_t dever_rt_v1_adapter_settings_validate_names(const void *settings, const DeverRtWireName *names, uint64_t count, DeverRtBuffer *error);
uint32_t dever_rt_v1_adapter_settings_select(const void *settings, const DeverRtWireName *identity, const DeverRtWireName *candidates, uint64_t count, int64_t *index, void **setting, uint8_t *present, DeverRtBuffer *error);
/* Database support is independently bundled with runtime-database and the
* selected runtime-sqlite/runtime-postgres drivers. Bind rows below are the
* existing database scalar codec, never source-language business values.
* All arrays/handles are borrowed through operation creation and copied there.
* SQL byte strings alone are immutable process-static compiler output.
* Regular database calls return 0 success, 1 initialized typed fault, 2 ABI
* error. Async operations use the ordinary async 0/1/2/3/4 contract. Every
* destination, including the fault slot, is checked before advancing work.
*/
typedef struct {
const DeverRtOwnedType *fault_type;
void (*pack)(uint32_t kind, const void *message, void *out_fault);
void (*append_cause)(void *fault, const void *message);
} DeverRtDbError;
/* Error kinds: Pool=0, PoolExhausted=1, Connection=2, Timeout=3, Cancelled=4,
* Database=5, Constraint=6, NotFound=7, InvalidData=8, Migration=9. */
typedef struct { DeverRtWireName sqlite, postgres; } DeverRtDbSql;
/* kinds: Null=0, Bool=1, Int=2, Float=3, Decimal=4, Text=5, Bytes=6, Uuid=7.
* Bool uses integer 0/1; Decimal uses precision/scale plus exact bits; the
* three handle kinds borrow their normal runtime owners. Other fields ignored. */
typedef struct {
uint32_t kind, precision, scale;
int64_t integer;
double floating;
DeverRtDecimal decimal;
const void *handle;
} DeverRtDbValue;
typedef struct {
const DeverRtWireName *explicit_name;
DeverRtWireName package_root;
uint8_t tenant_scoped;
} DeverRtDbBinding;
typedef struct { const DeverRtDbBinding *bindings; uint64_t count; } DeverRtDbTransactionBindings;
typedef struct {
DeverRtWireName name, type;
uint8_t nullable, generated;
const DeverRtWireName *default_value, *rename_from;
} DeverRtDbField;
typedef struct {
DeverRtWireName name;
const DeverRtWireName *fields;
uint64_t count;
uint8_t unique;
} DeverRtDbIndex;
typedef struct {
DeverRtWireName name, revision;
const DeverRtWireName *drops;
uint64_t count;
} DeverRtDbMigration;
typedef struct {
DeverRtDbSql sql;
const DeverRtDbValue *parameters;
uint64_t count;
} DeverRtDbSeed;
typedef struct {
DeverRtWireName name;
uint32_t phase; /* Before=0, After=1 */
DeverRtDbSeed statement;
} DeverRtDbDataMigration;
typedef struct {
DeverRtWireName name, definition, sql_type;
const DeverRtWireName *default_value;
} DeverRtDbPostgresColumn;
typedef struct { DeverRtWireName name, definition; uint8_t foreign_key; } DeverRtDbPostgresConstraint;
typedef struct {
DeverRtWireName model, table, revision, seed_revision;
const DeverRtDbField *fields; uint64_t field_count;
const DeverRtDbIndex *indexes; uint64_t index_count;
const DeverRtDbMigration *migrations; uint64_t migration_count;
DeverRtDbSql create_table;
DeverRtWireName create_temporary_table;
const DeverRtDbSql *create_indexes; uint64_t create_index_count;
const DeverRtDbPostgresColumn *postgres_columns; uint64_t postgres_column_count;
const DeverRtDbPostgresConstraint *postgres_constraints; uint64_t postgres_constraint_count;
const DeverRtDbSeed *seeds; uint64_t seed_count;
const DeverRtDbDataMigration *data_migrations; uint64_t data_migration_count;
} DeverRtDbModel;
typedef struct {
const DeverRtOwnedType *row_type;
uint32_t (*decode)(const void *row, void *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
} DeverRtDbRowDecoder;
/* Application root closes the published session after child Scope drain and
* before runtime destruction. The compiler releases/zeros its session and
* database globals only after this call returns. Cleanup preserves primary
* faults and uses append_cause; callbacks may not fail or unwind. */
uint32_t dever_rt_v1_db_application_root(const DeverRtAsyncFunction *function, const void *input, void *out, void *fault, void *const *session_slot, const DeverRtDbError *errors, DeverRtBuffer *error);
void dever_rt_v1_db_cause_append(void **cause_text, const void *message);
uint32_t dever_rt_v1_db_session_new(const DeverRtDbBinding *bindings, uint64_t count, const DeverRtDbTransactionBindings *transactions, uint64_t transaction_count, void **out, DeverRtBuffer *error);
void dever_rt_v1_db_session_release(void *session);
DeverRtAsyncOp *dever_rt_v1_db_prepare(const void *session, const DeverRtDbError *errors, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_select(const void *session, const DeverRtDbBinding *binding, void **out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
void *dever_rt_v1_db_retain(const void *database);
void dever_rt_v1_db_release(void *database);
uint32_t dever_rt_v1_db_max_page_size(const void *database, int64_t *out, DeverRtBuffer *error);
/* Startup order matches native: stable sort by resolved database name, migrate
* every Model, then install foreign keys. Per-model descriptors retain spans. */
DeverRtAsyncOp *dever_rt_v1_db_migrate_models(const void *const *databases, const DeverRtDbModel *models, const DeverRtDbError *const *errors, uint64_t count, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_db_begin(const void *database, const DeverRtDbError *errors, DeverRtBuffer *error);
void *dever_rt_v1_db_transaction_retain(const void *transaction);
void dever_rt_v1_db_transaction_release(void *transaction);
/* finish takes the transaction's shared inner owner on its first poll. The
* handle itself remains borrowed; success/error/cancellation cannot reuse it. */
DeverRtAsyncOp *dever_rt_v1_db_finish(const void *transaction, uint8_t commit, const DeverRtDbError *errors, DeverRtBuffer *error);
/* On non-NULL creation, moves the complete primary fault into the operation.
* NULL creation does not consume it. Completion always returns that typed
* fault, augmented only if rollback fails; cancellation drops it once. */
DeverRtAsyncOp *dever_rt_v1_db_rollback_take(const void *transaction, void *primary_fault, const DeverRtOwnedType *primary_type, const DeverRtDbError *errors, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_db_execute(const void *database, const void *transaction, const DeverRtDbSql *sql, const DeverRtDbValue *parameters, uint64_t count, const DeverRtDbError *errors, DeverRtBuffer *error);
/* maximum=0 selects unbounded query; positive maximum reuses query_bounded. */
DeverRtAsyncOp *dever_rt_v1_db_query(const void *database, const void *transaction, const DeverRtDbSql *sql, const DeverRtDbValue *parameters, uint64_t count, int64_t maximum, const DeverRtDbError *errors, DeverRtBuffer *error);
/* Prefix/before_limit/suffix are process-static SQL fragments. */
DeverRtAsyncOp *dever_rt_v1_db_relation_query(const void *database, const void *transaction, const DeverRtWireName *prefix, const DeverRtWireName *before_limit, const DeverRtWireName *suffix, const int64_t *ids, uint64_t count, int64_t limit, const DeverRtDbError *errors, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_db_stream(const void *database, const void *transaction, const DeverRtDbSql *sql, const DeverRtDbValue *parameters, uint64_t count, int64_t capacity, const DeverRtDbRowDecoder *decoder, const DeverRtDbError *errors, DeverRtBuffer *error);
void *dever_rt_v1_db_stream_retain(const void *stream);
void dever_rt_v1_db_stream_release(void *stream);
uint32_t dever_rt_v1_db_stream_close(const void *stream, uint8_t *out, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_db_stream_pull(const void *stream, const DeverRtDbError *errors, DeverRtBuffer *error);
void dever_rt_v1_db_rows_release(void *rows);
uint32_t dever_rt_v1_db_rows_len(const void *rows, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_rows_at(const void *rows, int64_t index, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_required_row(const void *rows, const DeverRtWireName *operation, void **out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_optional_row(const void *rows, const DeverRtWireName *operation, void **out, uint8_t *present, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
void dever_rt_v1_db_row_release(void *row);
uint32_t dever_rt_v1_db_row_len(const void *row, int64_t *out, DeverRtBuffer *error);
/* Related uses indirection for recursive Model associations. NULL is Unloaded;
* a non-NULL owner contains one concrete Loaded row, including nullable rows. */
uint32_t dever_rt_v1_db_related_new(const DeverRtType *type, const void *value, void **out, DeverRtBuffer *error);
void *dever_rt_v1_db_related_retain(const void *related);
void dever_rt_v1_db_related_release(void *related);
uint8_t dever_rt_v1_db_related_equal(const void *left, const void *right);
uint32_t dever_rt_v1_db_related_get(const void *related, void *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_null(const void *row, int64_t index, uint8_t *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_bool(const void *row, int64_t index, uint8_t *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_int(const void *row, int64_t index, int64_t *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_float(const void *row, int64_t index, double *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_decimal(const void *row, int64_t index, DeverRtDecimal *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_text(const void *row, int64_t index, void **out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_bytes(const void *row, int64_t index, void **out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_row_uuid(const void *row, int64_t index, void **out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_uuid_new(void **out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_error(uint32_t kind, const void *message, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_pagination(int64_t page, int64_t size, int64_t maximum, int64_t *out_page, int64_t *out_size, int64_t *out_offset, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_cursor_size(int64_t size, int64_t maximum, int64_t *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_stream_capacity(int64_t size, int64_t maximum, int64_t *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
uint32_t dever_rt_v1_db_relation_limit(int64_t maximum, int64_t *out, const DeverRtDbError *errors, void *fault, DeverRtBuffer *error);
/* Application descriptors are compiler-owned process-static metadata. Decode
* borrows Inputs only for its synchronous call; success initializes a complete
* typed input, failure drops its own partial input. Runtime finish rejects any
* trailing fields before calling the concrete handler. Handler success returns
* exactly one owned Text containing checked JSON. Typed failures remain owned
* by runtime until the static status callback has inspected them.
*/
typedef struct {
const DeverRtAsyncFunction *asynchronous;
const DeverRtSyncFunction *synchronous;
const DeverRtOwnedType *input_type;
uint32_t (*decode)(void *inputs, int64_t detail_id, void *out, DeverRtBuffer *error);
int64_t (*fault_status)(const void *fault);
/* Optional; only status 400 may expose this borrowed Text as an input error. */
const void *(*fault_message)(const void *fault);
} DeverRtApiHandler;
typedef struct {
const DeverRtAsyncFunction *asynchronous;
const DeverRtSyncFunction *synchronous;
const DeverRtOwnedType *input_type;
uint32_t (*pack)(const void *subject, const void *session, const void *nullable_tenant, const void *site, void *out, DeverRtBuffer *error);
uint32_t (*unpack)(const void *identity, void **id, int64_t *user_id, uint8_t *user_present, int64_t *tenant_id, uint8_t *tenant_present, DeverRtBuffer *error);
int64_t (*fault_status)(const void *fault);
} DeverRtApiAuth;
typedef struct {
DeverRtWireName key, component, domain, site, action, method;
} DeverRtApiPermission;
typedef struct {
DeverRtWireName method, path;
const DeverRtWireName *directory;
uint64_t directory_count;
const DeverRtWireName *components;
uint64_t component_count;
const DeverRtApiPermission *permission;
const DeverRtApiAuth *auth;
const DeverRtApiHandler *handler;
uint8_t anonymous, multipart, detail;
} DeverRtApiRoute;
typedef struct {
const void *path, *domain;
int64_t same_site; /* 0 Strict, 1 Lax, 2 None */
uint8_t secure, http_only;
int64_t max_age;
uint8_t max_age_present;
} DeverRtApiCookieOptions;
uint32_t dever_rt_v1_api_application_root(const DeverRtAsyncFunction *function, const void *input, void *out, void *fault, void *const *session_slot, void (*append_cause)(void *fault, const void *text), DeverRtBuffer *error);
uint32_t dever_rt_v1_api_session_new(const DeverRtDbBinding *bindings, uint64_t count, const DeverRtDbTransactionBindings *transactions, uint64_t transaction_count, void **out, DeverRtBuffer *error);
void dever_rt_v1_api_session_release(void *session);
uint32_t dever_rt_v1_api_session_database(const void *session, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_has_tenant(const void *session, uint8_t *out, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_initialize(const void *session, const DeverRtWireName *fingerprint, const DeverRtApiPermission *permissions, uint64_t count, uint8_t service_start, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_serve(const void *session, const DeverRtApiRoute *routes, uint64_t count, const DeverRtWireName *tenant_components, uint64_t component_count, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_tenant_scope(int64_t tenant_id, const DeverRtAsyncFunction *function, const void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_require_components(const void *session, const DeverRtWireName *components, uint64_t count, const DeverRtWireName *manifest, uint64_t manifest_count, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_migrate_models(const void *session, const DeverRtDbBinding *bindings, const DeverRtDbModel *models, const DeverRtDbError *const *errors, uint64_t count, int64_t tenant_id, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_migrate_application(const void *session, const DeverRtDbBinding *bindings, const DeverRtDbModel *models, const DeverRtDbError *const *errors, uint64_t count, const DeverRtDbError *fallback_errors, int64_t tenant_id, DeverRtBuffer *error);
/* Job metadata is immutable compiler output. The handler reuses the typed API
* callable layout, but decode borrows a persisted payload Text and detail_id=0;
* decode status 1 means invalid payload, and success initializes its concrete
* input. Job handler success is Unit (size 0, align 1), never a dynamic value.
* The registry owns its bindings and Clock within one application Session.
*/
typedef struct {
DeverRtWireName target, schema;
uint32_t attempts, timeout_ms;
const DeverRtWireName *schedule;
const DeverRtDbBinding *binding;
const DeverRtWireName *components;
uint64_t component_count;
const DeverRtApiHandler *handler;
} DeverRtJob;
typedef struct { DeverRtWireName provider; const DeverRtApiAuth *auth; } DeverRtJobAuth;
uint32_t dever_rt_v1_job_session_new(const void *session, const void *clock, const DeverRtJob *jobs, uint64_t count, const DeverRtJobAuth *auth, uint64_t auth_count, const DeverRtApiPermission *permissions, uint64_t permission_count, const DeverRtWireName *components, uint64_t component_count, void **out, DeverRtBuffer *error);
void dever_rt_v1_job_session_release(void *jobs);
uint32_t dever_rt_v1_job_configure(const void *session, uint8_t api, uint8_t worker, DeverRtBuffer *error);
uint32_t dever_rt_v1_job_decode_unit(const void *payload, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_job_initialize(const void *jobs, const DeverRtDbError *errors, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_job_enqueue(const void *jobs, uint64_t index, const void *database, const void *transaction, const void *payload, const void *key, int64_t run_at, const DeverRtDbError *errors, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_job_drain(const void *jobs, int64_t limit, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_job_system_scope(int64_t tenant, uint8_t has_tenant, const DeverRtAsyncFunction *function, const void *input, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_serve_with_jobs(const void *session, const DeverRtApiRoute *routes, uint64_t count, const DeverRtWireName *components, uint64_t component_count, const void *jobs, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_tenant_owner(const void *session, int64_t tenant_id, const void *site, int64_t user_id, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_api_tenant_component(const void *session, int64_t tenant_id, const void *component, uint8_t enabled, const DeverRtWireName *manifest, uint64_t count, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_db_resolve_scoped(const void *session, const DeverRtDbBinding *binding, const DeverRtDbError *errors, DeverRtBuffer *error);
void dever_rt_v1_api_cause_append(void **cause, const void *message);
uint32_t dever_rt_v1_api_input_field(void *inputs, const DeverRtWireName *name, uint8_t required, uint32_t query_kind, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_input_raw_field(void *inputs, const DeverRtWireName *name, uint8_t required, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_input_upload(void *inputs, const DeverRtWireName *name, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_text_bounds(const DeverRtWireName *name, const void *nullable_text, int64_t minimum, int64_t maximum, uint8_t has_maximum, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_pagination(int64_t page, int64_t size, int64_t maximum, int64_t *out_page, int64_t *out_size, int64_t *out_offset, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_request_id(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_method(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_path(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_client_address(void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_header(const void *name, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_cookie(const void *name, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_secret_cookie(const void *name, void **out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_response_header(const void *name, const void *value, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_response_cookie(const void *name, const void *value, const DeverRtApiCookieOptions *options, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_api_response_secret_cookie(const void *name, const void *value, const DeverRtApiCookieOptions *options, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_site_key(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_id(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_session(void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_user_id(int64_t *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_tenant_id(int64_t *out, uint8_t *present, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_owns_user(int64_t user_id, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_issue(const void *subject, const void *session, const void *nullable_tenant, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_issue_cookie(const void *subject, const void *session, const void *nullable_tenant, uint8_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_auth_clear_cookie(uint8_t *out, DeverRtBuffer *error);
typedef void (*DeverRtPackPermission)(const void *key, const void *component, const void *domain, const void *site, const void *action, const void *method, void *out);
DeverRtAsyncOp *dever_rt_v1_auth_permissions(const DeverRtType *element, DeverRtPackPermission pack, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_auth_save_role(const void *id, const void *name, uint8_t all_permissions, const void *permission_keys, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_auth_grant_role(int64_t user_id, const void *role, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_auth_revoke_role(int64_t user_id, const void *role, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_auth_disable_role(const void *role, DeverRtBuffer *error);
void *dever_rt_v1_upload_retain(const void *upload);
void dever_rt_v1_upload_release(void *upload);
uint32_t dever_rt_v1_upload_filename(const void *upload, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_upload_content_type(const void *upload, void **out, DeverRtBuffer *error);
uint32_t dever_rt_v1_upload_size(const void *upload, int64_t *out, DeverRtBuffer *error);
uint32_t dever_rt_v1_upload_close_take(void *upload, uint8_t *out, DeverRtBuffer *error);
DeverRtAsyncOp *dever_rt_v1_upload_store_take(void *upload, DeverRtBuffer *error);
#ifdef __cplusplus
}
#endif
#endif
+154
View File
@@ -0,0 +1,154 @@
// Private LLVM 18 / LLD bridge. Inputs are borrowed only for the call; outputs
// use malloc/free through one ABI and never expose LLVM ownership to Rust.
#include "lld/Common/Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include <cstdlib>
#include <cstring>
#include <mutex>
LLD_HAS_DRIVER(elf)
LLD_HAS_DRIVER(coff)
LLD_HAS_DRIVER(macho)
struct Reply {
unsigned char *bytes;
size_t len;
uint32_t status;
};
struct Resource {
const unsigned char *symbol;
size_t symbol_len;
const unsigned char *bytes;
size_t len;
};
static void answer(Reply *reply, llvm::StringRef bytes, uint32_t status) {
constexpr size_t limit = 320 * 1024 * 1024;
if (bytes.size() > limit) {
bytes = "compiler bridge output exceeds 320 MiB";
status = 1;
}
reply->status = status;
reply->len = bytes.size();
reply->bytes = static_cast<unsigned char *>(std::malloc(bytes.size()));
if (!reply->bytes && !bytes.empty()) {
reply->len = 0;
reply->status = 1;
return;
}
if (!bytes.empty()) std::memcpy(reply->bytes, bytes.data(), bytes.size());
}
extern "C" void dever_backend_free(unsigned char *bytes) { std::free(bytes); }
extern "C" void dever_backend_object(const unsigned char *ir, size_t len,
const char *triple, const Resource *resources,
size_t resource_count, Reply *reply) {
try {
static std::once_flag initialized;
std::call_once(initialized, [] {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
});
llvm::LLVMContext context;
llvm::SMDiagnostic diagnostic;
auto input = llvm::MemoryBuffer::getMemBufferCopy(
llvm::StringRef(reinterpret_cast<const char *>(ir), len), "dever.ir");
auto module = llvm::parseIR(input->getMemBufferRef(), diagnostic, context);
std::string error;
llvm::raw_string_ostream errors(error);
if (!module) {
diagnostic.print("dever", errors);
return answer(reply, error, 1);
}
// Do not silently compile a module for a target different from its ABI.
if (!module->getTargetTriple().empty() && module->getTargetTriple() != triple)
return answer(reply, "LLVM module target disagrees with selected target", 1);
for (size_t index = 0; index < resource_count; ++index) {
const auto &resource = resources[index];
auto *global = module->getNamedGlobal(llvm::StringRef(
reinterpret_cast<const char *>(resource.symbol), resource.symbol_len));
auto *array = global ? llvm::dyn_cast<llvm::ArrayType>(global->getValueType()) : nullptr;
if (!global || !global->isDeclaration() || !global->isConstant() ||
!global->hasExternalLinkage() || global->isThreadLocal() ||
global->getAddressSpace() != 0 || !array ||
!array->getElementType()->isIntegerTy(8) ||
array->getNumElements() != resource.len || global->use_empty())
return answer(reply, "LLVM resource must match a used external constant byte-array declaration", 1);
global->setInitializer(llvm::ConstantDataArray::get(
context, llvm::ArrayRef<uint8_t>(resource.bytes, resource.len)));
global->setLinkage(llvm::GlobalValue::PrivateLinkage);
}
if (llvm::verifyModule(*module, &errors)) return answer(reply, error, 1);
auto target = llvm::TargetRegistry::lookupTarget(triple, error);
if (!target) return answer(reply, error, 1);
llvm::TargetOptions options;
std::unique_ptr<llvm::TargetMachine> machine(target->createTargetMachine(
triple, "generic", "", options, llvm::Reloc::PIC_, std::nullopt,
llvm::CodeGenOptLevel::Default));
if (!machine) return answer(reply, "LLVM target machine is unavailable", 1);
auto layout = machine->createDataLayout();
if (!module->getDataLayoutStr().empty() && module->getDataLayout() != layout)
return answer(reply, "LLVM module layout disagrees with selected target", 1);
module->setTargetTriple(triple);
module->setDataLayout(layout);
llvm::PassBuilder passes(machine.get());
llvm::LoopAnalysisManager loops;
llvm::FunctionAnalysisManager functions;
llvm::CGSCCAnalysisManager calls;
llvm::ModuleAnalysisManager modules;
passes.registerModuleAnalyses(modules);
passes.registerCGSCCAnalyses(calls);
passes.registerFunctionAnalyses(functions);
passes.registerLoopAnalyses(loops);
passes.crossRegisterProxies(loops, functions, calls, modules);
auto pipeline = passes.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O2);
pipeline.run(*module, modules);
if (llvm::verifyModule(*module, &errors)) return answer(reply, error, 1);
llvm::SmallVector<char, 0> output;
llvm::raw_svector_ostream stream(output);
llvm::legacy::PassManager emission;
if (machine->addPassesToEmitFile(emission, stream, nullptr,
llvm::CodeGenFileType::ObjectFile))
return answer(reply, "LLVM target cannot emit native objects", 1);
emission.run(*module);
answer(reply, llvm::StringRef(output.data(), output.size()), 0);
} catch (const std::exception &error) {
answer(reply, error.what(), 1);
} catch (...) {
answer(reply, "LLVM bridge failed", 1);
}
}
extern "C" void dever_backend_link(const char *const *args, size_t count,
Reply *reply) {
try {
std::string output, error;
llvm::raw_string_ostream out(output), err(error);
const lld::DriverDef drivers[] = {{lld::Gnu, lld::elf::link},
{lld::WinLink, lld::coff::link},
{lld::Darwin, lld::macho::link}};
auto result = lld::lldMain(llvm::ArrayRef(args, count), out, err, drivers);
// LLD explicitly forbids cleanup/re-entry after failed crash recovery.
// This bridge belongs to a compiler worker, never an application process.
if (!result.canRunAgain) lld::exitLld(result.retCode ? result.retCode : 1);
answer(reply, error, result.retCode == 0 ? 0 : 1);
} catch (const std::exception &) {
lld::exitLld(1);
} catch (...) {
lld::exitLld(1);
}
}
File diff suppressed because it is too large. Load diff
+310
View File
@@ -0,0 +1,310 @@
//! Private compiler bridge. LLVM/LLD handles never escape the safe interface.
//! This crate is not the HIR lowerer and does not expose language FFI.
/// Runtime packs must match the versioned symbols in include/runtime.h.
pub const RUNTIME_ABI_VERSION: u32 = 1;
#[cfg(any(feature = "embedded", feature = "runtime-abi"))]
mod ffi;
#[cfg(feature = "runtime-abi")]
pub use dever_runtime::abi::DecimalBits as AbiDecimal;
#[cfg(feature = "runtime-abi")]
pub const ABI_OK: u32 = 0;
#[cfg(feature = "runtime-abi")]
pub const ABI_RUNTIME_ERROR: u32 = 1;
#[cfg(feature = "runtime-abi")]
pub const ABI_INVALID_INPUT: u32 = 2;
/// The six release targets; target selection never consults host defaults.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Target {
LinuxX86_64,
LinuxAarch64,
MacosX86_64,
MacosAarch64,
WindowsX86_64,
WindowsAarch64,
}
impl Target {
pub const ALL: [Self; 6] = [
Self::LinuxX86_64,
Self::LinuxAarch64,
Self::MacosX86_64,
Self::MacosAarch64,
Self::WindowsX86_64,
Self::WindowsAarch64,
];
pub fn triple(self) -> &'static str {
match self {
Self::LinuxX86_64 => "x86_64-unknown-linux-gnu",
Self::LinuxAarch64 => "aarch64-unknown-linux-gnu",
Self::MacosX86_64 => "x86_64-apple-macosx11.0.0",
Self::MacosAarch64 => "arm64-apple-macosx11.0.0",
Self::WindowsX86_64 => "x86_64-pc-windows-msvc",
Self::WindowsAarch64 => "aarch64-pc-windows-msvc",
}
}
}
/// Parse, verify, optimize and emit a position-independent native object.
/// Errors are LLVM diagnostics, not successful empty artifacts.
#[cfg(feature = "embedded")]
pub fn emit_object(ir: &str, target: Target) -> Result<Vec<u8>, String> {
emit_object_with_resources(ir, target, &[])
}
/// A borrowed immutable initializer for one declared byte-array global.
#[derive(Clone, Copy, Debug)]
pub struct BinaryResource<'a> {
pub symbol: &'a str,
pub bytes: &'a [u8],
}
/// Attach binary payloads before verification and optimization, without text encoding.
#[cfg(feature = "embedded")]
pub fn emit_object_with_resources(
ir: &str,
target: Target,
resources: &[BinaryResource<'_>],
) -> Result<Vec<u8>, String> {
if ir.is_empty() || ir.len() > 8 * 1024 * 1024 {
return Err("LLVM IR must contain 1..8388608 bytes".into());
}
if ir.as_bytes().contains(&0) {
return Err("LLVM IR must escape NUL bytes".into());
}
if resources.len() > 4096 {
return Err("LLVM resources exceed 4096 attachments".into());
}
let mut total = 0usize;
let mut symbols = std::collections::BTreeSet::new();
for resource in resources {
if resource.symbol.is_empty()
|| resource.symbol.len() > 256
|| !resource.symbol.bytes().enumerate().all(|(index, byte)| {
byte == b'_' || byte.is_ascii_alphabetic() || (index > 0 && byte.is_ascii_digit())
})
{
return Err("LLVM resource requires an unquoted symbol name".into());
}
if !symbols.insert(resource.symbol) {
return Err("duplicate LLVM resource symbol".into());
}
if resource.bytes.len() > 128 * 1024 * 1024 {
return Err("LLVM resource exceeds 128 MiB".into());
}
total = total
.checked_add(resource.bytes.len())
.ok_or("LLVM resource size overflow")?;
if total > 256 * 1024 * 1024 {
return Err("LLVM resources exceed 256 MiB".into());
}
}
ffi::emit_object(ir, target, resources)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LinkKind {
Executable,
/// Standard CRT entry with explicit archives; never search host shared libraries.
StaticExecutable,
Shared,
}
/// Inputs are explicit object/archive/import-library paths supplied by the
/// compiler's verified pack owner. LLD cannot search host library directories.
/// Output must be new and below a compiler-owned private build directory.
/// An unrecoverable LLD crash terminates the private compiler worker rather
/// than allowing cleanup or another call into potentially corrupted state.
#[cfg(feature = "embedded")]
pub fn link(
target: Target,
kind: LinkKind,
inputs: &[std::path::PathBuf],
output: &std::path::Path,
entry: Option<&str>,
) -> Result<(), String> {
use std::ffi::CString;
if inputs.is_empty() || inputs.len() > 4096 {
return Err("link requires 1..4096 explicit inputs".into());
}
let parent = output
.parent()
.ok_or("link output has no parent")?
.canonicalize()
.map_err(|error| format!("link output directory: {error}"))?;
verify_link_directory(&parent)?;
let output = parent.join(output.file_name().ok_or("link output has no filename")?);
let mut args = link_arguments(target, kind, entry)?;
args.extend(output_arguments(target, &output)?);
for input in inputs {
let path = input
.canonicalize()
.map_err(|error| format!("link input: {error}"))?;
if !path.is_file() {
return Err("link input is not a regular file".into());
}
args.push(
path.to_str()
.ok_or("link input path must be UTF-8")?
.to_owned(),
);
}
let args = args
.into_iter()
.map(CString::new)
.collect::<Result<Vec<_>, _>>()
.map_err(|_| "link argument contains NUL")?;
// Claim the new output before entering the serialized linker. Concurrent
// callers cannot both pass a check-then-create and overwrite each other.
let mut create = std::fs::OpenOptions::new();
create.write(true).create_new(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
create.mode(0o600);
}
drop(
create
.open(&output)
.map_err(|error| format!("cannot reserve new link output: {error}"))?,
);
let result = ffi::link(&args);
// Only our new output is eligible for failure cleanup, never input packs.
if result.is_err()
&& let Err(error) = std::fs::remove_file(&output)
&& error.kind() != std::io::ErrorKind::NotFound
{
return Err(format!(
"{}; link output cleanup: {error}",
result.unwrap_err()
));
}
result
}
#[cfg(all(feature = "embedded", unix))]
fn verify_link_directory(directory: &std::path::Path) -> Result<(), String> {
use std::os::unix::fs::MetadataExt;
let uid = rustix::process::geteuid().as_raw();
for (index, ancestor) in directory.ancestors().enumerate() {
let metadata = ancestor
.symlink_metadata()
.map_err(|error| format!("cannot inspect link directory: {error}"))?;
if !metadata.is_dir() || !matches!(metadata.uid(), owner if owner == uid || owner == 0) {
return Err("link directory has an untrusted ancestor".into());
}
let mode = metadata.mode();
if index == 0 && (metadata.uid() != uid || mode & 0o077 != 0) {
return Err("link output requires a compiler-owned private directory".into());
}
// Sticky OS temp roots protect our owned entry. A writable non-sticky
// ancestor would permit another UID to rename an otherwise private leaf.
if mode & 0o022 != 0 && mode & 0o1000 == 0 {
return Err("link directory has a publicly writable ancestor".into());
}
}
Ok(())
}
#[cfg(all(feature = "embedded", not(unix)))]
fn verify_link_directory(_: &std::path::Path) -> Result<(), String> {
Err("compiler-private link directory verification is unavailable on this host".into())
}
#[cfg(feature = "embedded")]
fn output_arguments(target: Target, output: &std::path::Path) -> Result<Vec<String>, String> {
let output = output.to_str().ok_or("link output path must be UTF-8")?;
Ok(match target {
Target::WindowsX86_64 | Target::WindowsAarch64 => vec![format!("/out:{output}")],
_ => vec!["-o".into(), output.into()],
})
}
#[cfg(feature = "embedded")]
fn link_arguments(
target: Target,
kind: LinkKind,
entry: Option<&str>,
) -> Result<Vec<String>, String> {
if let Some(entry) = entry
&& (entry.is_empty()
|| !entry
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || byte == b'_'))
{
return Err("link entry must be a symbol name".into());
}
let args: &[&str] = match target {
Target::LinuxX86_64 => &["ld.lld", "-m", "elf_x86_64", "--no-undefined"],
Target::LinuxAarch64 => &["ld.lld", "-m", "aarch64linux", "--no-undefined"],
Target::MacosX86_64 => &[
"ld64.lld",
"-arch",
"x86_64",
"-platform_version",
"macos",
"11.0",
"11.0",
],
Target::MacosAarch64 => &[
"ld64.lld",
"-arch",
"arm64",
"-platform_version",
"macos",
"11.0",
"11.0",
],
Target::WindowsX86_64 => &[
"lld-link",
"/machine:x64",
"/nodefaultlib",
"/subsystem:console",
],
Target::WindowsAarch64 => &[
"lld-link",
"/machine:arm64",
"/nodefaultlib",
"/subsystem:console",
],
};
let mut args = args
.iter()
.map(|arg| (*arg).into())
.collect::<Vec<String>>();
match (target, kind) {
(Target::LinuxX86_64 | Target::LinuxAarch64, LinkKind::StaticExecutable) => {
args.extend([
"-static".into(),
"--gc-sections".into(),
"--strip-all".into(),
]);
}
(_, LinkKind::StaticExecutable) => {
return Err("static executable runtime packs currently require a Linux target".into());
}
(Target::LinuxX86_64 | Target::LinuxAarch64, LinkKind::Shared) => {
args.push("-shared".into())
}
(Target::MacosX86_64 | Target::MacosAarch64, LinkKind::Shared) => {
args.push("-dylib".into())
}
(Target::WindowsX86_64 | Target::WindowsAarch64, LinkKind::Shared) => {
args.extend(["/dll".into(), "/noentry".into()]);
}
_ => {}
}
if let Some(entry) = entry {
match target {
Target::WindowsX86_64 | Target::WindowsAarch64 => args.push(format!("/entry:{entry}")),
_ => args.extend(["-e".into(), entry.into()]),
}
}
Ok(args)
}