1
1
use crate :: Task ;
2
2
use linkme:: distributed_slice;
3
+ use std:: sync:: OnceLock ;
3
4
4
5
/// Compat encapsulate functions to find async runtimes to spawn task.
5
6
pub enum Compat {
7
+ /// Named global function to spawn task.
8
+ NamedGlobal { name : & ' static str , spawn : fn ( Task ) } ,
6
9
/// Global function to spawn task.
7
- ///
8
- /// [spawn](`crate::spawn()`) will panic if there is no local spawners but multiple global spawners.
10
+ # [ doc ( hidden ) ]
11
+ # [ deprecated ( since = "1.0.3" , note = "use NamedGlobal instead" ) ]
9
12
Global ( fn ( Task ) ) ,
10
13
#[ allow( clippy:: type_complexity) ]
11
14
/// Local function to detect async runtimes.
@@ -16,33 +19,85 @@ pub enum Compat {
16
19
#[ distributed_slice]
17
20
pub static COMPATS : [ Compat ] = [ ..] ;
18
21
19
- pub ( crate ) fn find_spawn ( ) -> Option < fn ( Task ) > {
20
- match COMPATS . len ( ) {
21
- 0 => return None ,
22
- 1 => match COMPATS [ 0 ] {
23
- Compat :: Global ( inject) => return Some ( inject) ,
24
- Compat :: Local ( detect) => return detect ( ) ,
25
- } ,
26
- _ => { }
27
- }
22
+ #[ derive( Clone , Copy ) ]
23
+ pub ( crate ) enum Failure {
24
+ NotFound ,
25
+ #[ allow( dead_code) ]
26
+ MultipleGlobals ,
27
+ }
28
28
29
- let mut last_global = None ;
29
+ fn pick_global ( choose : Option < & str > ) -> Result < fn ( Task ) , Failure > {
30
30
let mut globals = 0 ;
31
- match COMPATS . iter ( ) . find_map ( |injection| match injection {
32
- Compat :: Local ( local) => local ( ) ,
31
+ let mut last_named = None ;
32
+ let mut last_unnamed = None ;
33
+ match COMPATS . iter ( ) . find_map ( |compat| match compat {
34
+ Compat :: Local ( _) => None ,
35
+ #[ allow( deprecated) ]
33
36
Compat :: Global ( global) => {
34
37
globals += 1 ;
35
- last_global = Some ( global) ;
38
+ last_unnamed = Some ( global) ;
36
39
None
37
40
}
41
+ Compat :: NamedGlobal { spawn, name } => {
42
+ if choose == Some ( name) {
43
+ Some ( spawn)
44
+ } else {
45
+ globals += 1 ;
46
+ last_named = Some ( spawn) ;
47
+ None
48
+ }
49
+ }
38
50
} ) {
39
- Some ( spawn) => Some ( spawn) ,
51
+ Some ( spawn) => Ok ( * spawn) ,
40
52
None => {
41
53
#[ cfg( feature = "panic-multiple-global-spawners" ) ]
42
54
if globals > 1 {
43
- panic ! ( "multiple global spawners" )
55
+ return Err ( Failure :: MultipleGlobals ) ;
44
56
}
45
- last_global. copied ( )
57
+ last_named
58
+ . or ( last_unnamed)
59
+ . ok_or ( Failure :: NotFound )
60
+ . copied ( )
46
61
}
47
62
}
48
63
}
64
+
65
+ fn find_global ( ) -> Result < fn ( Task ) , Failure > {
66
+ static FOUND : OnceLock < Result < fn ( Task ) , Failure > > = OnceLock :: new ( ) ;
67
+ if let Some ( found) = FOUND . get ( ) {
68
+ return * found;
69
+ }
70
+ let choose = std:: env:: var ( "SPAWNS_GLOBAL_SPAWNER" ) . ok ( ) ;
71
+ let result = pick_global ( choose. as_deref ( ) ) ;
72
+ * FOUND . get_or_init ( || result)
73
+ }
74
+
75
+ fn find_local ( ) -> Option < fn ( Task ) > {
76
+ COMPATS . iter ( ) . find_map ( |compat| match compat {
77
+ Compat :: Local ( local) => local ( ) ,
78
+ #[ allow( deprecated) ]
79
+ Compat :: Global ( _) => None ,
80
+ Compat :: NamedGlobal { .. } => None ,
81
+ } )
82
+ }
83
+
84
+ pub ( crate ) fn find_spawn ( ) -> Option < fn ( Task ) > {
85
+ match COMPATS . len ( ) {
86
+ 0 => return None ,
87
+ 1 => match COMPATS [ 0 ] {
88
+ Compat :: NamedGlobal { spawn, .. } => return Some ( spawn) ,
89
+ #[ allow( deprecated) ]
90
+ Compat :: Global ( spawn) => return Some ( spawn) ,
91
+ Compat :: Local ( local) => return local ( ) ,
92
+ } ,
93
+ _ => { }
94
+ }
95
+ match find_local ( )
96
+ . ok_or ( Failure :: NotFound )
97
+ . or_else ( |_| find_global ( ) )
98
+ {
99
+ Ok ( spawn) => Some ( spawn) ,
100
+ Err ( Failure :: NotFound ) => None ,
101
+ Err ( Failure :: MultipleGlobals ) => panic ! ( "multiple global spawners" ) ,
102
+ }
103
+ }
0 commit comments