1use anyhow::Context;
2use mlua::{Either, FromLua, IntoLua, Lua};
3
4use crate::{
5 ext::TableSetFnExt, impl_enum_into_lua, impl_into_lua, versioning::RtkRustcDriverVersion,
6};
7
8pub trait RtkLuaScriptExecutor: Send + Sync + Clone + 'static {
9 fn intake_version(&self, version: RtkRustcDriverVersion);
11
12 fn intake_debug_version(&self, version: RtkRustcDriverVersion) {
14 self.intake_version(version);
15 }
16
17 fn query_method_calls(&self, query: MethodCallQuery) -> Vec<MethodCall>;
18 fn query_trait_impls(&self, query: Location) -> Vec<TraitImpl>;
19 fn query_functions(&self, query: Location) -> Vec<FunctionTypeValue>;
20 fn query_function_calls(&self, query: Location) -> Vec<FunctionCall>;
21
22 fn log_note(&self, msg: String);
23 fn log_warn(&self, msg: String);
24 fn log_error(&self, msg: String);
25 fn log_fatal_error(&self, msg: String) -> !;
26
27 fn emit(&self, text: String);
28}
29
30pub fn inject(
32 lua: &Lua,
33 table: &mlua::Table,
34 exec: impl RtkLuaScriptExecutor,
35) -> anyhow::Result<()> {
36 let intake_version_exec = exec.clone();
37
38 table
39 .set_rtk_api_fn(lua, "version", move |version: RtkRustcDriverVersion| {
40 intake_version_exec.intake_version(version);
41 mlua::Nil
42 })
43 .context("failed to set intake_version function")?;
44
45 let intake_debug_version_exec = exec.clone();
46 table
47 .set_rtk_api_fn(lua, "dbg_version", move |version: RtkRustcDriverVersion| {
48 intake_debug_version_exec.intake_debug_version(version);
49 mlua::Nil
50 })
51 .context("failed to set intake_debug_version function")?;
52
53 let note_exec = exec.clone();
54 table
55 .set_rtk_api_fn(lua, "note", move |msg: String| {
56 note_exec.log_note(msg);
57 mlua::Nil
58 })
59 .context("failed to set debug function")?;
60
61 let warn_exec = exec.clone();
62 table
63 .set_rtk_api_fn(lua, "warn", move |msg: String| {
64 warn_exec.log_warn(msg);
65 mlua::Nil
66 })
67 .context("failed to set warn function")?;
68
69 let error_exec = exec.clone();
70 table
71 .set_rtk_api_fn(lua, "error", move |msg: String| {
72 error_exec.log_error(msg);
73 mlua::Nil
74 })
75 .context("failed to set error function")?;
76
77 let fatal_error_exec = exec.clone();
78 table
79 .set_rtk_api_fn(lua, "fatal_error", move |msg: String| {
80 fatal_error_exec.log_fatal_error(msg);
81 #[allow(unreachable_code)]
83 mlua::Nil
84 })
85 .context("failed to set fatal_error function")?;
86
87 let query_method_calls_exec = exec.clone();
88 table
89 .set_rtk_api_fn(lua, "query_method_calls", move |query: MethodCallQuery| {
90 query_method_calls_exec.query_method_calls(query)
91 })
92 .context("failed to set query_method_calls function")?;
93
94 let query_trait_impls_exec = exec.clone();
95 table
96 .set_rtk_api_fn(lua, "query_trait_impls", move |query: Location| {
97 query_trait_impls_exec.query_trait_impls(query)
98 })
99 .context("failed to set query_trait_impls function")?;
100
101 let query_functions_exec = exec.clone();
102 table
103 .set_rtk_api_fn(lua, "query_functions", move |query: Location| {
104 query_functions_exec.query_functions(query)
105 })
106 .context("failed to set query_functions function")?;
107
108 let query_function_calls_exec = exec.clone();
109 table
110 .set_rtk_api_fn(lua, "query_function_calls", move |query: Location| {
111 query_function_calls_exec.query_function_calls(query)
112 })
113 .context("failed to set query_function_calls function")?;
114
115 let emit_exec = exec.clone();
116 table
117 .set_rtk_api_fn(lua, "emit", move |text: String| {
118 emit_exec.emit(text);
119 mlua::Nil
120 })
121 .context("failed to set emit function")?;
122
123 Ok(())
124}
125
126#[derive(Clone, Debug, PartialEq, Eq, Default)]
127pub struct Location {
128 pub crate_name: String,
129 pub path: Vec<String>,
130 pub impl_block_number: Option<usize>,
131}
132
133impl FromLua for Location {
134 fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
135 let table = value
136 .as_table()
137 .ok_or_else(|| mlua::Error::FromLuaConversionError {
138 from: "Value",
139 to: "Location".to_string(),
140 message: Some("expected a table".to_string()),
141 })?;
142
143 let crate_name: String = table.get("crate_name")?;
144 let path: Vec<String> = table.get("path")?;
145 let impl_block_number: Option<usize> = table.get("impl_block_number")?;
146
147 Ok(Location {
148 crate_name,
149 path,
150 impl_block_number,
151 })
152 }
153}
154
155impl_into_lua! {
156 Location {
157 crate_name,
158 path,
159 impl_block_number,
160 }
161}
162
163#[derive(Clone, Debug, Eq, PartialEq)]
166pub struct MethodCallQuery {
167 pub parent: Option<Box<MethodCallQuery>>,
175 pub location: Location,
177}
178
179impl_into_lua! {
180 MethodCallQuery {
181 parent => parent.map(|b| *b),
182 location,
183 }
184}
185
186impl FromLua for MethodCallQuery {
187 fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> mlua::Result<Self> {
188 let table = value
189 .as_table()
190 .ok_or_else(|| mlua::Error::FromLuaConversionError {
191 from: "Value",
192 to: "MethodCallQuery".to_string(),
193 message: Some("expected a table".to_string()),
194 })?;
195
196 let parent = match table.get("parent")? {
197 mlua::Nil => None,
198 t => Some(Box::new(Self::from_lua(t, _lua)?)),
199 };
200
201 let location: Location =
202 table
203 .get("location")
204 .map_err(|_| mlua::Error::FromLuaConversionError {
205 from: "Value",
206 to: "Location".to_string(),
207 message: Some("expected a Location".to_string()),
208 })?;
209
210 Ok(MethodCallQuery { parent, location })
211 }
212}
213
214#[derive(Clone, Debug)]
215pub struct MethodCall {
216 pub origin: MethodCallQuery,
220 pub args: Vec<Value>,
221 pub in_item_id: String,
222}
223
224impl_into_lua! {
225 MethodCall {
226 origin,
227 args,
228 in_item_id,
229 }
230}
231
232#[derive(Clone, Debug)]
233pub enum Value {
234 StringLiteral(String),
235 IntegerLiteral(i64),
236 FloatLiteral(f64),
237
238 FunctionCall(FunctionCall),
239 MethodCall(MethodCall),
240
241 Type(TypeValue),
242}
243
244impl_enum_into_lua! {
245 Value {
246 StringLiteral(s) => s,
247 IntegerLiteral(i) => i,
248 FloatLiteral(f) => f,
249
250 FunctionCall(f) => f,
251 MethodCall(m) => m,
252
253 Type(t) => t,
254 }
255}
256
257#[derive(Clone, Debug)]
258pub enum TypeValue {
259 String,
260
261 U8,
262 U16,
263 U32,
264 U64,
265 U128,
266 Usize,
267
268 I8,
269 I16,
270 I32,
271 I64,
272 I128,
273 Isize,
274
275 F32,
276 F64,
277
278 Bool,
279
280 HashMap(Box<TypeValue>, Box<TypeValue>),
281 Vec(Box<TypeValue>),
282 Result(Box<TypeValue>, Box<TypeValue>),
283
284 Struct(StructTypeValue),
285 Enum(EnumTypeValue),
286
287 Closure(ClosureTypeValue),
288 Function(FunctionTypeValue),
289
290 Option(Box<TypeValue>),
291
292 Tuple(Vec<TypeValue>),
293
294 RecursiveRef(Location),
295}
296
297impl_enum_into_lua! {
298 TypeValue {
299 String,
300 U8,
301 U16,
302 U32,
303 U64,
304 U128,
305 Usize,
306 I8,
307 I16,
308 I32,
309 I64,
310 I128,
311 Isize,
312 F32,
313 F64,
314 Bool,
315
316 HashMap(_, _) => mlua::Nil,
318 Vec(t) => *t,
319 Result(_, _) => mlua::Nil,
321
322 Struct(s) => s,
323 Enum(e) => e,
324
325 Closure(c) => c,
326
327 Function(f) => f,
328
329 Option(t) => *t,
330
331 Tuple(elements) => elements,
332
333 RecursiveRef(location) => location,
334 }
335}
336
337#[derive(Clone, Debug)]
338pub struct StructTypeValue {
339 pub location: Location,
340 pub fields: Vec<StructTypeValueField>,
341 pub doc_comment: Option<String>,
342 pub attributes: Vec<Attribute>,
343}
344
345impl_into_lua! {
346 StructTypeValue {
347 location,
348 fields,
349 doc_comment,
350 attributes,
351 }
352}
353
354#[derive(Clone, Debug)]
355pub struct StructTypeValueField {
356 pub name: Either<usize, String>,
357 pub doc_comment: Option<String>,
358 pub attributes: Vec<Attribute>,
359 pub value: TypeValue,
360}
361
362impl_into_lua! {
363 StructTypeValueField {
364 name,
365 doc_comment,
366 attributes,
367 value,
368 }
369}
370
371#[derive(Clone, Debug)]
372pub struct EnumTypeValue {
373 pub location: Location,
374 pub variants: Vec<EnumTypeValueVariant>,
375 pub doc_comment: Option<String>,
376 pub attributes: Vec<Attribute>,
377}
378
379impl_into_lua! {
380 EnumTypeValue {
381 location,
382 variants,
383 doc_comment,
384 attributes,
385 }
386}
387
388#[derive(Clone, Debug)]
389pub struct EnumTypeValueVariant {
390 pub name: String,
391 pub value: Option<TypeValue>,
394 pub doc_comment: Option<String>,
395 pub attributes: Vec<Attribute>,
396}
397
398impl_into_lua! {
399 EnumTypeValueVariant {
400 name,
401 value,
402 doc_comment,
403 attributes,
404 }
405}
406
407#[derive(Clone, Debug)]
409pub struct ClosureTypeValue {
410 pub args: Vec<TypeValue>,
411 pub return_type: Option<Box<TypeValue>>,
412}
413
414impl_into_lua! {
415 ClosureTypeValue {
416 args,
417 return_type => return_type.map(|b| *b),
418 }
419}
420
421#[derive(Clone, Debug)]
422pub struct FunctionTypeValue {
423 pub location: Location,
424 pub args_struct: StructTypeValue,
425 pub return_type: Option<Box<TypeValue>>,
426 pub item_id: String,
427 pub attributes: Vec<Attribute>,
428 pub doc_comment: Option<String>,
429 pub is_async: bool,
430}
431
432impl_into_lua! {
433 FunctionTypeValue {
434 location,
435 args_struct,
436 return_type => return_type.map(|b| *b),
437 item_id,
438 attributes,
439 doc_comment,
440 is_async,
441 }
442}
443
444#[derive(Clone, Debug)]
446pub struct Attribute {
447 pub name: String,
448 pub value_str: Option<String>,
450}
451
452impl_into_lua! {
453 Attribute {
454 name,
455 value_str,
456 }
457}
458
459#[derive(Clone, Debug)]
460pub struct FunctionCall {
461 pub location: Location,
462 pub args: Vec<Value>,
463 pub in_item_id: String,
464}
465
466impl_into_lua! {
467 FunctionCall {
468 location,
469 args,
470 in_item_id,
471 }
472}
473
474#[derive(Clone, Debug)]
475pub struct TraitImpl {
476 pub trait_location: Location,
477 pub for_type: TypeValue,
478 pub functions: Vec<FunctionTypeValue>,
479}
480
481impl_into_lua! {
482 TraitImpl {
483 trait_location,
484 for_type,
485 functions,
486 }
487}