code_native/abi.rs
1//! Vendored copy of `code-abi`'s C-ABI contract.
2//!
3//! `code-abi` is the canonical, single source of truth for this ABI (used
4//! directly by the host runtime: `native_module.rs`, `wasm_module.rs`), but it
5//! stays unpublished (`publish = false`) on purpose. `code-native` — the
6//! authoring SDK for native modules — needs to be publishable to crates.io on
7//! its own, and crates.io rejects packages with a path dependency on an
8//! unpublished crate.
9//!
10//! This file is therefore a literal, mechanically-kept-in-sync copy of
11//! `crates/code-abi/src/lib.rs`. **Do not hand-edit it** — edit `code-abi`,
12//! then copy its `src/lib.rs` here verbatim (only the header comment and the
13//! crate-level `#![no_std]` attribute differ, since this is a module, not its
14//! own crate). `tests/abi_in_sync.rs` fails the build if the two diverge.
15
16use core::ffi::{c_char, c_void};
17
18// ===========================================================================
19// ABI version + target constants
20// ===========================================================================
21
22/// Current ABI version. Native modules must return this from
23/// `code_module_abi_version`.
24pub const CODE_ABI_VERSION: u32 = 2;
25
26/// Emission target: dispatch to the linking module's base handlers.
27pub const CODE_EMIT_TARGET_BASE: u32 = 0;
28
29// ===========================================================================
30// Value tag constants (must match the codegen tags)
31// ===========================================================================
32
33pub const CODE_TAG_NUMBER: u8 = 0;
34pub const CODE_TAG_STRING: u8 = 1;
35pub const CODE_TAG_BOOLEAN: u8 = 2;
36pub const CODE_TAG_OBJECT: u8 = 3;
37pub const CODE_TAG_NULL: u8 = 4;
38pub const CODE_TAG_ARRAY: u8 = 5;
39
40// ===========================================================================
41// C-ABI struct definitions (repr(C) — mirrored in code_abi.h)
42// ===========================================================================
43
44/// A single Code value in C-ABI representation.
45///
46/// Active fields depend on `tag`:
47/// - `CODE_TAG_NUMBER` → `number`
48/// - `CODE_TAG_STRING` → `string` (null-terminated UTF-8 C string)
49/// - `CODE_TAG_BOOLEAN` → `boolean` (0 = false, non-zero = true)
50/// - `CODE_TAG_OBJECT` → `fields` + `field_count`
51/// - `CODE_TAG_NULL` → (no data)
52/// - `CODE_TAG_ARRAY` → `elements` + `element_count`
53#[repr(C)]
54pub struct CodeValue {
55 pub tag: u8,
56 pub number: f64,
57 pub string: *const c_char,
58 pub boolean: u8,
59 pub fields: *const CodeField,
60 pub field_count: u32,
61 pub elements: *const CodeValue,
62 pub element_count: u32,
63}
64
65impl CodeValue {
66 /// Create a null `CodeValue` with all fields zeroed.
67 pub fn null() -> Self {
68 CodeValue {
69 tag: CODE_TAG_NULL,
70 number: 0.0,
71 string: core::ptr::null(),
72 boolean: 0,
73 fields: core::ptr::null(),
74 field_count: 0,
75 elements: core::ptr::null(),
76 element_count: 0,
77 }
78 }
79}
80
81/// A key-value pair for object fields.
82#[repr(C)]
83pub struct CodeField {
84 pub name: *const c_char,
85 pub value: CodeValue,
86}
87
88// ---------------------------------------------------------------------------
89// Function / handler signatures
90// ---------------------------------------------------------------------------
91
92/// Native handler signature: `fn(particle) -> CodeValue`.
93pub type CodeNativeHandlerFn = unsafe extern "C" fn(particle: CodeValue) -> CodeValue;
94
95/// Callback signature for native-module emission.
96pub type CodeEmitFn = unsafe extern "C" fn(context: *mut c_void, particle: CodeValue);
97
98// ---------------------------------------------------------------------------
99// Export descriptor types
100// ---------------------------------------------------------------------------
101
102/// Exported variable: name + constant value.
103#[repr(C)]
104pub struct CodeExportVar {
105 pub name: *const c_char,
106 pub value: CodeValue,
107}
108
109/// Exported handler: class name + handler function.
110#[repr(C)]
111pub struct CodeExportHandler {
112 pub class_name: *const c_char,
113 pub handler: CodeNativeHandlerFn,
114}
115
116/// Field descriptor for type declarations.
117#[repr(C)]
118pub struct CodeTypeField {
119 pub name: *const c_char,
120 /// Type name as C string, e.g. "String", "Number".
121 pub type_name: *const c_char,
122 /// 0 = required, non-zero = optional.
123 pub is_optional: u8,
124}
125
126/// Exported type declaration.
127#[repr(C)]
128pub struct CodeExportType {
129 pub name: *const c_char,
130 pub fields: *const CodeTypeField,
131 pub field_count: u32,
132}
133
134/// Emission declaration exported by a native module.
135#[repr(C)]
136pub struct CodeEmission {
137 pub class_name: *const c_char,
138 /// 0 = base (dispatch to linking module's handlers).
139 pub target: u32,
140}
141
142/// Top-level module descriptor returned by `code_module_init()`.
143#[repr(C)]
144pub struct CodeModuleDesc {
145 pub abi_version: u32,
146 pub vars: *const CodeExportVar,
147 pub var_count: u32,
148 pub handlers: *const CodeExportHandler,
149 pub handler_count: u32,
150 pub types: *const CodeExportType,
151 pub type_count: u32,
152 pub emissions: *const CodeEmission,
153 pub emission_count: u32,
154}
155
156// ---------------------------------------------------------------------------
157// Safety: these types contain raw pointers but are only used as immutable
158// descriptors shared across threads. The module init function is called once
159// and the data is read-only after that.
160// ---------------------------------------------------------------------------
161
162unsafe impl Sync for CodeValue {}
163unsafe impl Send for CodeValue {}
164unsafe impl Sync for CodeField {}
165unsafe impl Send for CodeField {}
166unsafe impl Sync for CodeExportVar {}
167unsafe impl Send for CodeExportVar {}
168unsafe impl Sync for CodeExportHandler {}
169unsafe impl Send for CodeExportHandler {}
170unsafe impl Sync for CodeTypeField {}
171unsafe impl Send for CodeTypeField {}
172unsafe impl Sync for CodeExportType {}
173unsafe impl Send for CodeExportType {}
174unsafe impl Sync for CodeEmission {}
175unsafe impl Send for CodeEmission {}
176unsafe impl Sync for CodeModuleDesc {}
177unsafe impl Send for CodeModuleDesc {}