@@ -405,3 +405,141 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
405405 krate : & hir:: Crate ) -> Vec < u8 > { vec ! [ ] }
406406 fn metadata_encoding_version ( & self ) -> & [ u8 ] { unimplemented ! ( ) }
407407}
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