@@ -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 :: RwLock < 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. read ( ) ;
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,39 +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 guard = c. read ( ) ;
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 ( ) ;
6976 guard
70- . get ( thread_name)
77+ . get ( & thread_name)
7178 . unwrap_or_else ( || panic ! ( "thread {thread_name} is not initiated" ) )
7279 . set ( value)
7380 }
7481 }
7582 }
7683}
7784
78- impl Debug for Singleton {
85+ impl Debug for SingletonType {
7986 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
8087 f. debug_struct ( "Singleton" )
8188 . field ( "type" , & match self {
82- Self :: Production ( _ ) => "Production" ,
89+ Self :: Production => "Production" ,
8390 #[ cfg( debug_assertions) ]
84- Self :: Testing ( _ ) => "Testing" ,
91+ Self :: Testing => "Testing" ,
8592 } )
8693 . finish ( )
8794 }
8895}
8996
90- /// GLOBAL is a static type that holding all global data.
91- static GLOBAL : OnceCell < Singleton > = OnceCell :: new ( ) ;
92-
9397/// Global is an empty struct that only used to carry associated functions.
9498pub struct GlobalInstance ;
9599
@@ -98,48 +102,47 @@ impl GlobalInstance {
98102 ///
99103 /// Should only be initiated once.
100104 pub fn init_production ( ) {
101- let _ = GLOBAL . set ( Singleton :: Production ( <Container ! [ Send + Sync ] >:: new ( ) ) ) ;
105+ let _ = SINGLETON_TYPE . set ( SingletonType :: Production ) ;
106+ let _ = GLOBAL . set ( <Container ! [ Send + Sync ] >:: new ( ) ) ;
102107 }
103108
104109 /// init testing global data registry.
105110 ///
106111 /// Should only be initiated once and only used in testing.
107112 #[ cfg( debug_assertions) ]
108113 pub fn init_testing ( thread_name : & str ) {
109- let _ = GLOBAL . set ( Singleton :: Testing ( parking_lot:: RwLock :: default ( ) ) ) ;
110- if let Singleton :: Testing ( v) = GLOBAL . wait ( ) {
111- let mut guard = v. write ( ) ;
112- guard. insert ( thread_name. to_string ( ) , <Container ! [ Send + Sync ] >:: new ( ) ) ;
113- }
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+ )
114125 }
115126
116127 /// drop testing global data by thread name.
117128 ///
118129 /// Should only be used in testing code.
119130 #[ cfg( debug_assertions) ]
120131 pub fn drop_testing ( thread_name : & str ) {
121- match GLOBAL . wait ( ) {
122- Singleton :: Production ( _) => {
123- unreachable ! ( "drop_testing should never be called on production global" )
124- }
125- Singleton :: Testing ( c) => {
126- let mut guard = c. write ( ) ;
127- guard. remove ( thread_name) ;
128- }
129- }
132+ LOCAL . wait ( ) . write ( ) . remove ( thread_name) ;
130133 }
131134
132135 /// Get data from global data registry.
133136 pub fn get < T : Clone + ' static > ( ) -> T {
134- GLOBAL
137+ SINGLETON_TYPE
135138 . get ( )
136139 . expect ( "global data registry must be initiated" )
137140 . get ( )
138141 }
139142
140143 /// Set data into global data registry.
141144 pub fn set < T : Send + Sync + ' static > ( value : T ) {
142- let set = GLOBAL
145+ let set = SINGLETON_TYPE
143146 . get ( )
144147 . expect ( "global data registry must be initiated" )
145148 . set ( value) ;
0 commit comments