1use std::{
4 any::Any,
5 fmt,
6 ops::{Deref, DerefMut},
7 sync::Arc,
8};
9
10use anyhow::bail;
11use arrayvec::ArrayVec;
12use bump_scope::BumpScope;
13use snafu::Snafu;
14
15use crate::{
16 Address, AsErasedContext, BuiltinDef, CallArgs, EntityRef, ErasedEntityHandle, ExecutionCtx,
17 FunctionRef, MAX_ARGS, QCMemory, QCParams, Type, Value, function_args,
18 progs::{VmScalar, VmValue},
19};
20
21type ErasedAddr = u16;
22
23#[derive(Snafu, Debug, Copy, Clone, PartialEq, Eq)]
25pub enum AddrError<E> {
26 OutOfRange,
28 Other {
30 error: E,
32 },
33}
34
35impl<E> From<E> for AddrError<E> {
36 fn from(value: E) -> Self {
37 Self::Other { error: value }
38 }
39}
40
41impl<E> AddrError<E>
42where
43 E: fmt::Display,
44{
45 pub(crate) fn into_anyhow(self) -> AddrError<anyhow::Error> {
46 {
47 match self {
48 Self::OutOfRange => AddrError::OutOfRange,
49 Self::Other { error: e } => AddrError::Other {
50 error: anyhow::format_err!("{e}"),
51 },
52 }
53 }
54 }
55}
56
57pub trait Context {
59 type Entity: ?Sized + EntityHandle<Context = Self>;
63 type Function: ?Sized + Function<Context = Self>;
65 type Error: std::error::Error;
67 type GlobalAddr: Address;
69
70 fn builtin(&self, def: &BuiltinDef) -> Result<Arc<Self::Function>, Self::Error>;
72
73 fn global(&self, def: Self::GlobalAddr) -> Result<Value, AddrError<Self::Error>>;
75
76 fn state(&self, _frame: f32, _think_fn: Arc<dyn ErasedFunction>) -> Result<(), Self::Error> {
85 unimplemented!("`OP_STATE` not available in this environment");
86 }
87
88 fn set_global(
90 &mut self,
91 def: Self::GlobalAddr,
92 value: Value,
93 ) -> Result<(), AddrError<Self::Error>>;
94}
95
96pub trait ErasedContext: Any {
98 fn dyn_builtin(&self, def: &BuiltinDef) -> anyhow::Result<Arc<dyn ErasedFunction>>;
100
101 fn dyn_state(&self, _frame: f32, _think_fn: Arc<dyn ErasedFunction>) -> anyhow::Result<()> {
103 anyhow::bail!("`OP_STATE` not available in this environment")
104 }
105
106 fn dyn_entity_get(
108 &self,
109 erased_ent: EntityRef,
110 field: ErasedAddr,
111 ty: Type,
112 ) -> anyhow::Result<Value, AddrError<anyhow::Error>>;
113
114 fn dyn_entity_set(
116 &mut self,
117 erased_ent: EntityRef,
118 field: ErasedAddr,
119 value: Value,
120 ) -> anyhow::Result<(), AddrError<anyhow::Error>>;
121
122 fn dyn_global(&self, def: ErasedAddr, ty: Type) -> Result<Value, AddrError<anyhow::Error>>;
124
125 fn dyn_set_global(
127 &mut self,
128 def: ErasedAddr,
129 value: Value,
130 ) -> Result<(), AddrError<anyhow::Error>>;
131}
132
133impl fmt::Debug for &'_ mut dyn ErasedContext {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 <&dyn ErasedContext>::fmt(&&**self, f)
136 }
137}
138
139impl fmt::Debug for &'_ dyn ErasedContext {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 write!(f, "..")
142 }
143}
144
145impl<T> ErasedContext for T
146where
147 T: Any + Context,
148 T::Function: Sized + ErasedFunction,
149{
150 fn dyn_builtin(&self, def: &BuiltinDef) -> anyhow::Result<Arc<dyn ErasedFunction>> {
151 Ok(self.builtin(def).map_err(|e| anyhow::format_err!("{e}"))? as Arc<dyn ErasedFunction>)
152 }
153
154 fn dyn_entity_get(
155 &self,
156 erased_ent: EntityRef,
157 field: ErasedAddr,
158 ty: Type,
159 ) -> anyhow::Result<Value, AddrError<anyhow::Error>> {
160 let field_addr =
161 <<T::Entity as EntityHandle>::FieldAddr as Address>::from_u16_typed(field, ty)
162 .ok_or(AddrError::OutOfRange)?;
163 <T::Entity as EntityHandle>::from_erased(erased_ent, |ent| ent.get(self, field_addr))
164 .map_err(|e| anyhow::format_err!("{e}"))?
165 .map_err(|e| AddrError::Other {
166 error: anyhow::format_err!("{e}"),
167 })
168 }
169
170 fn dyn_entity_set(
171 &mut self,
172 erased_ent: EntityRef,
173 field: ErasedAddr,
174 value: Value,
175 ) -> Result<(), AddrError<anyhow::Error>> {
176 let field_addr = <<T::Entity as EntityHandle>::FieldAddr as Address>::from_u16_typed(
177 field,
178 value.type_(),
179 )
180 .ok_or(AddrError::OutOfRange)?;
181 <T::Entity as EntityHandle>::from_erased(erased_ent, |ent| ent.set(self, field_addr, value))
182 .map_err(|e| anyhow::format_err!("{e}"))?
183 .map_err(|e| AddrError::Other {
184 error: anyhow::format_err!("{e}"),
185 })
186 }
187
188 fn dyn_global(&self, def: ErasedAddr, ty: Type) -> Result<Value, AddrError<anyhow::Error>> {
189 self.global(
190 <T as Context>::GlobalAddr::from_u16_typed(def, ty).ok_or(AddrError::OutOfRange)?,
191 )
192 .map_err(AddrError::into_anyhow)
193 }
194
195 fn dyn_set_global(
196 &mut self,
197 def: ErasedAddr,
198 value: Value,
199 ) -> Result<(), AddrError<anyhow::Error>> {
200 self.set_global(
201 <T as Context>::GlobalAddr::from_u16_typed(def, value.type_())
202 .ok_or(AddrError::OutOfRange)?,
203 value,
204 )
205 .map_err(AddrError::into_anyhow)
206 }
207}
208
209pub trait QCType: fmt::Debug {
213 fn type_(&self) -> Type;
215 fn is_null(&self) -> bool;
217}
218
219pub trait DynEq: Any {
221 fn dyn_eq(&self, other: &dyn Any) -> bool;
223 fn dyn_ne(&self, other: &dyn Any) -> bool {
225 !self.dyn_eq(other)
226 }
227}
228
229impl<T> DynEq for T
230where
231 T: PartialEq + Any,
232{
233 fn dyn_eq(&self, other: &dyn Any) -> bool {
234 other.downcast_ref().is_some_and(|other| self == other)
235 }
236
237 fn dyn_ne(&self, other: &dyn Any) -> bool {
238 other.downcast_ref().is_some_and(|other| self != other)
239 }
240}
241
242pub trait EntityHandle: QCType {
247 type Context: ?Sized + Context<Entity = Self>;
249 type Error: std::error::Error;
251 type FieldAddr: Address;
253
254 fn from_erased<F, O>(erased: EntityRef, callback: F) -> Result<O, Self::Error>
256 where
257 F: FnOnce(&Self) -> O,
258 {
259 Self::from_erased_mut(erased, |this| callback(&*this))
260 }
261
262 fn from_erased_mut<F, O>(erased: EntityRef, callback: F) -> Result<O, Self::Error>
264 where
265 F: FnOnce(&mut Self) -> O;
266
267 fn to_erased(&self) -> EntityRef;
269
270 fn get(
272 &self,
273 context: &Self::Context,
274 field: Self::FieldAddr,
275 ) -> Result<Value, AddrError<Self::Error>>;
276
277 fn set(
279 &self,
280 context: &mut Self::Context,
281 field: Self::FieldAddr,
282 value: Value,
283 ) -> Result<(), AddrError<Self::Error>>;
284}
285
286pub trait Function: QCType {
289 type Context: ?Sized + Context<Function = Self>;
291 type Error: std::error::Error;
293
294 fn signature(&self) -> Result<ArrayVec<Type, MAX_ARGS>, Self::Error>;
299
300 fn call(&self, context: FnCall<'_, Self::Context>) -> Result<Value, Self::Error>;
302}
303
304pub struct FnCall<'a, T: ?Sized = dyn ErasedContext> {
307 pub(crate) execution:
308 ExecutionCtx<'a, T, BumpScope<'a>, CallArgs<ArrayVec<[VmScalar; 3], MAX_ARGS>>>,
309}
310
311impl<T: ?Sized> Deref for FnCall<'_, T> {
312 type Target = T;
313
314 fn deref(&self) -> &Self::Target {
315 &*self.execution.context
316 }
317}
318
319impl<T: ?Sized> DerefMut for FnCall<'_, T> {
320 fn deref_mut(&mut self) -> &mut Self::Target {
321 &mut *self.execution.context
322 }
323}
324
325impl<T: ?Sized> FnCall<'_, T> {
326 pub fn context_mut(&mut self) -> &mut T {
329 self.execution.context
330 }
331}
332
333impl<T> FnCall<'_, T>
334where
335 T: ?Sized + AsErasedContext,
336{
337 pub fn arguments(&self, args: &[Type]) -> impl Iterator<Item = Value> {
342 function_args()
343 .into_iter()
344 .zip(args)
345 .map(|(i, ty)| match ty {
346 Type::Vector => {
347 let [x, y, z] = self.execution.memory.get_vector(i.addr as _).unwrap();
348 let vec = [
349 x.try_into().unwrap(),
350 y.try_into().unwrap(),
351 z.try_into().unwrap(),
352 ];
353 self.execution.to_value(VmValue::Vector(vec)).unwrap()
354 }
355 _ => {
356 let value = self.execution.memory.get(i.addr as _).unwrap().into();
357 self.execution.to_value(value).unwrap()
358 }
359 })
360 }
361}
362
363impl<'a> FnCall<'a, dyn ErasedContext> {
364 fn downcast<T>(self) -> Option<FnCall<'a, T>>
365 where
366 T: Any,
367 {
368 Some(FnCall {
369 execution: self.execution.downcast()?,
370 })
371 }
372}
373
374impl<'a, T> FnCall<'a, T>
375where
376 T: ErasedContext,
377{
378 pub fn call<A, F>(&mut self, function_ref: F, args: A) -> anyhow::Result<Value>
380 where
381 F: Into<FunctionRef>,
382 A: QCParams,
383 {
384 let function_def = self
385 .execution
386 .functions
387 .get(function_ref)?
388 .clone()
389 .try_into_qc()
390 .map_err(|def| {
391 anyhow::format_err!("Function {:?} is not a QuakeC function", def.name)
392 })?;
393
394 self.execution
395 .with_args(&function_def.name, args, |mut exec| {
396 Ok(exec.execute_def(&function_def)?.try_into()?)
397 })
398 }
399}
400
401pub trait ErasedFunction: QCType + Send + Sync + DynEq {
403 fn dyn_signature(&self) -> anyhow::Result<ArrayVec<Type, MAX_ARGS>>;
405
406 fn dyn_call<'a, 'b>(&'a self, context: FnCall<'b>) -> anyhow::Result<Value>;
408}
409
410impl PartialEq for dyn ErasedFunction {
411 fn eq(&self, other: &Self) -> bool {
412 self.dyn_eq(other)
413 }
414}
415
416impl QCType for ErasedEntityHandle {
417 fn type_(&self) -> Type {
418 Type::Entity
419 }
420
421 fn is_null(&self) -> bool {
422 false
423 }
424}
425
426impl<T> ErasedFunction for T
427where
428 T: Function + PartialEq + Any + Send + Sync,
429 T::Context: Sized,
430{
431 fn dyn_signature(&self) -> anyhow::Result<ArrayVec<Type, MAX_ARGS>> {
432 self.signature().map_err(|e| anyhow::format_err!("{e}"))
433 }
434
435 fn dyn_call(&self, context: FnCall) -> anyhow::Result<Value> {
436 let type_name = std::any::type_name_of_val(context.execution.context);
437 match context.downcast() {
438 Some(context) => Ok(self.call(context).map_err(|e| anyhow::format_err!("{e}"))?),
439 None => bail!(
440 "Type mismatch for builtin context: expected {}, found {}",
441 std::any::type_name::<T::Context>(),
442 type_name
443 ),
444 }
445 }
446}