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