aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/server/src')
-rw-r--r--crates/server/src/dispatch.rs18
-rw-r--r--crates/server/src/main.rs5
-rw-r--r--crates/server/src/main_loop/handlers.rs25
-rw-r--r--crates/server/src/main_loop/mod.rs108
4 files changed, 106 insertions, 50 deletions
diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs
index d8cca48d0..806534944 100644
--- a/crates/server/src/dispatch.rs
+++ b/crates/server/src/dispatch.rs
@@ -58,20 +58,18 @@ fn parse_request_as<R: ClientRequest>(raw: RawRequest)
58 Ok(Ok((params, responder))) 58 Ok(Ok((params, responder)))
59} 59}
60 60
61pub fn handle_request<R, F>(req: &mut Option<RawRequest>, f: F) -> Result<()> 61pub fn handle_request<R, F>(req: RawRequest, f: F) -> Result<::std::result::Result<u64, RawRequest>>
62 where 62 where
63 R: ClientRequest, 63 R: ClientRequest,
64 F: FnOnce(R::Params, Responder<R>) -> Result<()> 64 F: FnOnce(R::Params, Responder<R>) -> Result<()>
65{ 65{
66 match req.take() { 66 let id = req.id;
67 None => Ok(()), 67 match parse_request_as::<R>(req)? {
68 Some(r) => match parse_request_as::<R>(r)? { 68 Ok((params, responder)) => {
69 Ok((params, responder)) => f(params, responder), 69 let () = f(params, responder)?;
70 Err(r) => { 70 Ok(Ok(id))
71 *req = Some(r); 71 },
72 Ok(()) 72 Err(r) => Ok(Err(r)),
73 }
74 }
75 } 73 }
76} 74}
77 75
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs
index 6af8bf81b..eeb343b80 100644
--- a/crates/server/src/main.rs
+++ b/crates/server/src/main.rs
@@ -84,14 +84,13 @@ fn initialize(io: &mut Io) -> Result<()> {
84 bail!("expected initialize request, got {:?}", res), 84 bail!("expected initialize request, got {:?}", res),
85 85
86 RawMsg::Request(req) => { 86 RawMsg::Request(req) => {
87 let mut req = Some(req); 87 let req = dispatch::handle_request::<req::Initialize, _>(req, |_params, resp| {
88 dispatch::handle_request::<req::Initialize, _>(&mut req, |_params, resp| {
89 let res = req::InitializeResult { capabilities: caps::server_capabilities() }; 88 let res = req::InitializeResult { capabilities: caps::server_capabilities() };
90 let resp = resp.into_response(Ok(res))?; 89 let resp = resp.into_response(Ok(res))?;
91 io.send(RawMsg::Response(resp)); 90 io.send(RawMsg::Response(resp));
92 Ok(()) 91 Ok(())
93 })?; 92 })?;
94 if let Some(req) = req { 93 if let Err(req) = req {
95 bail!("expected initialize request, got {:?}", req) 94 bail!("expected initialize request, got {:?}", req)
96 } 95 }
97 match io.recv()? { 96 match io.recv()? {
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};
9use serde_json::to_value; 9use serde_json::to_value;
10use libanalysis::{Query, FileId, RunnableKind}; 10use libanalysis::{Query, FileId, RunnableKind, JobToken};
11use libsyntax2::{ 11use libsyntax2::{
12 text_utils::contains_offset_nonstrict, 12 text_utils::contains_offset_nonstrict,
13}; 13};
@@ -21,6 +21,7 @@ use ::{
21pub fn handle_syntax_tree( 21pub 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(
30pub fn handle_extend_selection( 31pub 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(
45pub fn handle_find_matching_brace( 47pub 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(
63pub fn handle_join_lines( 66pub 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(
74pub fn handle_on_type_formatting( 78pub 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(
93pub fn handle_document_symbol( 98pub 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(
131pub fn handle_workspace_symbol( 137pub 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(
175pub fn handle_goto_definition( 182pub 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(
194pub fn handle_parent_module( 202pub 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(
211pub fn handle_runnables( 220pub 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(
260pub fn handle_decorations( 270pub 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(
268pub fn handle_completion( 279pub 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(
297pub fn handle_code_action( 309pub 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;
2mod subscriptions; 2mod subscriptions;
3 3
4use std::{ 4use std::{
5 collections::{HashSet}, 5 collections::{HashMap},
6}; 6};
7 7
8use threadpool::ThreadPool; 8use threadpool::ThreadPool;
9use crossbeam_channel::{Sender, Receiver}; 9use crossbeam_channel::{Sender, Receiver};
10use libanalysis::FileId; 10use languageserver_types::{NumberOrString};
11use libanalysis::{FileId, JobHandle, JobToken};
11 12
12use { 13use {
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(
109fn on_request( 112fn 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(
154fn on_notification( 166fn 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
197struct PoolDispatcher<'a> { 222struct 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
204impl<'a> PoolDispatcher<'a> { 230impl<'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
226fn update_file_notifications_on_threadpool( 272fn update_file_notifications_on_threadpool(