diff options
Diffstat (limited to 'crates/server/src/main_loop')
-rw-r--r-- | crates/server/src/main_loop/handlers.rs | 25 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 108 |
2 files changed, 96 insertions, 37 deletions
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 6b70399b0..ab8b6f799 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs | |||
@@ -7,7 +7,7 @@ use languageserver_types::{ | |||
7 | CompletionItem, InsertTextFormat, CompletionItemKind, | 7 | CompletionItem, InsertTextFormat, CompletionItemKind, |
8 | }; | 8 | }; |
9 | use serde_json::to_value; | 9 | use serde_json::to_value; |
10 | use libanalysis::{Query, FileId, RunnableKind}; | 10 | use libanalysis::{Query, FileId, RunnableKind, JobToken}; |
11 | use libsyntax2::{ | 11 | use libsyntax2::{ |
12 | text_utils::contains_offset_nonstrict, | 12 | text_utils::contains_offset_nonstrict, |
13 | }; | 13 | }; |
@@ -21,6 +21,7 @@ use ::{ | |||
21 | pub fn handle_syntax_tree( | 21 | pub fn handle_syntax_tree( |
22 | world: ServerWorld, | 22 | world: ServerWorld, |
23 | params: req::SyntaxTreeParams, | 23 | params: req::SyntaxTreeParams, |
24 | _token: JobToken, | ||
24 | ) -> Result<String> { | 25 | ) -> Result<String> { |
25 | let id = params.text_document.try_conv_with(&world)?; | 26 | let id = params.text_document.try_conv_with(&world)?; |
26 | let res = world.analysis().syntax_tree(id); | 27 | let res = world.analysis().syntax_tree(id); |
@@ -30,6 +31,7 @@ pub fn handle_syntax_tree( | |||
30 | pub fn handle_extend_selection( | 31 | pub fn handle_extend_selection( |
31 | world: ServerWorld, | 32 | world: ServerWorld, |
32 | params: req::ExtendSelectionParams, | 33 | params: req::ExtendSelectionParams, |
34 | _token: JobToken, | ||
33 | ) -> Result<req::ExtendSelectionResult> { | 35 | ) -> Result<req::ExtendSelectionResult> { |
34 | let file_id = params.text_document.try_conv_with(&world)?; | 36 | let file_id = params.text_document.try_conv_with(&world)?; |
35 | let file = world.analysis().file_syntax(file_id); | 37 | let file = world.analysis().file_syntax(file_id); |
@@ -45,6 +47,7 @@ pub fn handle_extend_selection( | |||
45 | pub fn handle_find_matching_brace( | 47 | pub fn handle_find_matching_brace( |
46 | world: ServerWorld, | 48 | world: ServerWorld, |
47 | params: req::FindMatchingBraceParams, | 49 | params: req::FindMatchingBraceParams, |
50 | _token: JobToken, | ||
48 | ) -> Result<Vec<Position>> { | 51 | ) -> Result<Vec<Position>> { |
49 | let file_id = params.text_document.try_conv_with(&world)?; | 52 | let file_id = params.text_document.try_conv_with(&world)?; |
50 | let file = world.analysis().file_syntax(file_id); | 53 | let file = world.analysis().file_syntax(file_id); |
@@ -63,6 +66,7 @@ pub fn handle_find_matching_brace( | |||
63 | pub fn handle_join_lines( | 66 | pub fn handle_join_lines( |
64 | world: ServerWorld, | 67 | world: ServerWorld, |
65 | params: req::JoinLinesParams, | 68 | params: req::JoinLinesParams, |
69 | _token: JobToken, | ||
66 | ) -> Result<req::SourceChange> { | 70 | ) -> Result<req::SourceChange> { |
67 | let file_id = params.text_document.try_conv_with(&world)?; | 71 | let file_id = params.text_document.try_conv_with(&world)?; |
68 | let line_index = world.analysis().file_line_index(file_id); | 72 | let line_index = world.analysis().file_line_index(file_id); |
@@ -74,6 +78,7 @@ pub fn handle_join_lines( | |||
74 | pub fn handle_on_type_formatting( | 78 | pub fn handle_on_type_formatting( |
75 | world: ServerWorld, | 79 | world: ServerWorld, |
76 | params: req::DocumentOnTypeFormattingParams, | 80 | params: req::DocumentOnTypeFormattingParams, |
81 | _token: JobToken, | ||
77 | ) -> Result<Option<Vec<TextEdit>>> { | 82 | ) -> Result<Option<Vec<TextEdit>>> { |
78 | if params.ch != "=" { | 83 | if params.ch != "=" { |
79 | return Ok(None); | 84 | return Ok(None); |
@@ -93,6 +98,7 @@ pub fn handle_on_type_formatting( | |||
93 | pub fn handle_document_symbol( | 98 | pub fn handle_document_symbol( |
94 | world: ServerWorld, | 99 | world: ServerWorld, |
95 | params: req::DocumentSymbolParams, | 100 | params: req::DocumentSymbolParams, |
101 | _token: JobToken, | ||
96 | ) -> Result<Option<req::DocumentSymbolResponse>> { | 102 | ) -> Result<Option<req::DocumentSymbolResponse>> { |
97 | let file_id = params.text_document.try_conv_with(&world)?; | 103 | let file_id = params.text_document.try_conv_with(&world)?; |
98 | let line_index = world.analysis().file_line_index(file_id); | 104 | let line_index = world.analysis().file_line_index(file_id); |
@@ -131,6 +137,7 @@ pub fn handle_document_symbol( | |||
131 | pub fn handle_workspace_symbol( | 137 | pub fn handle_workspace_symbol( |
132 | world: ServerWorld, | 138 | world: ServerWorld, |
133 | params: req::WorkspaceSymbolParams, | 139 | params: req::WorkspaceSymbolParams, |
140 | token: JobToken, | ||
134 | ) -> Result<Option<Vec<SymbolInformation>>> { | 141 | ) -> Result<Option<Vec<SymbolInformation>>> { |
135 | let all_symbols = params.query.contains("#"); | 142 | let all_symbols = params.query.contains("#"); |
136 | let query = { | 143 | let query = { |
@@ -144,18 +151,18 @@ pub fn handle_workspace_symbol( | |||
144 | q.limit(128); | 151 | q.limit(128); |
145 | q | 152 | q |
146 | }; | 153 | }; |
147 | let mut res = exec_query(&world, query)?; | 154 | let mut res = exec_query(&world, query, &token)?; |
148 | if res.is_empty() && !all_symbols { | 155 | if res.is_empty() && !all_symbols { |
149 | let mut query = Query::new(params.query); | 156 | let mut query = Query::new(params.query); |
150 | query.limit(128); | 157 | query.limit(128); |
151 | res = exec_query(&world, query)?; | 158 | res = exec_query(&world, query, &token)?; |
152 | } | 159 | } |
153 | 160 | ||
154 | return Ok(Some(res)); | 161 | return Ok(Some(res)); |
155 | 162 | ||
156 | fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> { | 163 | fn exec_query(world: &ServerWorld, query: Query, token: &JobToken) -> Result<Vec<SymbolInformation>> { |
157 | let mut res = Vec::new(); | 164 | let mut res = Vec::new(); |
158 | for (file_id, symbol) in world.analysis().symbol_search(query) { | 165 | for (file_id, symbol) in world.analysis().symbol_search(query, token) { |
159 | let line_index = world.analysis().file_line_index(file_id); | 166 | let line_index = world.analysis().file_line_index(file_id); |
160 | let info = SymbolInformation { | 167 | let info = SymbolInformation { |
161 | name: symbol.name.to_string(), | 168 | name: symbol.name.to_string(), |
@@ -175,12 +182,13 @@ pub fn handle_workspace_symbol( | |||
175 | pub fn handle_goto_definition( | 182 | pub fn handle_goto_definition( |
176 | world: ServerWorld, | 183 | world: ServerWorld, |
177 | params: req::TextDocumentPositionParams, | 184 | params: req::TextDocumentPositionParams, |
185 | token: JobToken, | ||
178 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 186 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
179 | let file_id = params.text_document.try_conv_with(&world)?; | 187 | let file_id = params.text_document.try_conv_with(&world)?; |
180 | let line_index = world.analysis().file_line_index(file_id); | 188 | let line_index = world.analysis().file_line_index(file_id); |
181 | let offset = params.position.conv_with(&line_index); | 189 | let offset = params.position.conv_with(&line_index); |
182 | let mut res = Vec::new(); | 190 | let mut res = Vec::new(); |
183 | for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset) { | 191 | for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset, &token) { |
184 | let line_index = world.analysis().file_line_index(file_id); | 192 | let line_index = world.analysis().file_line_index(file_id); |
185 | let location = to_location( | 193 | let location = to_location( |
186 | file_id, symbol.node_range, | 194 | file_id, symbol.node_range, |
@@ -194,6 +202,7 @@ pub fn handle_goto_definition( | |||
194 | pub fn handle_parent_module( | 202 | pub fn handle_parent_module( |
195 | world: ServerWorld, | 203 | world: ServerWorld, |
196 | params: TextDocumentIdentifier, | 204 | params: TextDocumentIdentifier, |
205 | _token: JobToken, | ||
197 | ) -> Result<Vec<Location>> { | 206 | ) -> Result<Vec<Location>> { |
198 | let file_id = params.try_conv_with(&world)?; | 207 | let file_id = params.try_conv_with(&world)?; |
199 | let mut res = Vec::new(); | 208 | let mut res = Vec::new(); |
@@ -211,6 +220,7 @@ pub fn handle_parent_module( | |||
211 | pub fn handle_runnables( | 220 | pub fn handle_runnables( |
212 | world: ServerWorld, | 221 | world: ServerWorld, |
213 | params: req::RunnablesParams, | 222 | params: req::RunnablesParams, |
223 | _token: JobToken, | ||
214 | ) -> Result<Vec<req::Runnable>> { | 224 | ) -> Result<Vec<req::Runnable>> { |
215 | let file_id = params.text_document.try_conv_with(&world)?; | 225 | let file_id = params.text_document.try_conv_with(&world)?; |
216 | let line_index = world.analysis().file_line_index(file_id); | 226 | let line_index = world.analysis().file_line_index(file_id); |
@@ -260,6 +270,7 @@ pub fn handle_runnables( | |||
260 | pub fn handle_decorations( | 270 | pub fn handle_decorations( |
261 | world: ServerWorld, | 271 | world: ServerWorld, |
262 | params: TextDocumentIdentifier, | 272 | params: TextDocumentIdentifier, |
273 | _token: JobToken, | ||
263 | ) -> Result<Vec<Decoration>> { | 274 | ) -> Result<Vec<Decoration>> { |
264 | let file_id = params.try_conv_with(&world)?; | 275 | let file_id = params.try_conv_with(&world)?; |
265 | Ok(highlight(&world, file_id)) | 276 | Ok(highlight(&world, file_id)) |
@@ -268,6 +279,7 @@ pub fn handle_decorations( | |||
268 | pub fn handle_completion( | 279 | pub fn handle_completion( |
269 | world: ServerWorld, | 280 | world: ServerWorld, |
270 | params: req::CompletionParams, | 281 | params: req::CompletionParams, |
282 | _token: JobToken, | ||
271 | ) -> Result<Option<req::CompletionResponse>> { | 283 | ) -> Result<Option<req::CompletionResponse>> { |
272 | let file_id = params.text_document.try_conv_with(&world)?; | 284 | let file_id = params.text_document.try_conv_with(&world)?; |
273 | let line_index = world.analysis().file_line_index(file_id); | 285 | let line_index = world.analysis().file_line_index(file_id); |
@@ -297,6 +309,7 @@ pub fn handle_completion( | |||
297 | pub fn handle_code_action( | 309 | pub fn handle_code_action( |
298 | world: ServerWorld, | 310 | world: ServerWorld, |
299 | params: req::CodeActionParams, | 311 | params: req::CodeActionParams, |
312 | _token: JobToken, | ||
300 | ) -> Result<Option<Vec<Command>>> { | 313 | ) -> Result<Option<Vec<Command>>> { |
301 | let file_id = params.text_document.try_conv_with(&world)?; | 314 | let file_id = params.text_document.try_conv_with(&world)?; |
302 | let line_index = world.analysis().file_line_index(file_id); | 315 | let line_index = world.analysis().file_line_index(file_id); |
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index cd17cab56..db7d5ae34 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -2,12 +2,13 @@ mod handlers; | |||
2 | mod subscriptions; | 2 | mod subscriptions; |
3 | 3 | ||
4 | use std::{ | 4 | use std::{ |
5 | collections::{HashSet}, | 5 | collections::{HashMap}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use threadpool::ThreadPool; | 8 | use threadpool::ThreadPool; |
9 | use crossbeam_channel::{Sender, Receiver}; | 9 | use crossbeam_channel::{Sender, Receiver}; |
10 | use libanalysis::FileId; | 10 | use languageserver_types::{NumberOrString}; |
11 | use libanalysis::{FileId, JobHandle, JobToken}; | ||
11 | 12 | ||
12 | use { | 13 | use { |
13 | req, dispatch, | 14 | req, dispatch, |
@@ -28,7 +29,7 @@ pub(super) fn main_loop( | |||
28 | info!("server initialized, serving requests"); | 29 | info!("server initialized, serving requests"); |
29 | let mut state = ServerWorldState::new(); | 30 | let mut state = ServerWorldState::new(); |
30 | 31 | ||
31 | let mut pending_requests: HashSet<u64> = HashSet::new(); | 32 | let mut pending_requests: HashMap<u64, JobHandle> = HashMap::new(); |
32 | let mut fs_events_receiver = Some(&fs_events_receiver); | 33 | let mut fs_events_receiver = Some(&fs_events_receiver); |
33 | let mut subs = Subscriptions::new(); | 34 | let mut subs = Subscriptions::new(); |
34 | loop { | 35 | loop { |
@@ -61,8 +62,12 @@ pub(super) fn main_loop( | |||
61 | } | 62 | } |
62 | Event::Task(task) => { | 63 | Event::Task(task) => { |
63 | match task { | 64 | match task { |
64 | Task::Respond(response) => | 65 | Task::Respond(response) => { |
65 | io.send(RawMsg::Response(response)), | 66 | if let Some(handle) = pending_requests.remove(&response.id) { |
67 | assert!(handle.has_completed()); | ||
68 | } | ||
69 | io.send(RawMsg::Response(response)) | ||
70 | } | ||
66 | Task::Notify(n) => | 71 | Task::Notify(n) => |
67 | io.send(RawMsg::Notification(n)), | 72 | io.send(RawMsg::Notification(n)), |
68 | Task::Die(error) => | 73 | Task::Die(error) => |
@@ -78,18 +83,16 @@ pub(super) fn main_loop( | |||
78 | Event::Msg(msg) => { | 83 | Event::Msg(msg) => { |
79 | match msg { | 84 | match msg { |
80 | RawMsg::Request(req) => { | 85 | RawMsg::Request(req) => { |
81 | if !on_request(io, &mut state, pool, &task_sender, req)? { | 86 | if !on_request(io, &mut state, &mut pending_requests, pool, &task_sender, req)? { |
82 | return Ok(()); | 87 | return Ok(()); |
83 | } | 88 | } |
84 | } | 89 | } |
85 | RawMsg::Notification(not) => { | 90 | RawMsg::Notification(not) => { |
86 | on_notification(io, &mut state, &mut subs, not)?; | 91 | on_notification(io, &mut state, &mut pending_requests, &mut subs, not)?; |
87 | state_changed = true; | 92 | state_changed = true; |
88 | } | 93 | } |
89 | RawMsg::Response(resp) => { | 94 | RawMsg::Response(resp) => { |
90 | if !pending_requests.remove(&resp.id) { | 95 | error!("unexpected response: {:?}", resp) |
91 | error!("unexpected response: {:?}", resp) | ||
92 | } | ||
93 | } | 96 | } |
94 | } | 97 | } |
95 | } | 98 | } |
@@ -109,15 +112,17 @@ pub(super) fn main_loop( | |||
109 | fn on_request( | 112 | fn on_request( |
110 | io: &mut Io, | 113 | io: &mut Io, |
111 | world: &mut ServerWorldState, | 114 | world: &mut ServerWorldState, |
115 | pending_requests: &mut HashMap<u64, JobHandle>, | ||
112 | pool: &ThreadPool, | 116 | pool: &ThreadPool, |
113 | sender: &Sender<Task>, | 117 | sender: &Sender<Task>, |
114 | req: RawRequest, | 118 | req: RawRequest, |
115 | ) -> Result<bool> { | 119 | ) -> Result<bool> { |
116 | let mut pool_dispatcher = PoolDispatcher { | 120 | let mut pool_dispatcher = PoolDispatcher { |
117 | req: Some(req), | 121 | req: Some(req), |
122 | res: None, | ||
118 | pool, world, sender | 123 | pool, world, sender |
119 | }; | 124 | }; |
120 | pool_dispatcher | 125 | let req = pool_dispatcher |
121 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? | 126 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? |
122 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? | 127 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? |
123 | .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)? | 128 | .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)? |
@@ -130,23 +135,30 @@ fn on_request( | |||
130 | .on::<req::Runnables>(handlers::handle_runnables)? | 135 | .on::<req::Runnables>(handlers::handle_runnables)? |
131 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? | 136 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? |
132 | .on::<req::Completion>(handlers::handle_completion)? | 137 | .on::<req::Completion>(handlers::handle_completion)? |
133 | .on::<req::CodeActionRequest>(handlers::handle_code_action)?; | 138 | .on::<req::CodeActionRequest>(handlers::handle_code_action)? |
134 | 139 | .finish(); | |
135 | let mut req = pool_dispatcher.req; | 140 | match req { |
136 | let mut shutdown = false; | 141 | Ok((id, handle)) => { |
137 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { | 142 | let inserted = pending_requests.insert(id, handle).is_none(); |
138 | let resp = resp.into_response(Ok(()))?; | 143 | assert!(inserted, "duplicate request: {}", id); |
139 | io.send(RawMsg::Response(resp)); | 144 | }, |
140 | shutdown = true; | 145 | Err(req) => { |
141 | Ok(()) | 146 | let req = dispatch::handle_request::<req::Shutdown, _>(req, |(), resp| { |
142 | })?; | 147 | let resp = resp.into_response(Ok(()))?; |
143 | if shutdown { | 148 | io.send(RawMsg::Response(resp)); |
144 | info!("lifecycle: initiating shutdown"); | 149 | Ok(()) |
145 | return Ok(false); | 150 | })?; |
146 | } | 151 | match req { |
147 | if let Some(req) = req { | 152 | Ok(_id) => { |
148 | error!("unknown method: {:?}", req); | 153 | info!("lifecycle: initiating shutdown"); |
149 | io.send(RawMsg::Response(dispatch::unknown_method(req.id)?)); | 154 | return Ok(false); |
155 | } | ||
156 | Err(req) => { | ||
157 | error!("unknown method: {:?}", req); | ||
158 | io.send(RawMsg::Response(dispatch::unknown_method(req.id)?)); | ||
159 | } | ||
160 | } | ||
161 | } | ||
150 | } | 162 | } |
151 | Ok(true) | 163 | Ok(true) |
152 | } | 164 | } |
@@ -154,10 +166,23 @@ fn on_request( | |||
154 | fn on_notification( | 166 | fn on_notification( |
155 | io: &mut Io, | 167 | io: &mut Io, |
156 | state: &mut ServerWorldState, | 168 | state: &mut ServerWorldState, |
169 | pending_requests: &mut HashMap<u64, JobHandle>, | ||
157 | subs: &mut Subscriptions, | 170 | subs: &mut Subscriptions, |
158 | not: RawNotification, | 171 | not: RawNotification, |
159 | ) -> Result<()> { | 172 | ) -> Result<()> { |
160 | let mut not = Some(not); | 173 | let mut not = Some(not); |
174 | dispatch::handle_notification::<req::Cancel, _>(&mut not, |params| { | ||
175 | let id = match params.id { | ||
176 | NumberOrString::Number(id) => id, | ||
177 | NumberOrString::String(id) => { | ||
178 | panic!("string id's not supported: {:?}", id); | ||
179 | } | ||
180 | }; | ||
181 | if let Some(handle) = pending_requests.remove(&id) { | ||
182 | handle.cancel(); | ||
183 | } | ||
184 | Ok(()) | ||
185 | })?; | ||
161 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | 186 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { |
162 | let uri = params.text_document.uri; | 187 | let uri = params.text_document.uri; |
163 | let path = uri.to_file_path() | 188 | let path = uri.to_file_path() |
@@ -196,21 +221,30 @@ fn on_notification( | |||
196 | 221 | ||
197 | struct PoolDispatcher<'a> { | 222 | struct PoolDispatcher<'a> { |
198 | req: Option<RawRequest>, | 223 | req: Option<RawRequest>, |
224 | res: Option<(u64, JobHandle)>, | ||
199 | pool: &'a ThreadPool, | 225 | pool: &'a ThreadPool, |
200 | world: &'a ServerWorldState, | 226 | world: &'a ServerWorldState, |
201 | sender: &'a Sender<Task>, | 227 | sender: &'a Sender<Task>, |
202 | } | 228 | } |
203 | 229 | ||
204 | impl<'a> PoolDispatcher<'a> { | 230 | impl<'a> PoolDispatcher<'a> { |
205 | fn on<'b, R: req::ClientRequest>(&'b mut self, f: fn(ServerWorld, R::Params) -> Result<R::Result>) -> Result<&'b mut Self> { | 231 | fn on<'b, R: req::ClientRequest>( |
232 | &'b mut self, | ||
233 | f: fn(ServerWorld, R::Params, JobToken) -> Result<R::Result> | ||
234 | ) -> Result<&'b mut Self> { | ||
235 | let req = match self.req.take() { | ||
236 | None => return Ok(self), | ||
237 | Some(req) => req, | ||
238 | }; | ||
206 | let world = self.world; | 239 | let world = self.world; |
207 | let sender = self.sender; | 240 | let sender = self.sender; |
208 | let pool = self.pool; | 241 | let pool = self.pool; |
209 | dispatch::handle_request::<R, _>(&mut self.req, |params, resp| { | 242 | let (handle, token) = JobHandle::new(); |
243 | let req = dispatch::handle_request::<R, _>(req, |params, resp| { | ||
210 | let world = world.snapshot(); | 244 | let world = world.snapshot(); |
211 | let sender = sender.clone(); | 245 | let sender = sender.clone(); |
212 | pool.execute(move || { | 246 | pool.execute(move || { |
213 | let res = f(world, params); | 247 | let res = f(world, params, token); |
214 | let task = match resp.into_response(res) { | 248 | let task = match resp.into_response(res) { |
215 | Ok(resp) => Task::Respond(resp), | 249 | Ok(resp) => Task::Respond(resp), |
216 | Err(e) => Task::Die(e), | 250 | Err(e) => Task::Die(e), |
@@ -219,8 +253,20 @@ impl<'a> PoolDispatcher<'a> { | |||
219 | }); | 253 | }); |
220 | Ok(()) | 254 | Ok(()) |
221 | })?; | 255 | })?; |
256 | match req { | ||
257 | Ok(id) => self.res = Some((id, handle)), | ||
258 | Err(req) => self.req = Some(req), | ||
259 | } | ||
222 | Ok(self) | 260 | Ok(self) |
223 | } | 261 | } |
262 | |||
263 | fn finish(&mut self) -> ::std::result::Result<(u64, JobHandle), RawRequest> { | ||
264 | match (self.res.take(), self.req.take()) { | ||
265 | (Some(res), None) => Ok(res), | ||
266 | (None, Some(req)) => Err(req), | ||
267 | _ => unreachable!(), | ||
268 | } | ||
269 | } | ||
224 | } | 270 | } |
225 | 271 | ||
226 | fn update_file_notifications_on_threadpool( | 272 | fn update_file_notifications_on_threadpool( |