Skip to main content

runmat_runtime/native/
call.rs

1use super::{NativeExit, NativeFrame, NativeHostVTable, NativeValueRef};
2
3#[repr(transparent)]
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub struct NativeCallKind(pub u32);
6
7impl NativeCallKind {
8    pub const DIRECT: Self = Self(0);
9    pub const DYNAMIC: Self = Self(1);
10    pub const BUILTIN: Self = Self(2);
11    pub const METHOD: Self = Self(3);
12    pub const CALLBACK: Self = Self(4);
13    pub const RESUME: Self = Self(5);
14
15    pub const fn is_known(self) -> bool {
16        self.0 <= Self::RESUME.0
17    }
18}
19
20/// One borrowed call transaction. Results are committed only when the returned
21/// `NativeExit` is `Completed`; all other exits leave host-visible outputs unset.
22#[repr(C)]
23#[derive(Clone, Copy, Debug)]
24pub struct NativeCall {
25    pub abi_version: u32,
26    pub kind: NativeCallKind,
27    pub flags: u32,
28    pub requested_outputs: u32,
29    pub host: *const NativeHostVTable,
30    pub frame: *mut NativeFrame,
31    pub arguments: *const NativeValueRef,
32    pub argument_count: usize,
33    pub results: *mut NativeValueRef,
34    pub result_capacity: usize,
35}
36
37impl Default for NativeCall {
38    fn default() -> Self {
39        Self {
40            abi_version: super::NATIVE_ABI_VERSION.encoded(),
41            kind: NativeCallKind::DIRECT,
42            flags: 0,
43            requested_outputs: 0,
44            host: std::ptr::null(),
45            frame: std::ptr::null_mut(),
46            arguments: std::ptr::null(),
47            argument_count: 0,
48            results: std::ptr::null_mut(),
49            result_capacity: 0,
50        }
51    }
52}
53
54impl NativeCall {
55    /// Validate the transactional result produced for this call.
56    ///
57    /// Native code may write result slots speculatively, but the host commits
58    /// them only for a completed exit that fits the requested result window.
59    pub fn validate_exit(&self, exit: &NativeExit) -> Result<(), super::NativeAbiError> {
60        self.validate()?;
61        exit.validate()?;
62        if exit.kind == super::NativeExitKind::COMPLETED {
63            if exit.produced_outputs > self.requested_outputs
64                || exit.produced_outputs as usize > self.result_capacity
65            {
66                return Err(super::NativeAbiError::new(
67                    "native.exit.produced_outputs",
68                    "completed outputs exceed the call result window",
69                ));
70            }
71        } else if exit.produced_outputs != 0 {
72            return Err(super::NativeAbiError::new(
73                "native.exit.produced_outputs",
74                "non-completed exits cannot commit outputs",
75            ));
76        }
77        Ok(())
78    }
79}