Callbacks
Callback signatures, `RawPtr` user data, and the current native/hybrid callback rules.
Callbacks are a supported part of the current FFI design.
Current Rules
- callback typedefs lower to real native function pointers
- callback arguments can be passed directly to native or extern functions
- callback targets must currently resolve to
@Nativefunctions or extern callback symbols - user data/context is passed explicitly as
RawPtr - captured closures do not cross the ABI boundary
- Kira-owned persistent callback state uses
nativeState,nativeUserData, andnativeRecover(any)
Minimal Example
From examples/callbacks/app/main.kira:
import callbacks as cb
struct CounterState {
var count: Int
var total: Int
}
@Main
function main() {
print("callbacks")
var state = nativeState(CounterState {
count: 0
total: 0
})
var token = nativeUserData(state)
print(run_native(token, 5))
print(run_native(token, 7))
var recovered = nativeRecover(token)
print(recovered.count)
print(recovered.total)
return
}
@Native
function run_native(user_data: RawPtr, value: I64) -> I64 {
return cb.kira_invoke_callback(add_and_track, user_data, value)
}
@Native
function add_and_track(value: I64, user_data: RawPtr) -> I64 {
var state = nativeRecover(user_data)
state.count = state.count + 1
state.total = state.total + value
return value + state.count
}That flow matters because it proves a real opaque-userdata contract:
- Kira owns the callback state storage
- native code only carries a
RawPtrtoken - the callback recovers the original typed state instead of reaching for globals
- repeated callback invocations mutate the same persistent stored state
It is backed by a small C header and implementation:
- a callback typedef
- a function that accepts the callback and invokes it
Signature Checking
Kira validates callback signatures at semantic-analysis time.
If the target function does not match the required callback type exactly, the repo currently raises:
KSEM045- title:
invalid callback signature
The checks include:
- parameter count
- parameter types
- result type
- execution compatibility
Runtime functions cannot currently be converted into native callback targets.
Native And Hybrid Support
The callback path is proved in both:
- native-only execution
- hybrid execution
That is why the repo carries both:
tests/pass/run/ffi_callback_nativetests/pass/run/ffi_callback_hybridtests/pass/run/ffi_callback_state_parity
For hybrid mode, the callback still crosses a native boundary. The runtime/native bridge handles marshalling around that call path.