@@ -8,7 +8,7 @@ fn main() {
8
8
9
9
#[ cfg( feature = "binary" ) ]
10
10
mod binary {
11
- use std :: fmt ;
11
+ use quote :: quote ;
12
12
13
13
pub fn main ( ) {
14
14
use llvm_tools_build as llvm_tools;
@@ -207,17 +207,21 @@ mod binary {
207
207
Ok ( path)
208
208
if Path :: new ( & path) . file_name ( ) . and_then ( |s| s. to_str ( ) ) != Some ( "Cargo.toml" ) =>
209
209
{
210
- format ! (
211
- "compile_error!( \" The given `--kernel-manifest` path `{}` does not \
212
- point to a `Cargo.toml`\" ) ",
210
+ let err = format ! (
211
+ "The given `--kernel-manifest` path `{}` does not \
212
+ point to a `Cargo.toml`",
213
213
path,
214
- )
214
+ ) ;
215
+ quote ! { compile_error!( #err) }
215
216
}
216
217
Ok ( path) if !Path :: new ( & path) . exists ( ) => {
217
- format ! (
218
- "compile_error!(\" The given `--kernel-manifest` path `{}` does not exist`\" )" ,
219
- path,
220
- )
218
+ let err = format ! (
219
+ "The given `--kernel-manifest` path `{}` does not exist." ,
220
+ path
221
+ ) ;
222
+ quote ! {
223
+ compile_error!( #err) ;
224
+ }
221
225
}
222
226
Ok ( path) => {
223
227
println ! ( "cargo:rerun-if-changed={}" , path) ;
@@ -245,22 +249,28 @@ mod binary {
245
249
. unwrap_or_else ( || toml:: Value :: Table ( toml:: map:: Map :: new ( ) ) ) ;
246
250
247
251
config_table
248
- . try_into :: < Config > ( )
249
- . map ( |c| format ! ( "{:?}" , c ) )
252
+ . try_into :: < ParsedConfig > ( )
253
+ . map ( |c| quote ! { #c } )
250
254
. unwrap_or_else ( |err| {
251
- format ! (
252
- "compile_error!( \" failed to parse bootloader config in {}:\n \n {}\" ) " ,
255
+ let err = format ! (
256
+ "failed to parse bootloader config in {}:\n \n {}" ,
253
257
path,
254
- err. to_string( ) . escape_default( ) ,
255
- )
258
+ err. to_string( ) . escape_default( )
259
+ ) ;
260
+ quote ! {
261
+ compile_error!( #err) ;
262
+ }
256
263
} )
257
264
} else {
258
- format ! (
259
- "compile_error!(\" no bootloader dependency in {}\n \n The \
260
- `--kernel-manifest` path should point to the `Cargo.toml` \
261
- of the kernel.\" )",
262
- path,
263
- )
265
+ let err = format ! (
266
+ "no bootloader dependency in {}\n \n The \
267
+ `--kernel-manifest` path should point to the `Cargo.toml` \
268
+ of the kernel.",
269
+ path
270
+ ) ;
271
+ quote ! {
272
+ compile_error!( #err) ;
273
+ }
264
274
}
265
275
}
266
276
} ;
@@ -269,13 +279,13 @@ mod binary {
269
279
let file_path = out_dir. join ( "bootloader_config.rs" ) ;
270
280
let mut file = File :: create ( file_path) . expect ( "failed to create bootloader_config.rs" ) ;
271
281
file. write_all (
272
- format ! (
273
- " mod parsed_config { {
282
+ quote :: quote! {
283
+ mod parsed_config {
274
284
use crate :: config:: Config ;
275
- pub const CONFIG: Config = {} ;
276
- }}" ,
277
- config ,
278
- )
285
+ pub const CONFIG : Config = #config ;
286
+ }
287
+ }
288
+ . to_string ( )
279
289
. as_bytes ( ) ,
280
290
)
281
291
. expect ( "write to bootloader_config.rs failed" ) ;
@@ -294,10 +304,11 @@ mod binary {
294
304
///
295
305
/// This copy is needed because we can't derive Deserialize in the `src/config.rs`
296
306
/// module itself, since cargo currently unifies dependencies (the `toml` crate enables
297
- /// serde's standard feature).
307
+ /// serde's standard feature). Also, it allows to separate the parsing special cases
308
+ /// such as `AlignedAddress` more cleanly.
298
309
#[ derive( Debug , serde:: Deserialize ) ]
299
310
#[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
300
- struct Config {
311
+ struct ParsedConfig {
301
312
#[ serde( default ) ]
302
313
pub map_physical_memory : bool ,
303
314
#[ serde( default ) ]
@@ -312,11 +323,43 @@ mod binary {
312
323
pub framebuffer_address : Option < AlignedAddress > ,
313
324
}
314
325
326
+ /// Convert to tokens suitable for initializing the `Config` struct.
327
+ impl quote:: ToTokens for ParsedConfig {
328
+ fn to_tokens ( & self , tokens : & mut proc_macro2:: TokenStream ) {
329
+ fn optional ( value : Option < impl quote:: ToTokens > ) -> proc_macro2:: TokenStream {
330
+ value. map ( |v| quote ! ( Some ( #v) ) ) . unwrap_or ( quote ! ( None ) )
331
+ }
332
+
333
+ let map_physical_memory = self . map_physical_memory ;
334
+ let map_page_table_recursively = self . map_page_table_recursively ;
335
+ let map_framebuffer = self . map_framebuffer ;
336
+ let kernel_stack_size = optional ( self . kernel_stack_size ) ;
337
+ let physical_memory_offset = optional ( self . physical_memory_offset ) ;
338
+ let recursive_index = optional ( self . recursive_index ) ;
339
+ let kernel_stack_address = optional ( self . kernel_stack_address ) ;
340
+ let boot_info_address = optional ( self . boot_info_address ) ;
341
+ let framebuffer_address = optional ( self . framebuffer_address ) ;
342
+
343
+ tokens. extend ( quote ! { Config {
344
+ map_physical_memory: #map_physical_memory,
345
+ map_page_table_recursively: #map_page_table_recursively,
346
+ map_framebuffer: #map_framebuffer,
347
+ kernel_stack_size: #kernel_stack_size,
348
+ physical_memory_offset: #physical_memory_offset,
349
+ recursive_index: #recursive_index,
350
+ kernel_stack_address: #kernel_stack_address,
351
+ boot_info_address: #boot_info_address,
352
+ framebuffer_address: #framebuffer_address,
353
+ } } ) ;
354
+ }
355
+ }
356
+
357
+ #[ derive( Debug , Clone , Copy ) ]
315
358
struct AlignedAddress ( u64 ) ;
316
359
317
- impl fmt :: Debug for AlignedAddress {
318
- fn fmt ( & self , f : & mut fmt :: Formatter ) -> fmt :: Result {
319
- write ! ( f , "{}" , self . 0 )
360
+ impl quote :: ToTokens for AlignedAddress {
361
+ fn to_tokens ( & self , tokens : & mut proc_macro2 :: TokenStream ) {
362
+ self . 0 . to_tokens ( tokens ) ;
320
363
}
321
364
}
322
365
0 commit comments