@@ -17,37 +17,45 @@ use std::fmt::Debug;
1717use once_cell:: sync:: OnceCell ;
1818use state:: Container ;
1919
20+ /// SINGLETON_TYPE is the global singleton type.
21+ static SINGLETON_TYPE : OnceCell < SingletonType > = OnceCell :: new ( ) ;
22+
23+ /// GLOBAL is a static type that holding all global data.
24+ static GLOBAL : OnceCell < Container ! [ Send + Sync ] > = OnceCell :: new ( ) ;
25+
26+ #[ cfg( debug_assertions) ]
27+ /// LOCAL is a static type that holding all global data only for local tests.
28+ static LOCAL : OnceCell <
29+ parking_lot:: RwLock < std:: collections:: HashMap < String , Container ! [ Send + Sync ] > > ,
30+ > = OnceCell :: new ( ) ;
31+
2032/// Singleton is a wrapper enum for `Container![Send + Sync]`.
2133///
2234/// - `Production` is used in our production code.
2335/// - `Testing` is served for test only and gated under `debug_assertions`.
24- pub enum Singleton {
25- Production ( Container ! [ Send + Sync ] ) ,
36+ pub enum SingletonType {
37+ Production ,
2638
2739 #[ cfg( debug_assertions) ]
28- Testing ( parking_lot :: Mutex < std :: collections :: HashMap < String , Container ! [ Send + Sync ] > > ) ,
40+ Testing ,
2941}
3042
31- unsafe impl Send for Singleton { }
32- unsafe impl Sync for Singleton { }
33-
34- impl Singleton {
43+ impl SingletonType {
3544 fn get < T : Clone + ' static > ( & self ) -> T {
3645 match self {
37- Singleton :: Production ( c ) => {
38- let v: & T = c . get ( ) ;
46+ SingletonType :: Production => {
47+ let v: & T = GLOBAL . wait ( ) . get ( ) ;
3948 v. clone ( )
4049 }
4150 #[ cfg( debug_assertions) ]
42- Singleton :: Testing ( c) => {
43- let thread = std:: thread:: current ( ) ;
44- let thread_name = match thread. name ( ) {
45- Some ( name) => name,
46- None => panic ! ( "thread doesn't have name" ) ,
47- } ;
48- let guard = c. lock ( ) ;
51+ SingletonType :: Testing => {
52+ let thread_name = std:: thread:: current ( )
53+ . name ( )
54+ . expect ( "thread doesn't have name" )
55+ . to_string ( ) ;
56+ let guard = LOCAL . wait ( ) . read ( ) ;
4957 let v: & T = guard
50- . get ( thread_name)
58+ . get ( & thread_name)
5159 . unwrap_or_else ( || panic ! ( "thread {thread_name} is not initiated" ) )
5260 . get ( ) ;
5361 v. clone ( )
@@ -57,37 +65,35 @@ impl Singleton {
5765
5866 fn set < T : Send + Sync + ' static > ( & self , value : T ) -> bool {
5967 match self {
60- Singleton :: Production ( c ) => c . set ( value) ,
68+ SingletonType :: Production => GLOBAL . wait ( ) . set ( value) ,
6169 #[ cfg( debug_assertions) ]
62- Singleton :: Testing ( c) => {
63- let thread = std:: thread:: current ( ) ;
64- let thread_name = match thread. name ( ) {
65- Some ( name) => name,
66- None => panic ! ( "thread doesn't have name" ) ,
67- } ;
68- let mut guard = c. lock ( ) ;
69- let c = guard. entry ( thread_name. to_string ( ) ) . or_default ( ) ;
70- c. set ( value)
70+ SingletonType :: Testing => {
71+ let thread_name = std:: thread:: current ( )
72+ . name ( )
73+ . expect ( "thread doesn't have name" )
74+ . to_string ( ) ;
75+ let guard = LOCAL . wait ( ) . read ( ) ;
76+ guard
77+ . get ( & thread_name)
78+ . unwrap_or_else ( || panic ! ( "thread {thread_name} is not initiated" ) )
79+ . set ( value)
7180 }
7281 }
7382 }
7483}
7584
76- impl Debug for Singleton {
85+ impl Debug for SingletonType {
7786 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
7887 f. debug_struct ( "Singleton" )
7988 . field ( "type" , & match self {
80- Self :: Production ( _ ) => "Production" ,
89+ Self :: Production => "Production" ,
8190 #[ cfg( debug_assertions) ]
82- Self :: Testing ( _ ) => "Testing" ,
91+ Self :: Testing => "Testing" ,
8392 } )
8493 . finish ( )
8594 }
8695}
8796
88- /// GLOBAL is a static type that holding all global data.
89- static GLOBAL : OnceCell < Singleton > = OnceCell :: new ( ) ;
90-
9197/// Global is an empty struct that only used to carry associated functions.
9298pub struct GlobalInstance ;
9399
@@ -96,44 +102,48 @@ impl GlobalInstance {
96102 ///
97103 /// Should only be initiated once.
98104 pub fn init_production ( ) {
99- let _ = GLOBAL . set ( Singleton :: Production ( <Container ! [ Send + Sync ] >:: new ( ) ) ) ;
105+ let _ = SINGLETON_TYPE . set ( SingletonType :: Production ) ;
106+ let _ = GLOBAL . set ( <Container ! [ Send + Sync ] >:: new ( ) ) ;
100107 }
101108
102109 /// init testing global data registry.
103110 ///
104111 /// Should only be initiated once and only used in testing.
105112 #[ cfg( debug_assertions) ]
106- pub fn init_testing ( ) {
107- let _ = GLOBAL . set ( Singleton :: Testing ( parking_lot:: Mutex :: default ( ) ) ) ;
113+ pub fn init_testing ( thread_name : & str ) {
114+ let _ = SINGLETON_TYPE . set ( SingletonType :: Testing ) ;
115+ let _ = LOCAL . set ( parking_lot:: RwLock :: default ( ) ) ;
116+
117+ let v = LOCAL
118+ . wait ( )
119+ . write ( )
120+ . insert ( thread_name. to_string ( ) , <Container ! [ Send + Sync ] >:: new ( ) ) ;
121+ assert ! (
122+ v. is_none( ) ,
123+ "thread {thread_name} has been initiated before"
124+ )
108125 }
109126
110127 /// drop testing global data by thread name.
111128 ///
112129 /// Should only be used in testing code.
113130 #[ cfg( debug_assertions) ]
114131 pub fn drop_testing ( thread_name : & str ) {
115- match GLOBAL . wait ( ) {
116- Singleton :: Production ( _) => {
117- unreachable ! ( "drop_testing should never be called on production global" )
118- }
119- Singleton :: Testing ( c) => {
120- let mut guard = c. lock ( ) ;
121- let _ = guard. remove ( thread_name) ;
122- }
123- }
132+ // Make sure the write lock is released before alling drop.
133+ let _ = { LOCAL . wait ( ) . write ( ) . remove ( thread_name) } ;
124134 }
125135
126136 /// Get data from global data registry.
127137 pub fn get < T : Clone + ' static > ( ) -> T {
128- GLOBAL
138+ SINGLETON_TYPE
129139 . get ( )
130140 . expect ( "global data registry must be initiated" )
131141 . get ( )
132142 }
133143
134144 /// Set data into global data registry.
135145 pub fn set < T : Send + Sync + ' static > ( value : T ) {
136- let set = GLOBAL
146+ let set = SINGLETON_TYPE
137147 . get ( )
138148 . expect ( "global data registry must be initiated" )
139149 . set ( value) ;
0 commit comments