@@ -130,6 +130,28 @@ pub enum ChunkMode {
130
130
Binary ,
131
131
}
132
132
133
+ /// Represents a constant value that can be used by Luau compiler.
134
+ #[ cfg( any( feature = "luau" , doc) ) ]
135
+ #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
136
+ #[ derive( Clone , Debug ) ]
137
+ pub enum CompileConstant {
138
+ Nil ,
139
+ Boolean ( bool ) ,
140
+ Number ( crate :: Number ) ,
141
+ Vector ( crate :: Vector ) ,
142
+ String ( String ) ,
143
+ }
144
+
145
+ #[ cfg( feature = "luau" ) ]
146
+ impl From < & ' static str > for CompileConstant {
147
+ fn from ( s : & ' static str ) -> Self {
148
+ CompileConstant :: String ( s. to_string ( ) )
149
+ }
150
+ }
151
+
152
+ #[ cfg( any( feature = "luau" , doc) ) ]
153
+ type LibraryMemberConstantMap = std:: sync:: Arc < HashMap < ( String , String ) , CompileConstant > > ;
154
+
133
155
/// Luau compiler
134
156
#[ cfg( any( feature = "luau" , doc) ) ]
135
157
#[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
@@ -144,6 +166,9 @@ pub struct Compiler {
144
166
vector_type : Option < String > ,
145
167
mutable_globals : Vec < String > ,
146
168
userdata_types : Vec < String > ,
169
+ libraries_with_known_members : Vec < String > ,
170
+ library_constants : Option < LibraryMemberConstantMap > ,
171
+ disabled_builtins : Vec < String > ,
147
172
}
148
173
149
174
#[ cfg( any( feature = "luau" , doc) ) ]
@@ -168,6 +193,9 @@ impl Compiler {
168
193
vector_type : None ,
169
194
mutable_globals : Vec :: new ( ) ,
170
195
userdata_types : Vec :: new ( ) ,
196
+ libraries_with_known_members : Vec :: new ( ) ,
197
+ library_constants : None ,
198
+ disabled_builtins : Vec :: new ( ) ,
171
199
}
172
200
}
173
201
@@ -200,6 +228,7 @@ impl Compiler {
200
228
/// Possible values:
201
229
/// * 0 - generate for native modules (default)
202
230
/// * 1 - generate for all modules
231
+ #[ must_use]
203
232
pub const fn set_type_info_level ( mut self , level : u8 ) -> Self {
204
233
self . type_info_level = level;
205
234
self
@@ -242,23 +271,56 @@ impl Compiler {
242
271
///
243
272
/// It disables the import optimization for fields accessed through these.
244
273
#[ must_use]
245
- pub fn set_mutable_globals ( mut self , globals : Vec < String > ) -> Self {
246
- self . mutable_globals = globals;
274
+ pub fn set_mutable_globals < S : Into < String > > ( mut self , globals : Vec < S > ) -> Self {
275
+ self . mutable_globals = globals. into_iter ( ) . map ( |s| s . into ( ) ) . collect ( ) ;
247
276
self
248
277
}
249
278
250
279
/// Sets a list of userdata types that will be included in the type information.
251
280
#[ must_use]
252
- pub fn set_userdata_types ( mut self , types : Vec < String > ) -> Self {
253
- self . userdata_types = types;
281
+ pub fn set_userdata_types < S : Into < String > > ( mut self , types : Vec < S > ) -> Self {
282
+ self . userdata_types = types. into_iter ( ) . map ( |s| s. into ( ) ) . collect ( ) ;
283
+ self
284
+ }
285
+
286
+ /// Sets constants for known library members.
287
+ ///
288
+ /// The constants are used by the compiler to optimize the generated bytecode.
289
+ /// Optimization level must be at least 2 for this to have any effect.
290
+ ///
291
+ /// The first element of the tuple is the library name,the second is the member name, and the
292
+ /// third is the constant value.
293
+ #[ must_use]
294
+ pub fn set_library_constants < L , M > ( mut self , constants : Vec < ( L , M , CompileConstant ) > ) -> Self
295
+ where
296
+ L : Into < String > ,
297
+ M : Into < String > ,
298
+ {
299
+ let map = constants
300
+ . into_iter ( )
301
+ . map ( |( lib, member, cons) | ( ( lib. into ( ) , member. into ( ) ) , cons) )
302
+ . collect :: < HashMap < _ , _ > > ( ) ;
303
+ self . library_constants = Some ( std:: sync:: Arc :: new ( map) ) ;
304
+ self . libraries_with_known_members = ( self . library_constants . clone ( ) )
305
+ . map ( |map| map. keys ( ) . map ( |( lib, _) | lib. clone ( ) ) . collect ( ) )
306
+ . unwrap_or_default ( ) ;
307
+ self
308
+ }
309
+
310
+ /// Sets a list of builtins that should be disabled.
311
+ #[ must_use]
312
+ pub fn set_disabled_builtins < S : Into < String > > ( mut self , builtins : Vec < S > ) -> Self {
313
+ self . disabled_builtins = builtins. into_iter ( ) . map ( |s| s. into ( ) ) . collect ( ) ;
254
314
self
255
315
}
256
316
257
317
/// Compiles the `source` into bytecode.
258
318
///
259
319
/// Returns [`Error::SyntaxError`] if the source code is invalid.
260
320
pub fn compile ( & self , source : impl AsRef < [ u8 ] > ) -> Result < Vec < u8 > > {
261
- use std:: os:: raw:: c_int;
321
+ use std:: cell:: RefCell ;
322
+ use std:: ffi:: CStr ;
323
+ use std:: os:: raw:: { c_char, c_int} ;
262
324
use std:: ptr;
263
325
264
326
let vector_lib = self . vector_lib . clone ( ) ;
@@ -290,6 +352,44 @@ impl Compiler {
290
352
291
353
vec2cstring_ptr ! ( mutable_globals, mutable_globals_ptr) ;
292
354
vec2cstring_ptr ! ( userdata_types, userdata_types_ptr) ;
355
+ vec2cstring_ptr ! ( libraries_with_known_members, libraries_with_known_members_ptr) ;
356
+ vec2cstring_ptr ! ( disabled_builtins, disabled_builtins_ptr) ;
357
+
358
+ thread_local ! {
359
+ static LIBRARY_MEMBER_CONSTANT_MAP : RefCell <LibraryMemberConstantMap > = Default :: default ( ) ;
360
+ }
361
+
362
+ #[ cfg( feature = "luau" ) ]
363
+ unsafe extern "C-unwind" fn library_member_constant_callback (
364
+ library : * const c_char ,
365
+ member : * const c_char ,
366
+ constant : * mut ffi:: lua_CompileConstant ,
367
+ ) {
368
+ let library = CStr :: from_ptr ( library) . to_string_lossy ( ) ;
369
+ let member = CStr :: from_ptr ( member) . to_string_lossy ( ) ;
370
+ LIBRARY_MEMBER_CONSTANT_MAP . with_borrow ( |map| {
371
+ if let Some ( cons) = map. get ( & ( library. to_string ( ) , member. to_string ( ) ) ) {
372
+ match cons {
373
+ CompileConstant :: Nil => ffi:: luau_set_compile_constant_nil ( constant) ,
374
+ CompileConstant :: Boolean ( b) => {
375
+ ffi:: luau_set_compile_constant_boolean ( constant, * b as c_int )
376
+ }
377
+ CompileConstant :: Number ( n) => ffi:: luau_set_compile_constant_number ( constant, * n) ,
378
+ CompileConstant :: Vector ( v) => {
379
+ #[ cfg( not( feature = "luau-vector4" ) ) ]
380
+ ffi:: luau_set_compile_constant_vector ( constant, v. x ( ) , v. y ( ) , v. z ( ) , 0.0 ) ;
381
+ #[ cfg( feature = "luau-vector4" ) ]
382
+ ffi:: luau_set_compile_constant_vector ( constant, v. x ( ) , v. y ( ) , v. z ( ) , v. w ( ) ) ;
383
+ }
384
+ CompileConstant :: String ( s) => ffi:: luau_set_compile_constant_string (
385
+ constant,
386
+ s. as_ptr ( ) as * const c_char ,
387
+ s. len ( ) ,
388
+ ) ,
389
+ }
390
+ }
391
+ } )
392
+ }
293
393
294
394
let bytecode = unsafe {
295
395
let mut options = ffi:: lua_CompileOptions:: default ( ) ;
@@ -302,6 +402,14 @@ impl Compiler {
302
402
options. vectorType = vector_type. map_or ( ptr:: null ( ) , |s| s. as_ptr ( ) ) ;
303
403
options. mutableGlobals = mutable_globals_ptr;
304
404
options. userdataTypes = userdata_types_ptr;
405
+ options. librariesWithKnownMembers = libraries_with_known_members_ptr;
406
+ if let Some ( map) = self . library_constants . as_ref ( ) {
407
+ if !self . libraries_with_known_members . is_empty ( ) {
408
+ LIBRARY_MEMBER_CONSTANT_MAP . with_borrow_mut ( |gmap| * gmap = map. clone ( ) ) ;
409
+ options. libraryMemberConstantCallback = Some ( library_member_constant_callback) ;
410
+ }
411
+ }
412
+ options. disabledBuiltins = disabled_builtins_ptr;
305
413
ffi:: luau_compile ( source. as_ref ( ) , options)
306
414
} ;
307
415
0 commit comments