runmat_runtime/native/
site.rs1use super::{NativeCall, NativeExit, NativeHostStatus};
2use std::ffi::c_void;
3
4#[repr(transparent)]
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct NativeSitePhase(pub u32);
7
8impl NativeSitePhase {
9 pub const RVALUE: Self = Self(0);
10 pub const STATEMENT: Self = Self(1);
11 pub const TERMINATOR_RVALUE: Self = Self(2);
12 pub const TERMINATOR: Self = Self(3);
13
14 pub const fn is_known(self) -> bool {
15 self.0 <= Self::TERMINATOR.0
16 }
17}
18
19#[repr(C)]
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26pub struct NativeSiteRequest {
27 pub function: u32,
28 pub block: u32,
29 pub position: u32,
30 pub phase: NativeSitePhase,
31 pub ordinal: u32,
32 pub reserved: u32,
33}
34
35#[repr(transparent)]
36#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub struct NativeSiteOutcomeKind(pub u32);
38
39impl NativeSiteOutcomeKind {
40 pub const CONTINUE: Self = Self(0);
42 pub const EDGE: Self = Self(1);
44 pub const EXIT: Self = Self(2);
46
47 pub const fn is_known(self) -> bool {
48 self.0 <= Self::EXIT.0
49 }
50}
51
52#[repr(C)]
58#[derive(Clone, Copy, Debug, Eq, PartialEq)]
59pub struct NativeSiteOutcome {
60 pub kind: NativeSiteOutcomeKind,
61 pub edge: u32,
62 pub flags: u32,
63 pub reserved: u32,
64}
65
66impl NativeSiteOutcome {
67 pub const fn continue_execution() -> Self {
68 Self::new(NativeSiteOutcomeKind::CONTINUE, 0)
69 }
70
71 pub const fn edge(edge: u32) -> Self {
72 Self::new(NativeSiteOutcomeKind::EDGE, edge)
73 }
74
75 pub const fn exit() -> Self {
76 Self::new(NativeSiteOutcomeKind::EXIT, 0)
77 }
78
79 const fn new(kind: NativeSiteOutcomeKind, edge: u32) -> Self {
80 Self {
81 kind,
82 edge,
83 flags: 0,
84 reserved: 0,
85 }
86 }
87}
88
89pub type NativeExecuteSiteFn = unsafe extern "C" fn(
97 context: *mut c_void,
98 call: *mut NativeCall,
99 request: *const NativeSiteRequest,
100 outcome: *mut NativeSiteOutcome,
101 exit: *mut NativeExit,
102) -> NativeHostStatus;
103
104impl NativeSiteRequest {
105 pub fn validate(&self) -> Result<(), super::NativeAbiError> {
106 if !self.phase.is_known() {
107 return Err(super::NativeAbiError::new(
108 "native.site.phase",
109 "site phase is unknown",
110 ));
111 }
112 if self.reserved != 0 {
113 return Err(super::NativeAbiError::new(
114 "native.site.reserved",
115 "reserved bits must be zero for this ABI revision",
116 ));
117 }
118 Ok(())
119 }
120}
121
122impl NativeSiteOutcome {
123 pub fn validate(&self) -> Result<(), super::NativeAbiError> {
124 if !self.kind.is_known() {
125 return Err(super::NativeAbiError::new(
126 "native.site_outcome.kind",
127 "site outcome kind is unknown",
128 ));
129 }
130 if self.flags != 0 || self.reserved != 0 {
131 return Err(super::NativeAbiError::new(
132 "native.site_outcome.reserved",
133 "flags and reserved bits must be zero for this ABI revision",
134 ));
135 }
136 if self.kind != NativeSiteOutcomeKind::EDGE && self.edge != 0 {
137 return Err(super::NativeAbiError::new(
138 "native.site_outcome.edge",
139 "only an edge outcome may carry an edge index",
140 ));
141 }
142 Ok(())
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
151 #[cfg_attr(not(target_arch = "wasm32"), test)]
152 fn site_identity_and_outcomes_reject_reserved_or_ambiguous_states() {
153 let request = NativeSiteRequest {
154 function: 7,
155 block: 3,
156 position: 2,
157 phase: NativeSitePhase::STATEMENT,
158 ordinal: 1,
159 reserved: 0,
160 };
161 assert_eq!(request.validate(), Ok(()));
162 assert_eq!(NativeSiteOutcome::continue_execution().validate(), Ok(()));
163 assert_eq!(NativeSiteOutcome::edge(4).validate(), Ok(()));
164 assert_eq!(NativeSiteOutcome::exit().validate(), Ok(()));
165
166 let invalid_request = NativeSiteRequest {
167 phase: NativeSitePhase(u32::MAX),
168 ..request
169 };
170 assert_eq!(
171 invalid_request.validate().unwrap_err().field,
172 "native.site.phase"
173 );
174
175 let invalid_outcome = NativeSiteOutcome {
176 kind: NativeSiteOutcomeKind::CONTINUE,
177 edge: 1,
178 flags: 0,
179 reserved: 0,
180 };
181 assert_eq!(
182 invalid_outcome.validate().unwrap_err().field,
183 "native.site_outcome.edge"
184 );
185 }
186}