bones_scripting/lua/
ext.rs

1use super::{
2    bindings::{EcsRef, SchemaLuaEcsRefMetatable},
3    *,
4};
5
6/// Extension trait for the [`Context`] that makes it easier to access our lua singletons.
7pub trait CtxExt {
8    /// Get a reference to the lua singletons.
9    fn singletons(&self) -> &LuaSingletons;
10}
11impl CtxExt for piccolo::Context<'_> {
12    fn singletons(&self) -> &LuaSingletons {
13        let Value::UserData(data) = self.globals().get(*self, "luasingletons") else {
14            unreachable!();
15        };
16        data.downcast_static::<LuaSingletons>().unwrap()
17    }
18}
19
20/// Helper trait to get a singleton fn pointer for the metatable for a type.
21pub trait MetatableFn {
22    fn metatable_fn(&self) -> fn(piccolo::Context) -> piccolo::Table;
23}
24impl MetatableFn for SchemaRef<'_> {
25    fn metatable_fn(&self) -> fn(piccolo::Context) -> piccolo::Table {
26        self.schema()
27            .type_data
28            .get::<SchemaLuaEcsRefMetatable>()
29            .map(|x| x.0)
30            .unwrap_or(bindings::ecsref::metatable)
31    }
32}
33impl MetatableFn for SchemaRefMut<'_> {
34    fn metatable_fn(&self) -> fn(piccolo::Context) -> piccolo::Table {
35        self.schema()
36            .type_data
37            .get::<SchemaLuaEcsRefMetatable>()
38            .map(|x| x.0)
39            .unwrap_or(bindings::ecsref::metatable)
40    }
41}
42impl MetatableFn for EcsRef {
43    /// Get the function that may be used to retrieve the metatable to use for this [`EcsRef`].
44    fn metatable_fn(&self) -> fn(piccolo::Context) -> piccolo::Table {
45        (|| {
46            let b = self.borrow();
47            Some(b.schema_ref().ok()?.metatable_fn())
48        })()
49        .unwrap_or(bindings::ecsref::metatable)
50    }
51}
52
53/// Extension trait on top of [`Value`] to add helper functions.
54pub trait ValueExt<'gc> {
55    /// Convert to a static user data type.
56    fn as_static_user_data<T: 'static>(&self) -> Result<&'gc T, piccolo::TypeError>;
57}
58impl<'gc> ValueExt<'gc> for Value<'gc> {
59    fn as_static_user_data<T: 'static>(&self) -> Result<&'gc T, piccolo::TypeError> {
60        if let Value::UserData(t) = self {
61            Ok(t.downcast_static().map_err(|_| piccolo::TypeError {
62                expected: std::any::type_name::<T>(),
63                found: "other user data",
64            })?)
65        } else {
66            Err(piccolo::TypeError {
67                expected: std::any::type_name::<T>(),
68                found: "other lua value",
69            })
70        }
71    }
72}