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 return Err(anyhow::format_err!("Schema not found: {schema_name}").into());
32 }
33
34 Ok(CallbackReturn::Return)
35 })
36}
37
38pub fn schema_of_fn(ctx: Context) -> Callback {
39 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
40 let singletons = ctx.singletons();
41 let schema_metatable = singletons.get(ctx, schema::metatable);
42
43 let ecsref: &EcsRef = stack.consume(ctx)?;
44 let schema = ecsref.borrow().schema_ref()?.schema();
45
46 let schema = UserData::new_static(&ctx, schema);
47 schema.set_metatable(&ctx, Some(schema_metatable));
48 stack.replace(ctx, schema);
49
50 Ok(CallbackReturn::Return)
51 })
52}
53
54pub fn metatable(ctx: Context) -> Table {
55 let metatable = Table::new(&ctx);
56 metatable
57 .set(
58 ctx,
59 "__tostring",
60 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
61 let this: UserData = stack.consume(ctx)?;
62 let this = this.downcast_static::<&Schema>()?;
63 let s = piccolo::String::from_slice(&ctx, format!("Schema({})", this.full_name));
64
65 stack.push_front(Value::String(s));
66 Ok(CallbackReturn::Return)
67 }),
68 )
69 .unwrap();
70 let create_fn = ctx.registry().stash(
71 &ctx,
72 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
73 let this: UserData = stack.consume(ctx)?;
74 let this = this.downcast_static::<&Schema>()?;
75
76 let ecsref = EcsRef {
77 data: EcsRefData::Free(Rc::new(AtomicCell::new(SchemaBox::default(this)))),
78 path: default(),
79 }
80 .into_value(ctx);
81 stack.push_front(ecsref);
82
83 Ok(CallbackReturn::Return)
84 }),
85 );
86
87 let without_fn = ctx.registry().stash(
88 &ctx,
89 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
90 let this: UserData = stack.consume(ctx)?;
91 let this = this.downcast_static::<&Schema>()?;
92 stack.replace(ctx, UserData::new_static(&ctx, WithoutSchema(this)));
93 Ok(CallbackReturn::Return)
94 }),
95 );
96
97 let eq_fn = Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
98 let (this, other): (UserData, UserData) = stack.consume(ctx)?;
99 let (this, other) = (
100 this.downcast_static::<&Schema>()?,
101 other.downcast_static::<&Schema>()?,
102 );
103 stack.replace(ctx, this.id() == other.id());
104 Ok(CallbackReturn::Return)
105 });
106
107 metatable.set(ctx, "__eq", eq_fn).unwrap();
108 metatable
109 .set(
110 ctx,
111 "__index",
112 Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
113 let (this, key): (UserData, lua::String) = stack.consume(ctx)?;
114 let this = this.downcast_static::<&Schema>()?;
115
116 match key.as_bytes() {
117 b"name" => {
118 stack.replace(
119 ctx,
120 Value::String(piccolo::String::from_static(&ctx, this.name.as_bytes())),
121 );
122 }
123 b"full_name" => {
124 stack.replace(
125 ctx,
126 Value::String(piccolo::String::from_static(
127 &ctx,
128 this.full_name.as_bytes(),
129 )),
130 );
131 }
132 b"create" => stack.replace(ctx, ctx.registry().fetch(&create_fn)),
133 b"without" => stack.replace(ctx, ctx.registry().fetch(&without_fn)),
134 _ => (),
135 }
136
137 Ok(CallbackReturn::Return)
138 }),
139 )
140 .unwrap();
141
142 metatable
143}