@@ -93,11 +93,18 @@ thread_local! {
9393/// assert_eq!(current.get::<ValueB>(), None);
9494/// ```
9595#[ derive( Clone , Default ) ]
96+ #[ cfg_attr( target_pointer_width = "64" , repr( align( 16 ) ) ) ]
97+ #[ cfg_attr( target_pointer_width = "32" , repr( align( 8 ) ) ) ]
9698pub struct Context {
99+ pub ( crate ) inner : Option < Arc < InnerContext > > ,
100+ flags : ContextFlags ,
101+ }
102+
103+ #[ derive( Default ) ]
104+ pub ( crate ) struct InnerContext {
97105 #[ cfg( feature = "trace" ) ]
98106 pub ( crate ) span : Option < Arc < SynchronizedSpan > > ,
99107 entries : Option < Arc < EntryMap > > ,
100- suppress_telemetry : bool ,
101108}
102109
103110type EntryMap = HashMap < TypeId , Arc < dyn Any + Sync + Send > , BuildHasherDefault < IdHasher > > ;
@@ -198,7 +205,9 @@ impl Context {
198205 /// assert_eq!(cx.get::<MyUser>(), None);
199206 /// ```
200207 pub fn get < T : ' static > ( & self ) -> Option < & T > {
201- self . entries
208+ self . inner
209+ . as_ref ( ) ?
210+ . entries
202211 . as_ref ( ) ?
203212 . get ( & TypeId :: of :: < T > ( ) ) ?
204213 . downcast_ref ( )
@@ -232,20 +241,29 @@ impl Context {
232241 /// assert_eq!(cx_with_a_and_b.get::<ValueB>(), Some(&ValueB(42)));
233242 /// ```
234243 pub fn with_value < T : ' static + Send + Sync > ( & self , value : T ) -> Self {
235- let entries = if let Some ( current_entries) = & self . entries {
236- let mut inner_entries = ( * * current_entries) . clone ( ) ;
237- inner_entries. insert ( TypeId :: of :: < T > ( ) , Arc :: new ( value) ) ;
238- Some ( Arc :: new ( inner_entries) )
239- } else {
244+ fn new_entries < T : ' static + Send + Sync > ( value : T ) -> Option < Arc < EntryMap > > {
240245 let mut entries = EntryMap :: default ( ) ;
241246 entries. insert ( TypeId :: of :: < T > ( ) , Arc :: new ( value) ) ;
242247 Some ( Arc :: new ( entries) )
248+ }
249+ let ( entries, span) = if let Some ( inner) = & self . inner {
250+ if let Some ( current_entries) = & inner. entries {
251+ let mut inner_entries = ( * * current_entries) . clone ( ) ;
252+ inner_entries. insert ( TypeId :: of :: < T > ( ) , Arc :: new ( value) ) ;
253+ ( Some ( Arc :: new ( inner_entries) ) , & inner. span )
254+ } else {
255+ ( new_entries ( value) , & inner. span )
256+ }
257+ } else {
258+ ( new_entries ( value) , & None )
243259 } ;
244260 Context {
245- entries,
246- #[ cfg( feature = "trace" ) ]
247- span : self . span . clone ( ) ,
248- suppress_telemetry : self . suppress_telemetry ,
261+ inner : Some ( Arc :: new ( InnerContext {
262+ entries,
263+ #[ cfg( feature = "trace" ) ]
264+ span : span. clone ( ) ,
265+ } ) ) ,
266+ flags : self . flags ,
249267 }
250268 }
251269
@@ -335,16 +353,14 @@ impl Context {
335353 /// Returns whether telemetry is suppressed in this context.
336354 #[ inline]
337355 pub fn is_telemetry_suppressed ( & self ) -> bool {
338- self . suppress_telemetry
356+ self . flags . is_telemetry_suppressed ( )
339357 }
340358
341359 /// Returns a new context with telemetry suppression enabled.
342360 pub fn with_telemetry_suppressed ( & self ) -> Self {
343361 Context {
344- entries : self . entries . clone ( ) ,
345- #[ cfg( feature = "trace" ) ]
346- span : self . span . clone ( ) ,
347- suppress_telemetry : true ,
362+ inner : self . inner . clone ( ) ,
363+ flags : self . flags . with_telemetry_suppressed ( ) ,
348364 }
349365 }
350366
@@ -410,19 +426,45 @@ impl Context {
410426
411427 #[ cfg( feature = "trace" ) ]
412428 pub ( crate ) fn current_with_synchronized_span ( value : SynchronizedSpan ) -> Self {
413- Self :: map_current ( |cx| Context {
414- span : Some ( Arc :: new ( value) ) ,
415- entries : cx. entries . clone ( ) ,
416- suppress_telemetry : cx. suppress_telemetry ,
429+ Self :: map_current ( |cx| {
430+ if let Some ( inner) = & cx. inner {
431+ Context {
432+ inner : Some ( Arc :: new ( InnerContext {
433+ span : Some ( Arc :: new ( value) ) ,
434+ entries : inner. entries . clone ( ) ,
435+ } ) ) ,
436+ flags : cx. flags ,
437+ }
438+ } else {
439+ Context {
440+ inner : Some ( Arc :: new ( InnerContext {
441+ span : Some ( Arc :: new ( value) ) ,
442+ entries : None ,
443+ } ) ) ,
444+ flags : ContextFlags :: new ( ) ,
445+ }
446+ }
417447 } )
418448 }
419449
420450 #[ cfg( feature = "trace" ) ]
421451 pub ( crate ) fn with_synchronized_span ( & self , value : SynchronizedSpan ) -> Self {
422- Context {
423- span : Some ( Arc :: new ( value) ) ,
424- entries : self . entries . clone ( ) ,
425- suppress_telemetry : self . suppress_telemetry ,
452+ if let Some ( inner) = & self . inner {
453+ Context {
454+ inner : Some ( Arc :: new ( InnerContext {
455+ span : Some ( Arc :: new ( value) ) ,
456+ entries : inner. entries . clone ( ) ,
457+ } ) ) ,
458+ flags : self . flags ,
459+ }
460+ } else {
461+ Context {
462+ inner : Some ( Arc :: new ( InnerContext {
463+ span : Some ( Arc :: new ( value) ) ,
464+ entries : None ,
465+ } ) ) ,
466+ flags : ContextFlags :: new ( ) ,
467+ }
426468 }
427469 }
428470}
@@ -432,25 +474,67 @@ impl fmt::Debug for Context {
432474 let mut dbg = f. debug_struct ( "Context" ) ;
433475
434476 #[ cfg( feature = "trace" ) ]
435- let mut entries = self . entries . as_ref ( ) . map_or ( 0 , |e| e. len ( ) ) ;
477+ let mut entries = self
478+ . inner
479+ . as_ref ( )
480+ . map_or ( 0 , |i| i. entries . as_ref ( ) . map_or ( 0 , |e| e. len ( ) ) ) ;
436481 #[ cfg( feature = "trace" ) ]
437482 {
438- if let Some ( span) = & self . span {
483+ if let Some ( Some ( span) ) = self . inner . as_ref ( ) . map ( |i| i . span . as_ref ( ) ) {
439484 dbg. field ( "span" , & span. span_context ( ) ) ;
440485 entries += 1 ;
441486 } else {
442487 dbg. field ( "span" , & "None" ) ;
443488 }
444489 }
445490 #[ cfg( not( feature = "trace" ) ) ]
446- let entries = self . entries . as_ref ( ) . map_or ( 0 , |e| e. len ( ) ) ;
491+ let entries = self
492+ . inner
493+ . as_ref ( )
494+ . map_or ( 0 , |i| i. entries . as_ref ( ) . map_or ( 0 , |e| e. len ( ) ) ) ;
447495
448496 dbg. field ( "entries count" , & entries)
449- . field ( "suppress_telemetry " , & self . suppress_telemetry )
497+ . field ( "flags " , & self . flags )
450498 . finish ( )
451499 }
452500}
453501
502+ /// Bit flags for context state.
503+ #[ derive( Clone , Copy , Default ) ]
504+ struct ContextFlags ( u16 ) ;
505+
506+ impl ContextFlags {
507+ const SUPPRESS_TELEMETRY : u16 = 1 << 0 ;
508+
509+ /// Creates a new ContextFlags with all flags cleared.
510+ #[ inline( always) ]
511+ const fn new ( ) -> Self {
512+ ContextFlags ( 0 )
513+ }
514+
515+ /// Returns true if telemetry suppression is enabled.
516+ #[ inline( always) ]
517+ const fn is_telemetry_suppressed ( self ) -> bool {
518+ ( self . 0 & Self :: SUPPRESS_TELEMETRY ) != 0
519+ }
520+
521+ /// Returns a new ContextFlags with telemetry suppression enabled.
522+ #[ inline( always) ]
523+ const fn with_telemetry_suppressed ( self ) -> Self {
524+ ContextFlags ( self . 0 | Self :: SUPPRESS_TELEMETRY )
525+ }
526+ }
527+
528+ impl fmt:: Debug for ContextFlags {
529+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
530+ f. write_str ( "ContextFlags(" ) ?;
531+ if self . is_telemetry_suppressed ( ) {
532+ f. write_str ( "TELEMETRY_SUPPRESSED" ) ?;
533+ }
534+ f. write_str ( ")" )
535+ }
536+ }
537+
454538/// A guard that resets the current context to the prior context when dropped.
455539#[ derive( Debug ) ]
456540pub struct ContextGuard {
0 commit comments