1mod since_v0_0_1;
2mod since_v0_0_4;
3mod since_v0_0_6;
4mod since_v0_1_0;
5mod since_v0_2_0;
6mod since_v0_3_0;
7mod since_v0_4_0;
8mod since_v0_5_0;
9use extension::{KeyValueStoreDelegate, WorktreeDelegate};
10use language::LanguageName;
11use lsp::LanguageServerName;
12use release_channel::ReleaseChannel;
13use since_v0_5_0 as latest;
14
15use super::{WasmState, wasm_engine};
16use anyhow::{Context as _, Result, anyhow};
17use semantic_version::SemanticVersion;
18use std::{ops::RangeInclusive, sync::Arc};
19use wasmtime::{
20 Store,
21 component::{Component, Linker, Resource},
22};
23
24#[cfg(test)]
25pub use latest::CodeLabelSpanLiteral;
26pub use latest::{
27 CodeLabel, CodeLabelSpan, Command, ExtensionProject, Range, SlashCommand,
28 zed::extension::context_server::ContextServerConfiguration,
29 zed::extension::lsp::{
30 Completion, CompletionKind, CompletionLabelDetails, InsertTextFormat, Symbol, SymbolKind,
31 },
32 zed::extension::slash_command::{SlashCommandArgumentCompletion, SlashCommandOutput},
33};
34pub use since_v0_0_4::LanguageServerConfig;
35
36pub fn new_linker(
37 f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
38) -> Linker<WasmState> {
39 let mut linker = Linker::new(&wasm_engine());
40 wasmtime_wasi::add_to_linker_async(&mut linker).unwrap();
41 f(&mut linker, wasi_view).unwrap();
42 linker
43}
44
45fn wasi_view(state: &mut WasmState) -> &mut WasmState {
46 state
47}
48
49/// Returns whether the given Wasm API version is supported by the Wasm host.
50pub fn is_supported_wasm_api_version(
51 release_channel: ReleaseChannel,
52 version: SemanticVersion,
53) -> bool {
54 wasm_api_version_range(release_channel).contains(&version)
55}
56
57/// Returns the Wasm API version range that is supported by the Wasm host.
58#[inline(always)]
59pub fn wasm_api_version_range(release_channel: ReleaseChannel) -> RangeInclusive<SemanticVersion> {
60 // Note: The release channel can be used to stage a new version of the extension API.
61 let _ = release_channel;
62
63 let max_version = match release_channel {
64 ReleaseChannel::Dev | ReleaseChannel::Nightly => latest::MAX_VERSION,
65 ReleaseChannel::Stable | ReleaseChannel::Preview => latest::MAX_VERSION,
66 };
67
68 since_v0_0_1::MIN_VERSION..=max_version
69}
70
71/// Authorizes access to use unreleased versions of the Wasm API, based on the provided [`ReleaseChannel`].
72///
73/// Note: If there isn't currently an unreleased Wasm API version this function may be unused. Don't delete it!
74pub fn authorize_access_to_unreleased_wasm_api_version(
75 release_channel: ReleaseChannel,
76) -> Result<()> {
77 let allow_unreleased_version = match release_channel {
78 ReleaseChannel::Dev | ReleaseChannel::Nightly => true,
79 ReleaseChannel::Stable | ReleaseChannel::Preview => {
80 // We always allow the latest in tests so that the extension tests pass on release branches.
81 cfg!(any(test, feature = "test-support"))
82 }
83 };
84
85 if !allow_unreleased_version {
86 Err(anyhow!(
87 "unreleased versions of the extension API can only be used on development builds of Zed"
88 ))?;
89 }
90
91 Ok(())
92}
93
94pub enum Extension {
95 V0_5_0(since_v0_5_0::Extension),
96 V0_4_0(since_v0_4_0::Extension),
97 V0_3_0(since_v0_3_0::Extension),
98 V0_2_0(since_v0_2_0::Extension),
99 V0_1_0(since_v0_1_0::Extension),
100 V0_0_6(since_v0_0_6::Extension),
101 V0_0_4(since_v0_0_4::Extension),
102 V0_0_1(since_v0_0_1::Extension),
103}
104
105impl Extension {
106 pub async fn instantiate_async(
107 store: &mut Store<WasmState>,
108 release_channel: ReleaseChannel,
109 version: SemanticVersion,
110 component: &Component,
111 ) -> Result<Self> {
112 // Note: The release channel can be used to stage a new version of the extension API.
113 let _ = release_channel;
114
115 if version >= latest::MIN_VERSION {
116 let extension =
117 latest::Extension::instantiate_async(store, component, latest::linker())
118 .await
119 .context("failed to instantiate wasm extension")?;
120 Ok(Self::V0_5_0(extension))
121 } else if version >= since_v0_4_0::MIN_VERSION {
122 let extension = since_v0_4_0::Extension::instantiate_async(
123 store,
124 component,
125 since_v0_4_0::linker(),
126 )
127 .await
128 .context("failed to instantiate wasm extension")?;
129 Ok(Self::V0_4_0(extension))
130 } else if version >= since_v0_3_0::MIN_VERSION {
131 let extension = since_v0_3_0::Extension::instantiate_async(
132 store,
133 component,
134 since_v0_3_0::linker(),
135 )
136 .await
137 .context("failed to instantiate wasm extension")?;
138 Ok(Self::V0_3_0(extension))
139 } else if version >= since_v0_2_0::MIN_VERSION {
140 let extension = since_v0_2_0::Extension::instantiate_async(
141 store,
142 component,
143 since_v0_2_0::linker(),
144 )
145 .await
146 .context("failed to instantiate wasm extension")?;
147 Ok(Self::V0_2_0(extension))
148 } else if version >= since_v0_1_0::MIN_VERSION {
149 let extension = since_v0_1_0::Extension::instantiate_async(
150 store,
151 component,
152 since_v0_1_0::linker(),
153 )
154 .await
155 .context("failed to instantiate wasm extension")?;
156 Ok(Self::V0_1_0(extension))
157 } else if version >= since_v0_0_6::MIN_VERSION {
158 let extension = since_v0_0_6::Extension::instantiate_async(
159 store,
160 component,
161 since_v0_0_6::linker(),
162 )
163 .await
164 .context("failed to instantiate wasm extension")?;
165 Ok(Self::V0_0_6(extension))
166 } else if version >= since_v0_0_4::MIN_VERSION {
167 let extension = since_v0_0_4::Extension::instantiate_async(
168 store,
169 component,
170 since_v0_0_4::linker(),
171 )
172 .await
173 .context("failed to instantiate wasm extension")?;
174 Ok(Self::V0_0_4(extension))
175 } else {
176 let extension = since_v0_0_1::Extension::instantiate_async(
177 store,
178 component,
179 since_v0_0_1::linker(),
180 )
181 .await
182 .context("failed to instantiate wasm extension")?;
183 Ok(Self::V0_0_1(extension))
184 }
185 }
186
187 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
188 match self {
189 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
190 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
191 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
192 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
193 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
194 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
195 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
196 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
197 }
198 }
199
200 pub async fn call_language_server_command(
201 &self,
202 store: &mut Store<WasmState>,
203 language_server_id: &LanguageServerName,
204 language_name: &LanguageName,
205 resource: Resource<Arc<dyn WorktreeDelegate>>,
206 ) -> Result<Result<Command, String>> {
207 match self {
208 Extension::V0_5_0(ext) => {
209 ext.call_language_server_command(store, &language_server_id.0, resource)
210 .await
211 }
212 Extension::V0_4_0(ext) => {
213 ext.call_language_server_command(store, &language_server_id.0, resource)
214 .await
215 }
216 Extension::V0_3_0(ext) => {
217 ext.call_language_server_command(store, &language_server_id.0, resource)
218 .await
219 }
220 Extension::V0_2_0(ext) => Ok(ext
221 .call_language_server_command(store, &language_server_id.0, resource)
222 .await?
223 .map(|command| command.into())),
224 Extension::V0_1_0(ext) => Ok(ext
225 .call_language_server_command(store, &language_server_id.0, resource)
226 .await?
227 .map(|command| command.into())),
228 Extension::V0_0_6(ext) => Ok(ext
229 .call_language_server_command(store, &language_server_id.0, resource)
230 .await?
231 .map(|command| command.into())),
232 Extension::V0_0_4(ext) => Ok(ext
233 .call_language_server_command(
234 store,
235 &LanguageServerConfig {
236 name: language_server_id.0.to_string(),
237 language_name: language_name.to_string(),
238 },
239 resource,
240 )
241 .await?
242 .map(|command| command.into())),
243 Extension::V0_0_1(ext) => Ok(ext
244 .call_language_server_command(
245 store,
246 &LanguageServerConfig {
247 name: language_server_id.0.to_string(),
248 language_name: language_name.to_string(),
249 }
250 .into(),
251 resource,
252 )
253 .await?
254 .map(|command| command.into())),
255 }
256 }
257
258 pub async fn call_language_server_initialization_options(
259 &self,
260 store: &mut Store<WasmState>,
261 language_server_id: &LanguageServerName,
262 language_name: &LanguageName,
263 resource: Resource<Arc<dyn WorktreeDelegate>>,
264 ) -> Result<Result<Option<String>, String>> {
265 match self {
266 Extension::V0_5_0(ext) => {
267 ext.call_language_server_initialization_options(
268 store,
269 &language_server_id.0,
270 resource,
271 )
272 .await
273 }
274 Extension::V0_4_0(ext) => {
275 ext.call_language_server_initialization_options(
276 store,
277 &language_server_id.0,
278 resource,
279 )
280 .await
281 }
282 Extension::V0_3_0(ext) => {
283 ext.call_language_server_initialization_options(
284 store,
285 &language_server_id.0,
286 resource,
287 )
288 .await
289 }
290 Extension::V0_2_0(ext) => {
291 ext.call_language_server_initialization_options(
292 store,
293 &language_server_id.0,
294 resource,
295 )
296 .await
297 }
298 Extension::V0_1_0(ext) => {
299 ext.call_language_server_initialization_options(
300 store,
301 &language_server_id.0,
302 resource,
303 )
304 .await
305 }
306 Extension::V0_0_6(ext) => {
307 ext.call_language_server_initialization_options(
308 store,
309 &language_server_id.0,
310 resource,
311 )
312 .await
313 }
314 Extension::V0_0_4(ext) => {
315 ext.call_language_server_initialization_options(
316 store,
317 &LanguageServerConfig {
318 name: language_server_id.0.to_string(),
319 language_name: language_name.to_string(),
320 },
321 resource,
322 )
323 .await
324 }
325 Extension::V0_0_1(ext) => {
326 ext.call_language_server_initialization_options(
327 store,
328 &LanguageServerConfig {
329 name: language_server_id.0.to_string(),
330 language_name: language_name.to_string(),
331 }
332 .into(),
333 resource,
334 )
335 .await
336 }
337 }
338 }
339
340 pub async fn call_language_server_workspace_configuration(
341 &self,
342 store: &mut Store<WasmState>,
343 language_server_id: &LanguageServerName,
344 resource: Resource<Arc<dyn WorktreeDelegate>>,
345 ) -> Result<Result<Option<String>, String>> {
346 match self {
347 Extension::V0_5_0(ext) => {
348 ext.call_language_server_workspace_configuration(
349 store,
350 &language_server_id.0,
351 resource,
352 )
353 .await
354 }
355 Extension::V0_4_0(ext) => {
356 ext.call_language_server_workspace_configuration(
357 store,
358 &language_server_id.0,
359 resource,
360 )
361 .await
362 }
363 Extension::V0_3_0(ext) => {
364 ext.call_language_server_workspace_configuration(
365 store,
366 &language_server_id.0,
367 resource,
368 )
369 .await
370 }
371 Extension::V0_2_0(ext) => {
372 ext.call_language_server_workspace_configuration(
373 store,
374 &language_server_id.0,
375 resource,
376 )
377 .await
378 }
379 Extension::V0_1_0(ext) => {
380 ext.call_language_server_workspace_configuration(
381 store,
382 &language_server_id.0,
383 resource,
384 )
385 .await
386 }
387 Extension::V0_0_6(ext) => {
388 ext.call_language_server_workspace_configuration(
389 store,
390 &language_server_id.0,
391 resource,
392 )
393 .await
394 }
395 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
396 }
397 }
398
399 pub async fn call_language_server_additional_initialization_options(
400 &self,
401 store: &mut Store<WasmState>,
402 language_server_id: &LanguageServerName,
403 target_language_server_id: &LanguageServerName,
404 resource: Resource<Arc<dyn WorktreeDelegate>>,
405 ) -> Result<Result<Option<String>, String>> {
406 match self {
407 Extension::V0_5_0(ext) => {
408 ext.call_language_server_additional_initialization_options(
409 store,
410 &language_server_id.0,
411 &target_language_server_id.0,
412 resource,
413 )
414 .await
415 }
416 Extension::V0_4_0(ext) => {
417 ext.call_language_server_additional_initialization_options(
418 store,
419 &language_server_id.0,
420 &target_language_server_id.0,
421 resource,
422 )
423 .await
424 }
425 Extension::V0_3_0(_)
426 | Extension::V0_2_0(_)
427 | Extension::V0_1_0(_)
428 | Extension::V0_0_6(_)
429 | Extension::V0_0_4(_)
430 | Extension::V0_0_1(_) => Ok(Ok(None)),
431 }
432 }
433
434 pub async fn call_language_server_additional_workspace_configuration(
435 &self,
436 store: &mut Store<WasmState>,
437 language_server_id: &LanguageServerName,
438 target_language_server_id: &LanguageServerName,
439 resource: Resource<Arc<dyn WorktreeDelegate>>,
440 ) -> Result<Result<Option<String>, String>> {
441 match self {
442 Extension::V0_5_0(ext) => {
443 ext.call_language_server_additional_workspace_configuration(
444 store,
445 &language_server_id.0,
446 &target_language_server_id.0,
447 resource,
448 )
449 .await
450 }
451 Extension::V0_4_0(ext) => {
452 ext.call_language_server_additional_workspace_configuration(
453 store,
454 &language_server_id.0,
455 &target_language_server_id.0,
456 resource,
457 )
458 .await
459 }
460 Extension::V0_3_0(_)
461 | Extension::V0_2_0(_)
462 | Extension::V0_1_0(_)
463 | Extension::V0_0_6(_)
464 | Extension::V0_0_4(_)
465 | Extension::V0_0_1(_) => Ok(Ok(None)),
466 }
467 }
468
469 pub async fn call_labels_for_completions(
470 &self,
471 store: &mut Store<WasmState>,
472 language_server_id: &LanguageServerName,
473 completions: Vec<latest::Completion>,
474 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
475 match self {
476 Extension::V0_5_0(ext) => {
477 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
478 .await
479 }
480 Extension::V0_4_0(ext) => Ok(ext
481 .call_labels_for_completions(
482 store,
483 &language_server_id.0,
484 &completions.into_iter().collect::<Vec<_>>(),
485 )
486 .await?
487 .map(|labels| {
488 labels
489 .into_iter()
490 .map(|label| label.map(Into::into))
491 .collect()
492 })),
493 Extension::V0_3_0(ext) => Ok(ext
494 .call_labels_for_completions(
495 store,
496 &language_server_id.0,
497 &completions.into_iter().collect::<Vec<_>>(),
498 )
499 .await?
500 .map(|labels| {
501 labels
502 .into_iter()
503 .map(|label| label.map(Into::into))
504 .collect()
505 })),
506 Extension::V0_2_0(ext) => Ok(ext
507 .call_labels_for_completions(
508 store,
509 &language_server_id.0,
510 &completions.into_iter().collect::<Vec<_>>(),
511 )
512 .await?
513 .map(|labels| {
514 labels
515 .into_iter()
516 .map(|label| label.map(Into::into))
517 .collect()
518 })),
519 Extension::V0_1_0(ext) => Ok(ext
520 .call_labels_for_completions(
521 store,
522 &language_server_id.0,
523 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
524 )
525 .await?
526 .map(|labels| {
527 labels
528 .into_iter()
529 .map(|label| label.map(Into::into))
530 .collect()
531 })),
532 Extension::V0_0_6(ext) => Ok(ext
533 .call_labels_for_completions(
534 store,
535 &language_server_id.0,
536 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
537 )
538 .await?
539 .map(|labels| {
540 labels
541 .into_iter()
542 .map(|label| label.map(Into::into))
543 .collect()
544 })),
545 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
546 }
547 }
548
549 pub async fn call_labels_for_symbols(
550 &self,
551 store: &mut Store<WasmState>,
552 language_server_id: &LanguageServerName,
553 symbols: Vec<latest::Symbol>,
554 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
555 match self {
556 Extension::V0_5_0(ext) => {
557 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
558 .await
559 }
560 Extension::V0_4_0(ext) => Ok(ext
561 .call_labels_for_symbols(
562 store,
563 &language_server_id.0,
564 &symbols.into_iter().collect::<Vec<_>>(),
565 )
566 .await?
567 .map(|labels| {
568 labels
569 .into_iter()
570 .map(|label| label.map(Into::into))
571 .collect()
572 })),
573 Extension::V0_3_0(ext) => Ok(ext
574 .call_labels_for_symbols(
575 store,
576 &language_server_id.0,
577 &symbols.into_iter().collect::<Vec<_>>(),
578 )
579 .await?
580 .map(|labels| {
581 labels
582 .into_iter()
583 .map(|label| label.map(Into::into))
584 .collect()
585 })),
586 Extension::V0_2_0(ext) => Ok(ext
587 .call_labels_for_symbols(
588 store,
589 &language_server_id.0,
590 &symbols.into_iter().collect::<Vec<_>>(),
591 )
592 .await?
593 .map(|labels| {
594 labels
595 .into_iter()
596 .map(|label| label.map(Into::into))
597 .collect()
598 })),
599 Extension::V0_1_0(ext) => Ok(ext
600 .call_labels_for_symbols(
601 store,
602 &language_server_id.0,
603 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
604 )
605 .await?
606 .map(|labels| {
607 labels
608 .into_iter()
609 .map(|label| label.map(Into::into))
610 .collect()
611 })),
612 Extension::V0_0_6(ext) => Ok(ext
613 .call_labels_for_symbols(
614 store,
615 &language_server_id.0,
616 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
617 )
618 .await?
619 .map(|labels| {
620 labels
621 .into_iter()
622 .map(|label| label.map(Into::into))
623 .collect()
624 })),
625 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
626 }
627 }
628
629 pub async fn call_complete_slash_command_argument(
630 &self,
631 store: &mut Store<WasmState>,
632 command: &SlashCommand,
633 arguments: &[String],
634 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
635 match self {
636 Extension::V0_5_0(ext) => {
637 ext.call_complete_slash_command_argument(store, command, arguments)
638 .await
639 }
640 Extension::V0_4_0(ext) => {
641 ext.call_complete_slash_command_argument(store, command, arguments)
642 .await
643 }
644 Extension::V0_3_0(ext) => {
645 ext.call_complete_slash_command_argument(store, command, arguments)
646 .await
647 }
648 Extension::V0_2_0(ext) => {
649 ext.call_complete_slash_command_argument(store, command, arguments)
650 .await
651 }
652 Extension::V0_1_0(ext) => {
653 ext.call_complete_slash_command_argument(store, command, arguments)
654 .await
655 }
656 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
657 Ok(Ok(Vec::new()))
658 }
659 }
660 }
661
662 pub async fn call_run_slash_command(
663 &self,
664 store: &mut Store<WasmState>,
665 command: &SlashCommand,
666 arguments: &[String],
667 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
668 ) -> Result<Result<SlashCommandOutput, String>> {
669 match self {
670 Extension::V0_5_0(ext) => {
671 ext.call_run_slash_command(store, command, arguments, resource)
672 .await
673 }
674 Extension::V0_4_0(ext) => {
675 ext.call_run_slash_command(store, command, arguments, resource)
676 .await
677 }
678 Extension::V0_3_0(ext) => {
679 ext.call_run_slash_command(store, command, arguments, resource)
680 .await
681 }
682 Extension::V0_2_0(ext) => {
683 ext.call_run_slash_command(store, command, arguments, resource)
684 .await
685 }
686 Extension::V0_1_0(ext) => {
687 ext.call_run_slash_command(store, command, arguments, resource)
688 .await
689 }
690 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
691 Err(anyhow!("`run_slash_command` not available prior to v0.1.0"))
692 }
693 }
694 }
695
696 pub async fn call_context_server_command(
697 &self,
698 store: &mut Store<WasmState>,
699 context_server_id: Arc<str>,
700 project: Resource<ExtensionProject>,
701 ) -> Result<Result<Command, String>> {
702 match self {
703 Extension::V0_5_0(ext) => {
704 ext.call_context_server_command(store, &context_server_id, project)
705 .await
706 }
707 Extension::V0_4_0(ext) => {
708 ext.call_context_server_command(store, &context_server_id, project)
709 .await
710 }
711 Extension::V0_3_0(ext) => {
712 ext.call_context_server_command(store, &context_server_id, project)
713 .await
714 }
715 Extension::V0_2_0(ext) => Ok(ext
716 .call_context_server_command(store, &context_server_id, project)
717 .await?
718 .map(Into::into)),
719 Extension::V0_0_1(_)
720 | Extension::V0_0_4(_)
721 | Extension::V0_0_6(_)
722 | Extension::V0_1_0(_) => Err(anyhow!(
723 "`context_server_command` not available prior to v0.2.0"
724 )),
725 }
726 }
727
728 pub async fn call_context_server_configuration(
729 &self,
730 store: &mut Store<WasmState>,
731 context_server_id: Arc<str>,
732 project: Resource<ExtensionProject>,
733 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
734 match self {
735 Extension::V0_5_0(ext) => {
736 ext.call_context_server_configuration(store, &context_server_id, project)
737 .await
738 }
739 Extension::V0_0_1(_)
740 | Extension::V0_0_4(_)
741 | Extension::V0_0_6(_)
742 | Extension::V0_1_0(_)
743 | Extension::V0_2_0(_)
744 | Extension::V0_3_0(_)
745 | Extension::V0_4_0(_) => Err(anyhow!(
746 "`context_server_configuration` not available prior to v0.5.0"
747 )),
748 }
749 }
750
751 pub async fn call_suggest_docs_packages(
752 &self,
753 store: &mut Store<WasmState>,
754 provider: &str,
755 ) -> Result<Result<Vec<String>, String>> {
756 match self {
757 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
758 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
759 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
760 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
761 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
762 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => Err(anyhow!(
763 "`suggest_docs_packages` not available prior to v0.1.0"
764 )),
765 }
766 }
767
768 pub async fn call_index_docs(
769 &self,
770 store: &mut Store<WasmState>,
771 provider: &str,
772 package_name: &str,
773 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
774 ) -> Result<Result<(), String>> {
775 match self {
776 Extension::V0_5_0(ext) => {
777 ext.call_index_docs(store, provider, package_name, kv_store)
778 .await
779 }
780 Extension::V0_4_0(ext) => {
781 ext.call_index_docs(store, provider, package_name, kv_store)
782 .await
783 }
784 Extension::V0_3_0(ext) => {
785 ext.call_index_docs(store, provider, package_name, kv_store)
786 .await
787 }
788 Extension::V0_2_0(ext) => {
789 ext.call_index_docs(store, provider, package_name, kv_store)
790 .await
791 }
792 Extension::V0_1_0(ext) => {
793 ext.call_index_docs(store, provider, package_name, kv_store)
794 .await
795 }
796 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
797 Err(anyhow!("`index_docs` not available prior to v0.1.0"))
798 }
799 }
800 }
801}
802
803trait ToWasmtimeResult<T> {
804 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
805}
806
807impl<T> ToWasmtimeResult<T> for Result<T> {
808 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
809 Ok(self.map_err(|error| format!("{error:?}")))
810 }
811}