@@ -405,3 +405,141 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
405
405
krate : & hir:: Crate ) -> Vec < u8 > { vec ! [ ] }
406
406
fn metadata_encoding_version ( & self ) -> & [ u8 ] { unimplemented ! ( ) }
407
407
}
408
+
409
+
410
+ /// Metadata encoding and decoding can make use of thread-local encoding and
411
+ /// decoding contexts. These allow implementers of serialize::Encodable and
412
+ /// Decodable to access information and datastructures that would otherwise not
413
+ /// be available to them. For example, we can automatically translate def-id and
414
+ /// span information during decoding because the decoding context knows which
415
+ /// crate the data is decoded from. Or it allows to make ty::Ty decodable
416
+ /// because the context has access to the ty::ctxt that is needed for creating
417
+ /// ty::Ty instances.
418
+ ///
419
+ /// Note, however, that this only works for RBML-based encoding and decoding at
420
+ /// the moment.
421
+ pub mod tls {
422
+ use rbml:: writer:: Encoder as RbmlEncoder ;
423
+ use rbml:: reader:: Decoder as RbmlDecoder ;
424
+ use serialize;
425
+ use std:: mem;
426
+ use middle:: ty:: { self , Ty } ;
427
+ use middle:: subst:: Substs ;
428
+ use middle:: def_id:: DefId ;
429
+
430
+ pub trait EncodingContext < ' tcx > {
431
+ fn tcx < ' a > ( & ' a self ) -> & ' a ty:: ctxt < ' tcx > ;
432
+ fn encode_ty ( & self , rbml_w : & mut RbmlEncoder , t : Ty < ' tcx > ) ;
433
+ fn encode_substs ( & self , rbml_w : & mut RbmlEncoder , substs : & Substs < ' tcx > ) ;
434
+ }
435
+
436
+ /// Marker type used for the scoped TLS slot.
437
+ /// The type context cannot be used directly because the scoped TLS
438
+ /// in libstd doesn't allow types generic over lifetimes.
439
+ struct TlsPayload ;
440
+
441
+ scoped_thread_local ! ( static TLS_ENCODING : TlsPayload ) ;
442
+
443
+ /// Execute f after pushing the given EncodingContext onto the TLS stack.
444
+ pub fn enter_encoding_context < ' tcx , F , R > ( ecx : & EncodingContext < ' tcx > ,
445
+ rbml_w : & mut RbmlEncoder ,
446
+ f : F ) -> R
447
+ where F : FnOnce ( & EncodingContext < ' tcx > , & mut RbmlEncoder ) -> R
448
+ {
449
+ let tls_payload = ( ecx as * const _ , rbml_w as * mut _ ) ;
450
+ let tls_ptr = & tls_payload as * const _ as * const TlsPayload ;
451
+ TLS_ENCODING . set ( unsafe { & * tls_ptr } , || f ( ecx, rbml_w) )
452
+ }
453
+
454
+ /// Execute f with access to the thread-local encoding context and
455
+ /// rbml encoder. This function will panic if the encoder passed in and the
456
+ /// context encoder are not the same.
457
+ ///
458
+ /// Note that this method is 'practically' safe due to its checking that the
459
+ /// encoder passed in is the same as the one in TLS, but it would still be
460
+ /// possible to construct cases where the EncodingContext is exchanged
461
+ /// while the same encoder is used, thus working with a wrong context.
462
+ pub fn with_encoding_context < ' tcx , E , F , R > ( encoder : & mut E , f : F ) -> R
463
+ where F : FnOnce ( & EncodingContext < ' tcx > , & mut RbmlEncoder ) -> R ,
464
+ E : serialize:: Encoder
465
+ {
466
+ unsafe {
467
+ unsafe_with_encoding_context ( |ecx, rbml_w| {
468
+ assert ! ( encoder as * mut _ as usize == rbml_w as * mut _ as usize ) ;
469
+
470
+ let ecx: & EncodingContext < ' tcx > = mem:: transmute ( ecx) ;
471
+
472
+ f ( ecx, rbml_w)
473
+ } )
474
+ }
475
+ }
476
+
477
+ /// Execute f with access to the thread-local encoding context and
478
+ /// rbml encoder.
479
+ pub unsafe fn unsafe_with_encoding_context < F , R > ( f : F ) -> R
480
+ where F : FnOnce ( & EncodingContext , & mut RbmlEncoder ) -> R
481
+ {
482
+ TLS_ENCODING . with ( |tls| {
483
+ let tls_payload = ( tls as * const TlsPayload )
484
+ as * mut ( & EncodingContext , & mut RbmlEncoder ) ;
485
+ f ( ( * tls_payload) . 0 , ( * tls_payload) . 1 )
486
+ } )
487
+ }
488
+
489
+ pub trait DecodingContext < ' tcx > {
490
+ fn tcx < ' a > ( & ' a self ) -> & ' a ty:: ctxt < ' tcx > ;
491
+ fn decode_ty ( & self , rbml_r : & mut RbmlDecoder ) -> ty:: Ty < ' tcx > ;
492
+ fn decode_substs ( & self , rbml_r : & mut RbmlDecoder ) -> Substs < ' tcx > ;
493
+ fn translate_def_id ( & self , def_id : DefId ) -> DefId ;
494
+ }
495
+
496
+ scoped_thread_local ! ( static TLS_DECODING : TlsPayload ) ;
497
+
498
+ /// Execute f after pushing the given DecodingContext onto the TLS stack.
499
+ pub fn enter_decoding_context < ' tcx , F , R > ( dcx : & DecodingContext < ' tcx > ,
500
+ rbml_r : & mut RbmlDecoder ,
501
+ f : F ) -> R
502
+ where F : FnOnce ( & DecodingContext < ' tcx > , & mut RbmlDecoder ) -> R
503
+ {
504
+ let tls_payload = ( dcx as * const _ , rbml_r as * mut _ ) ;
505
+ let tls_ptr = & tls_payload as * const _ as * const TlsPayload ;
506
+ TLS_DECODING . set ( unsafe { & * tls_ptr } , || f ( dcx, rbml_r) )
507
+ }
508
+
509
+ /// Execute f with access to the thread-local decoding context and
510
+ /// rbml decoder. This function will panic if the decoder passed in and the
511
+ /// context decoder are not the same.
512
+ ///
513
+ /// Note that this method is 'practically' safe due to its checking that the
514
+ /// decoder passed in is the same as the one in TLS, but it would still be
515
+ /// possible to construct cases where the DecodingContext is exchanged
516
+ /// while the same decoder is used, thus working with a wrong context.
517
+ pub fn with_decoding_context < ' decoder , ' tcx , D , F , R > ( d : & ' decoder mut D , f : F ) -> R
518
+ where D : serialize:: Decoder ,
519
+ F : FnOnce ( & DecodingContext < ' tcx > ,
520
+ & mut RbmlDecoder ) -> R ,
521
+ ' tcx : ' decoder
522
+ {
523
+ unsafe {
524
+ unsafe_with_decoding_context ( |dcx, rbml_r| {
525
+ assert ! ( ( d as * mut _ as usize ) == ( rbml_r as * mut _ as usize ) ) ;
526
+
527
+ let dcx: & DecodingContext < ' tcx > = mem:: transmute ( dcx) ;
528
+
529
+ f ( dcx, rbml_r)
530
+ } )
531
+ }
532
+ }
533
+
534
+ /// Execute f with access to the thread-local decoding context and
535
+ /// rbml decoder.
536
+ pub unsafe fn unsafe_with_decoding_context < F , R > ( f : F ) -> R
537
+ where F : FnOnce ( & DecodingContext , & mut RbmlDecoder ) -> R
538
+ {
539
+ TLS_DECODING . with ( |tls| {
540
+ let tls_payload = ( tls as * const TlsPayload )
541
+ as * mut ( & DecodingContext , & mut RbmlDecoder ) ;
542
+ f ( ( * tls_payload) . 0 , ( * tls_payload) . 1 )
543
+ } )
544
+ }
545
+ }
0 commit comments