Skip to main content

devela/code/ops/call/
semantics.rs

1// devela/src/code/ops/call/semantics.rs
2//
3//! Structural axes for reasoning about invocation semantics and dispatch
4//
5// TOC
6// - struct CallSemantics
7// - enum CallBindTime
8// - enum CallContext
9// - enum CallDispatch
10// - enum CallOpenness
11// - enum CallStorage
12
13use crate::Ordering;
14
15#[doc = crate::_tags!(exec)]
16/// Structural semantics of a call edge.
17#[doc = crate::_doc_meta!{location("core/ops")}]
18///
19/// The axes describe how a call is bound, dispatched, contextualized,
20/// and represented; not merely the callable value itself.
21///
22/// Effective behavior arises at the invocation boundary as the combination of:
23/// - the callable's intrinsic semantics, and
24/// - the dispatcher or container semantics.
25///
26/// Ordered axes form a product partial order (ignoring `CallOpenness`).
27///
28/// ## Invocation Categories
29///
30/// All invocation reduces to one of:
31/// - Direct call
32/// - Branch-based dispatch
33/// - Indirect function pointer call
34/// - Vtable dispatch
35///
36/// Callable representations reduce to:
37/// - Function items
38/// - Enums (closed sets)
39/// - Function pointers
40/// - Trait objects
41/// - Type-erased closures
42#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
43pub struct CallSemantics {
44    /// When callee identity is fixed.
45    pub bind: CallBindTime,
46
47    /// Where the execution environment resides.
48    pub context: CallContext,
49
50    /// Mechanism of control transfer.
51    pub dispatch: CallDispatch,
52
53    /// Whether the behavior set is fixed or extensible.
54    pub open: CallOpenness,
55
56    /// Where the callable representation is stored.
57    pub storage: CallStorage,
58}
59impl PartialOrd for CallSemantics {
60    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
61        use Ordering::{Equal, Greater, Less};
62        let axes = [
63            self.bind.cmp(&other.bind),
64            self.dispatch.cmp(&other.dispatch),
65            self.context.cmp(&other.context),
66            self.storage.cmp(&other.storage),
67        ];
68        let mut less = false;
69        let mut greater = false;
70        for ord in axes {
71            match ord {
72                Less => less = true,
73                Greater => greater = true,
74                Equal => {}
75            }
76        }
77        match (less, greater) {
78            (true, true) => None, // incomparable
79            (true, false) => Some(Less),
80            (false, true) => Some(Greater),
81            (false, false) => Some(Equal),
82        }
83    }
84}
85
86#[doc = crate::_tags!(exec)]
87/// When the callee identity becomes fixed.
88#[doc = crate::_doc_meta!{location("core/ops")}]
89///
90/// Ordered: `Compile < Build < Run`.
91///
92/// Later binding increases runtime dynamism and reduces static visibility.
93#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
94pub enum CallBindTime {
95    /// Callee identity fixed by the compiler.
96    ///
97    /// Boundary: the call graph edge is known statically and may be inlined.
98    ///
99    /// Example: direct function call or monomorphized generic.
100    Compile = 0,
101
102    /// Callee selected by build-time fixed data.
103    ///
104    /// Boundary: selection occurs via branch on a closed set
105    /// (e.g. enum or bytecode), but cannot change without rebuilding.
106    Build = 1,
107
108    /// Callee selected by runtime-provided data.
109    ///
110    /// Boundary: changing runtime data alone can alter the invoked function
111    /// (e.g. function pointers or trait objects).
112    Run = 2,
113}
114
115#[doc = crate::_tags!(exec)]
116/// Where the callable's execution environment resides.
117#[doc = crate::_doc_meta!{location("core/ops")}]
118///
119/// Ordered: `None < Receiver < Captured`.
120///
121/// This axis describes structural coupling, not argument types.
122#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
123pub enum CallContext {
124    /// No distinguished execution environment.
125    ///
126    /// Boundary: all required inputs are ordinary parameters.
127    ///
128    /// Example: `fn add(a: u32, b: u32) -> u32`.
129    None = 0,
130
131    /// Execution environment supplied explicitly by the caller.
132    ///
133    /// Boundary: a persistent state object participates in the invocation
134    /// protocol (e.g. `&mut Vm`, `&World`, or `&self`).
135    Receiver = 1,
136
137    /// Execution environment embedded inside the callable object.
138    ///
139    /// Boundary: the callable owns or encloses state not provided at call site.
140    ///
141    /// Example: `move |x| acc + x`.
142    Captured = 2,
143}
144
145#[doc = crate::_tags!(exec)]
146/// Mechanism by which control transfers to the callee.
147#[doc = crate::_doc_meta!{location("core/ops")}]
148///
149/// Ordered: `Direct < Branch < Indirect < Vtable`.
150///
151/// Later variants introduce more indirection and reduce static visibility.
152#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
153pub enum CallDispatch {
154    /// Statically resolved call.
155    ///
156    /// Boundary: the call site encodes the callee directly.
157    Direct = 0,
158
159    /// Selection among a finite set via conditional branch.
160    ///
161    /// Boundary: dispatch occurs by matching a discriminant.
162    Branch = 1,
163
164    /// Call via function pointer.
165    ///
166    /// Boundary: callee address is loaded from memory at runtime.
167    Indirect = 2,
168
169    /// Dynamic dispatch via trait object.
170    ///
171    /// Boundary: method pointer resolved through a vtable.
172    Vtable = 3,
173}
174
175#[doc = crate::_tags!(exec)]
176/// Whether the behavior set is fixed or extensible.
177#[doc = crate::_doc_meta!{location("core/ops")}]
178///
179/// Not ordered.
180#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
181pub enum CallOpenness {
182    /// Behavior universe fixed at build time.
183    ///
184    /// Boundary: new behaviors require recompilation.
185    Closed = 0,
186
187    /// Behavior universe extensible at runtime.
188    ///
189    /// Boundary: new behaviors may be introduced without rebuilding.
190    Open = 1,
191}
192
193#[doc = crate::_tags!(exec)]
194/// Where the callable representation resides.
195#[doc = crate::_doc_meta!{location("core/ops")}]
196///
197/// Ordered: `Static < Inline < Arena < Heap`.
198///
199/// Later variants increase allocation dynamism and indirection.
200#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
201pub enum CallStorage {
202    /// Representation baked into the binary.
203    ///
204    /// Boundary: no allocation and program-long lifetime.
205    Static = 0,
206
207    /// Stored inline with known size.
208    ///
209    /// Boundary: concrete layout known at compile time.
210    Inline = 1,
211
212    /// Stored in type-erased managed buffer.
213    ///
214    /// Boundary: size erased; lifetime managed externally.
215    Arena = 2,
216
217    /// Stored in heap allocation.
218    ///
219    /// Boundary: allocation-managed memory.
220    Heap = 3,
221}