1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//! Host-supplied opaque types referenced from Keleusma scripts.
//!
//! Opaque types are the surface for Rust values that Keleusma
//! scripts hold by reference without introspecting their internal
//! structure. The script-side surface is a named primitive type
//! (e.g. `MyHandle`) declared in function signatures; the runtime
//! representation is `Value::Opaque(Arc<dyn HostOpaque>)`. Native
//! functions registered by the host produce and consume opaque
//! values.
//!
//! ## Design choice: trait object over type parameter
//!
//! The dyn-free alternative is to parameterise `Value`, `Vm`,
//! `NativeCtx`, and the native-function-trait surface by a host
//! opaque type `O`. That approach is type-safe by construction but
//! propagates a type parameter through every public signature and
//! every implementation block in `bytecode.rs`, `vm.rs`,
//! `marshall.rs`, and every native registration call. The present
//! design uses a custom marker trait, [`HostOpaque`], behind an
//! `Arc<dyn HostOpaque>` reference. The trait is small: a name
//! method for diagnostics, a sealed-supertrait `TypeId` lookup,
//! and the standard `Send + Sync + 'static` bounds. Hosts implement
//! [`HostOpaque`] for any Rust type they wish to expose. Native
//! functions extract a typed reference via [`dyn HostOpaque::downcast_ref`]
//! which checks the dynamic type through a `TypeId` comparison
//! without invoking `core::any::Any`.
//!
//! ## Cross-yield discipline
//!
//! Opaque values are host-managed through `Arc` and have a
//! lifetime independent of the arena. They may appear in the
//! dialogue type at a yield, may flow into the data segment, and
//! survive arena resets and hot code swaps. The cross-yield
//! prohibition on [`crate::bytecode::Value::KStr`] does not apply
//! because the storage is not arena-resident.
//!
//! ## WCMU contribution
//!
//! Opaque values contribute zero to the script-side WCMU bound
//! because the allocation is host-managed. Hosts that want their
//! own opaque heap bounded supply a per-native attestation through
//! [`crate::vm::Vm::set_native_bounds`].
extern crate alloc;
use Arc;
use TypeId;
/// Implementation-detail supertrait that surfaces the host's
/// concrete `TypeId` through the trait object's vtable. A blanket
/// implementation covers every `'static` type, so hosts never
/// implement this trait directly.
///
/// The trait lives in a private module so external callers cannot
/// observe its method beyond the surface that [`HostOpaque`]
/// exposes through inherent methods on `dyn HostOpaque`.
/// Marker trait for host-managed opaque types referenced from
/// Keleusma scripts.
///
/// The host implements this trait for every Rust type it wishes to
/// expose to scripts as an opaque value. The trait carries only
/// the metadata Keleusma needs at the runtime boundary; the host's
/// type remains structurally opaque to the script.
///
/// ## Required methods
///
/// - [`type_name`](HostOpaque::type_name) returns the script-side
/// type name. The type checker matches this name against the
/// `Type::Opaque(name)` declared in function signatures.
///
/// ## Implicit methods
///
/// The sealed supertrait `sealed::HostOpaqueTypeId` supplies the
/// host's concrete `TypeId` through a blanket implementation. Hosts
/// do not implement it directly; any `'static + Send + Sync` type
/// that implements [`HostOpaque`] automatically participates.
///
/// ## Thread-safety bounds
///
/// `HostOpaque` requires `Send + Sync + 'static`. The `Send + Sync`
/// pair makes `Arc<dyn HostOpaque>` safe to share across threads;
/// hosts running in a single-threaded environment satisfy this
/// trivially. The `'static` bound rules out borrowed-data opaque
/// types because their lifetime is not statically bounded against
/// the script's reference lifetime through the VM.
/// Convenience wrapper for `Arc::new` that returns an opaque-typed
/// `Arc<dyn HostOpaque>` ready to drop into a [`crate::bytecode::Value::Opaque`].
///
/// Useful at native-function return sites where the host
/// constructs a new opaque value:
///
/// ```ignore
/// use keleusma::{Value, host_arc, HostOpaque};
///
/// struct MyState { /* ... */ }
/// impl HostOpaque for MyState {
/// fn type_name(&self) -> &'static str { "MyState" }
/// }
///
/// vm.register_fn("make_state", || -> Value {
/// Value::Opaque(host_arc(MyState { /* ... */ }))
/// });
/// ```