1
- //! A visitor for downcasting arbitrary request (JSON) into a specific type .
1
+ //! See [RequestDispatcher] .
2
2
use std:: { fmt, panic, thread} ;
3
3
4
4
use serde:: { de:: DeserializeOwned , Serialize } ;
@@ -10,14 +10,30 @@ use crate::{
10
10
LspError , Result ,
11
11
} ;
12
12
13
+ /// A visitor for routing a raw JSON request to an appropriate handler function.
14
+ ///
15
+ /// Most requests are read-only and async and are handled on the threadpool
16
+ /// (`on` method).
17
+ ///
18
+ /// Some read-only requests are latency sensitive, and are immediately handled
19
+ /// on the main loop thread (`on_sync`). These are typically typing-related
20
+ /// requests.
21
+ ///
22
+ /// Some requests modify the state, and are run on the main thread to get
23
+ /// `&mut`.
24
+ ///
25
+ /// Read-only requests are wrapped into `catch_unwind` -- they don't modify the
26
+ /// state, so it's OK to recover from their failures.
13
27
pub ( crate ) struct RequestDispatcher < ' a > {
14
28
pub ( crate ) req : Option < lsp_server:: Request > ,
15
29
pub ( crate ) global_state : & ' a mut GlobalState ,
16
30
}
17
31
18
32
impl < ' a > RequestDispatcher < ' a > {
19
- /// Dispatches the request onto the current thread
20
- pub ( crate ) fn on_sync < R > (
33
+ /// Dispatches the request onto the current thread, given full access to
34
+ /// mutable global state. Unlike all other methods here, this one isn't
35
+ /// guarded by `catch_unwind`, so, please, don't make bugs :-)
36
+ pub ( crate ) fn on_sync_mut < R > (
21
37
& mut self ,
22
38
f : fn ( & mut GlobalState , R :: Params ) -> Result < R :: Result > ,
23
39
) -> Result < & mut Self >
@@ -26,26 +42,40 @@ impl<'a> RequestDispatcher<'a> {
26
42
R :: Params : DeserializeOwned + panic:: UnwindSafe + fmt:: Debug + ' static ,
27
43
R :: Result : Serialize + ' static ,
28
44
{
29
- let ( id, params) = match self . parse :: < R > ( ) {
45
+ let ( id, params, panic_context ) = match self . parse :: < R > ( ) {
30
46
Some ( it) => it,
31
47
None => return Ok ( self ) ,
32
48
} ;
33
- let global_state = panic:: AssertUnwindSafe ( & mut * self . global_state ) ;
49
+ let _pctx = stdx:: panic_context:: enter ( panic_context) ;
50
+
51
+ let result = f ( & mut self . global_state , params) ;
52
+ let response = result_to_response :: < R > ( id, result) ;
53
+
54
+ self . global_state . respond ( response) ;
55
+ Ok ( self )
56
+ }
57
+
58
+ /// Dispatches the request onto the current thread.
59
+ pub ( crate ) fn on_sync < R > (
60
+ & mut self ,
61
+ f : fn ( GlobalStateSnapshot , R :: Params ) -> Result < R :: Result > ,
62
+ ) -> Result < & mut Self >
63
+ where
64
+ R : lsp_types:: request:: Request + ' static ,
65
+ R :: Params : DeserializeOwned + panic:: UnwindSafe + fmt:: Debug + ' static ,
66
+ R :: Result : Serialize + ' static ,
67
+ {
68
+ let ( id, params, panic_context) = match self . parse :: < R > ( ) {
69
+ Some ( it) => it,
70
+ None => return Ok ( self ) ,
71
+ } ;
72
+ let global_state_snapshot = self . global_state . snapshot ( ) ;
34
73
35
74
let result = panic:: catch_unwind ( move || {
36
- // Make sure that the whole AssertUnwindSafe is moved into the
37
- // closure, and not just its field.
38
- let panic:: AssertUnwindSafe ( global_state) = { global_state } ;
39
-
40
- let _pctx = stdx:: panic_context:: enter ( format ! (
41
- "\n version: {}\n request: {} {:#?}" ,
42
- env!( "REV" ) ,
43
- R :: METHOD ,
44
- params
45
- ) ) ;
46
- f ( global_state, params)
75
+ let _pctx = stdx:: panic_context:: enter ( panic_context) ;
76
+ f ( global_state_snapshot, params)
47
77
} ) ;
48
- let response = result_to_response :: < R > ( id, result) ;
78
+ let response = thread_result_to_response :: < R > ( id, result) ;
49
79
50
80
self . global_state . respond ( response) ;
51
81
Ok ( self )
@@ -61,7 +91,7 @@ impl<'a> RequestDispatcher<'a> {
61
91
R :: Params : DeserializeOwned + panic:: UnwindSafe + Send + fmt:: Debug + ' static ,
62
92
R :: Result : Serialize + ' static ,
63
93
{
64
- let ( id, params) = match self . parse :: < R > ( ) {
94
+ let ( id, params, panic_context ) = match self . parse :: < R > ( ) {
65
95
Some ( it) => it,
66
96
None => return self ,
67
97
} ;
@@ -70,15 +100,10 @@ impl<'a> RequestDispatcher<'a> {
70
100
let world = self . global_state . snapshot ( ) ;
71
101
move || {
72
102
let result = panic:: catch_unwind ( move || {
73
- let _pctx = stdx:: panic_context:: enter ( format ! (
74
- "\n version: {}\n request: {} {:#?}" ,
75
- env!( "REV" ) ,
76
- R :: METHOD ,
77
- params
78
- ) ) ;
103
+ let _pctx = stdx:: panic_context:: enter ( panic_context) ;
79
104
f ( world, params)
80
105
} ) ;
81
- let response = result_to_response :: < R > ( id, result) ;
106
+ let response = thread_result_to_response :: < R > ( id, result) ;
82
107
Task :: Response ( response)
83
108
}
84
109
} ) ;
@@ -98,10 +123,10 @@ impl<'a> RequestDispatcher<'a> {
98
123
}
99
124
}
100
125
101
- fn parse < R > ( & mut self ) -> Option < ( lsp_server:: RequestId , R :: Params ) >
126
+ fn parse < R > ( & mut self ) -> Option < ( lsp_server:: RequestId , R :: Params , String ) >
102
127
where
103
128
R : lsp_types:: request:: Request + ' static ,
104
- R :: Params : DeserializeOwned + ' static ,
129
+ R :: Params : DeserializeOwned + fmt :: Debug + ' static ,
105
130
{
106
131
let req = match & self . req {
107
132
Some ( req) if req. method == R :: METHOD => self . req . take ( ) . unwrap ( ) ,
@@ -110,7 +135,11 @@ impl<'a> RequestDispatcher<'a> {
110
135
111
136
let res = crate :: from_json ( R :: METHOD , req. params ) ;
112
137
match res {
113
- Ok ( params) => Some ( ( req. id , params) ) ,
138
+ Ok ( params) => {
139
+ let panic_context =
140
+ format ! ( "\n version: {}\n request: {} {:#?}" , env!( "REV" ) , R :: METHOD , params) ;
141
+ Some ( ( req. id , params, panic_context) )
142
+ }
114
143
Err ( err) => {
115
144
let response = lsp_server:: Response :: new_err (
116
145
req. id ,
@@ -124,7 +153,7 @@ impl<'a> RequestDispatcher<'a> {
124
153
}
125
154
}
126
155
127
- fn result_to_response < R > (
156
+ fn thread_result_to_response < R > (
128
157
id : lsp_server:: RequestId ,
129
158
result : thread:: Result < Result < R :: Result > > ,
130
159
) -> lsp_server:: Response
@@ -134,8 +163,37 @@ where
134
163
R :: Result : Serialize + ' static ,
135
164
{
136
165
match result {
137
- Ok ( Ok ( resp) ) => lsp_server:: Response :: new_ok ( id, & resp) ,
138
- Ok ( Err ( e) ) => match e. downcast :: < LspError > ( ) {
166
+ Ok ( result) => result_to_response :: < R > ( id, result) ,
167
+ Err ( panic) => {
168
+ let mut message = "server panicked" . to_string ( ) ;
169
+
170
+ let panic_message = panic
171
+ . downcast_ref :: < String > ( )
172
+ . map ( String :: as_str)
173
+ . or_else ( || panic. downcast_ref :: < & str > ( ) . copied ( ) ) ;
174
+
175
+ if let Some ( panic_message) = panic_message {
176
+ message. push_str ( ": " ) ;
177
+ message. push_str ( panic_message)
178
+ } ;
179
+
180
+ lsp_server:: Response :: new_err ( id, lsp_server:: ErrorCode :: InternalError as i32 , message)
181
+ }
182
+ }
183
+ }
184
+
185
+ fn result_to_response < R > (
186
+ id : lsp_server:: RequestId ,
187
+ result : Result < R :: Result > ,
188
+ ) -> lsp_server:: Response
189
+ where
190
+ R : lsp_types:: request:: Request + ' static ,
191
+ R :: Params : DeserializeOwned + ' static ,
192
+ R :: Result : Serialize + ' static ,
193
+ {
194
+ match result {
195
+ Ok ( resp) => lsp_server:: Response :: new_ok ( id, & resp) ,
196
+ Err ( e) => match e. downcast :: < LspError > ( ) {
139
197
Ok ( lsp_error) => lsp_server:: Response :: new_err ( id, lsp_error. code , lsp_error. message ) ,
140
198
Err ( e) => {
141
199
if is_cancelled ( & * e) {
@@ -153,21 +211,6 @@ where
153
211
}
154
212
}
155
213
} ,
156
- Err ( panic) => {
157
- let mut message = "server panicked" . to_string ( ) ;
158
-
159
- let panic_message = panic
160
- . downcast_ref :: < String > ( )
161
- . map ( String :: as_str)
162
- . or_else ( || panic. downcast_ref :: < & str > ( ) . copied ( ) ) ;
163
-
164
- if let Some ( panic_message) = panic_message {
165
- message. push_str ( ": " ) ;
166
- message. push_str ( panic_message)
167
- } ;
168
-
169
- lsp_server:: Response :: new_err ( id, lsp_server:: ErrorCode :: InternalError as i32 , message)
170
- }
171
214
}
172
215
}
173
216
0 commit comments