bones_scripting/lua/bindings/
schema.rs1use super::*;
2
3pub(super) struct WithoutSchema(pub &'static Schema);
6
7pub fn schema_fn(ctx: Context) -> Callback {
8 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
9 let singletons = ctx.singletons();
10 let schema_metatable = singletons.get(ctx, schema::metatable);
11
12 let schema_name = stack.pop_front();
13 let Value::String(schema_name) = schema_name else {
14 return Err(anyhow::format_err!("Type error: expected string schema name").into());
15 };
16 let mut matches = SCHEMA_REGISTRY.schemas.iter().filter(|schema| {
17 schema.name.as_bytes() == schema_name.as_bytes()
18 || schema.full_name.as_bytes() == schema_name.as_bytes()
19 });
20
21 if let Some(next_match) = matches.next() {
22 if matches.next().is_some() {
23 return Err(anyhow::format_err!("Found multiple schemas matching name.").into());
24 }
25
26 let schema = UserData::new_static(&ctx, next_match);
28 schema.set_metatable(&ctx, Some(schema_metatable));
29 stack.push_front(schema.into());
30 } else {
31 #[cfg(not(debug_assertions))] return Err(anyhow::format_err!("Schema not found: {schema_name}").into());
33
34 #[cfg(debug_assertions)] return Err(anyhow::format_err!(
36 "Schema not found: {schema_name}, you may need to register the schema"
37 )
38 .into());
39 }
40
41 Ok(CallbackReturn::Return)
42 })
43}
44
45pub fn schema_of_fn(ctx: Context) -> Callback {
46 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
47 let singletons = ctx.singletons();
48 let schema_metatable = singletons.get(ctx, schema::metatable);
49
50 let ecsref: &EcsRef = stack.consume(ctx)?;
51 let schema = ecsref.borrow().schema_ref()?.schema();
52
53 let schema = UserData::new_static(&ctx, schema);
54 schema.set_metatable(&ctx, Some(schema_metatable));
55 stack.replace(ctx, schema);
56
57 Ok(CallbackReturn::Return)
58 })
59}
60
61pub fn metatable(ctx: Context) -> Table {
62 let metatable = Table::new(&ctx);
63 metatable
64 .set(
65 ctx,
66 "__tostring",
67 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
68 let this: UserData = stack.consume(ctx)?;
69 let this = this.downcast_static::<&Schema>()?;
70 let s = piccolo::String::from_slice(&ctx, format!("Schema({})", this.full_name));
71
72 stack.push_front(Value::String(s));
73 Ok(CallbackReturn::Return)
74 }),
75 )
76 .unwrap();
77 let create_fn = ctx.registry().stash(
78 &ctx,
79 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
80 let this: UserData = stack.consume(ctx)?;
81 let this = this.downcast_static::<&Schema>()?;
82
83 let ecsref = EcsRef {
84 data: EcsRefData::Free(Rc::new(AtomicCell::new(SchemaBox::default(this)))),
85 path: default(),
86 }
87 .into_value(ctx);
88 stack.push_front(ecsref);
89
90 Ok(CallbackReturn::Return)
91 }),
92 );
93
94 let without_fn = ctx.registry().stash(
95 &ctx,
96 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
97 let this: UserData = stack.consume(ctx)?;
98 let this = this.downcast_static::<&Schema>()?;
99 stack.replace(ctx, UserData::new_static(&ctx, WithoutSchema(this)));
100 Ok(CallbackReturn::Return)
101 }),
102 );
103
104 let eq_fn = Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
105 let (this, other): (UserData, UserData) = stack.consume(ctx)?;
106 let (this, other) = (
107 this.downcast_static::<&Schema>()?,
108 other.downcast_static::<&Schema>()?,
109 );
110 stack.replace(ctx, this.id() == other.id());
111 Ok(CallbackReturn::Return)
112 });
113
114 metatable.set(ctx, "__eq", eq_fn).unwrap();
115 metatable
116 .set(
117 ctx,
118 "__index",
119 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
120 let (this, key): (UserData, lua::String) = stack.consume(ctx)?;
121 let this = this.downcast_static::<&Schema>()?;
122
123 match key.as_bytes() {
124 b"name" => {
125 stack.replace(
126 ctx,
127 Value::String(piccolo::String::from_static(&ctx, this.name.as_bytes())),
128 );
129 }
130 b"full_name" => {
131 stack.replace(
132 ctx,
133 Value::String(piccolo::String::from_static(
134 &ctx,
135 this.full_name.as_bytes(),
136 )),
137 );
138 }
139 b"create" => stack.replace(ctx, ctx.registry().fetch(&create_fn)),
140 b"without" => stack.replace(ctx, ctx.registry().fetch(&without_fn)),
141 _ => (),
142 }
143
144 Ok(CallbackReturn::Return)
145 }),
146 )
147 .unwrap();
148
149 metatable
150}