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 => since_v0_4_0::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 authorize_access_to_unreleased_wasm_api_version(release_channel)?;
117
118 let extension =
119 latest::Extension::instantiate_async(store, component, latest::linker())
120 .await
121 .context("failed to instantiate wasm extension")?;
122 Ok(Self::V0_5_0(extension))
123 } else if version >= since_v0_4_0::MIN_VERSION {
124 let extension = since_v0_4_0::Extension::instantiate_async(
125 store,
126 component,
127 since_v0_4_0::linker(),
128 )
129 .await
130 .context("failed to instantiate wasm extension")?;
131 Ok(Self::V0_4_0(extension))
132 } else if version >= since_v0_3_0::MIN_VERSION {
133 let extension = since_v0_3_0::Extension::instantiate_async(
134 store,
135 component,
136 since_v0_3_0::linker(),
137 )
138 .await
139 .context("failed to instantiate wasm extension")?;
140 Ok(Self::V0_3_0(extension))
141 } else if version >= since_v0_2_0::MIN_VERSION {
142 let extension = since_v0_2_0::Extension::instantiate_async(
143 store,
144 component,
145 since_v0_2_0::linker(),
146 )
147 .await
148 .context("failed to instantiate wasm extension")?;
149 Ok(Self::V0_2_0(extension))
150 } else if version >= since_v0_1_0::MIN_VERSION {
151 let extension = since_v0_1_0::Extension::instantiate_async(
152 store,
153 component,
154 since_v0_1_0::linker(),
155 )
156 .await
157 .context("failed to instantiate wasm extension")?;
158 Ok(Self::V0_1_0(extension))
159 } else if version >= since_v0_0_6::MIN_VERSION {
160 let extension = since_v0_0_6::Extension::instantiate_async(
161 store,
162 component,
163 since_v0_0_6::linker(),
164 )
165 .await
166 .context("failed to instantiate wasm extension")?;
167 Ok(Self::V0_0_6(extension))
168 } else if version >= since_v0_0_4::MIN_VERSION {
169 let extension = since_v0_0_4::Extension::instantiate_async(
170 store,
171 component,
172 since_v0_0_4::linker(),
173 )
174 .await
175 .context("failed to instantiate wasm extension")?;
176 Ok(Self::V0_0_4(extension))
177 } else {
178 let extension = since_v0_0_1::Extension::instantiate_async(
179 store,
180 component,
181 since_v0_0_1::linker(),
182 )
183 .await
184 .context("failed to instantiate wasm extension")?;
185 Ok(Self::V0_0_1(extension))
186 }
187 }
188
189 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
190 match self {
191 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
192 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
193 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
194 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
195 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
196 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
197 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
198 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
199 }
200 }
201
202 pub async fn call_language_server_command(
203 &self,
204 store: &mut Store<WasmState>,
205 language_server_id: &LanguageServerName,
206 language_name: &LanguageName,
207 resource: Resource<Arc<dyn WorktreeDelegate>>,
208 ) -> Result<Result<Command, String>> {
209 match self {
210 Extension::V0_5_0(ext) => {
211 ext.call_language_server_command(store, &language_server_id.0, resource)
212 .await
213 }
214 Extension::V0_4_0(ext) => {
215 ext.call_language_server_command(store, &language_server_id.0, resource)
216 .await
217 }
218 Extension::V0_3_0(ext) => {
219 ext.call_language_server_command(store, &language_server_id.0, resource)
220 .await
221 }
222 Extension::V0_2_0(ext) => Ok(ext
223 .call_language_server_command(store, &language_server_id.0, resource)
224 .await?
225 .map(|command| command.into())),
226 Extension::V0_1_0(ext) => Ok(ext
227 .call_language_server_command(store, &language_server_id.0, resource)
228 .await?
229 .map(|command| command.into())),
230 Extension::V0_0_6(ext) => Ok(ext
231 .call_language_server_command(store, &language_server_id.0, resource)
232 .await?
233 .map(|command| command.into())),
234 Extension::V0_0_4(ext) => Ok(ext
235 .call_language_server_command(
236 store,
237 &LanguageServerConfig {
238 name: language_server_id.0.to_string(),
239 language_name: language_name.to_string(),
240 },
241 resource,
242 )
243 .await?
244 .map(|command| command.into())),
245 Extension::V0_0_1(ext) => Ok(ext
246 .call_language_server_command(
247 store,
248 &LanguageServerConfig {
249 name: language_server_id.0.to_string(),
250 language_name: language_name.to_string(),
251 }
252 .into(),
253 resource,
254 )
255 .await?
256 .map(|command| command.into())),
257 }
258 }
259
260 pub async fn call_language_server_initialization_options(
261 &self,
262 store: &mut Store<WasmState>,
263 language_server_id: &LanguageServerName,
264 language_name: &LanguageName,
265 resource: Resource<Arc<dyn WorktreeDelegate>>,
266 ) -> Result<Result<Option<String>, String>> {
267 match self {
268 Extension::V0_5_0(ext) => {
269 ext.call_language_server_initialization_options(
270 store,
271 &language_server_id.0,
272 resource,
273 )
274 .await
275 }
276 Extension::V0_4_0(ext) => {
277 ext.call_language_server_initialization_options(
278 store,
279 &language_server_id.0,
280 resource,
281 )
282 .await
283 }
284 Extension::V0_3_0(ext) => {
285 ext.call_language_server_initialization_options(
286 store,
287 &language_server_id.0,
288 resource,
289 )
290 .await
291 }
292 Extension::V0_2_0(ext) => {
293 ext.call_language_server_initialization_options(
294 store,
295 &language_server_id.0,
296 resource,
297 )
298 .await
299 }
300 Extension::V0_1_0(ext) => {
301 ext.call_language_server_initialization_options(
302 store,
303 &language_server_id.0,
304 resource,
305 )
306 .await
307 }
308 Extension::V0_0_6(ext) => {
309 ext.call_language_server_initialization_options(
310 store,
311 &language_server_id.0,
312 resource,
313 )
314 .await
315 }
316 Extension::V0_0_4(ext) => {
317 ext.call_language_server_initialization_options(
318 store,
319 &LanguageServerConfig {
320 name: language_server_id.0.to_string(),
321 language_name: language_name.to_string(),
322 },
323 resource,
324 )
325 .await
326 }
327 Extension::V0_0_1(ext) => {
328 ext.call_language_server_initialization_options(
329 store,
330 &LanguageServerConfig {
331 name: language_server_id.0.to_string(),
332 language_name: language_name.to_string(),
333 }
334 .into(),
335 resource,
336 )
337 .await
338 }
339 }
340 }
341
342 pub async fn call_language_server_workspace_configuration(
343 &self,
344 store: &mut Store<WasmState>,
345 language_server_id: &LanguageServerName,
346 resource: Resource<Arc<dyn WorktreeDelegate>>,
347 ) -> Result<Result<Option<String>, String>> {
348 match self {
349 Extension::V0_5_0(ext) => {
350 ext.call_language_server_workspace_configuration(
351 store,
352 &language_server_id.0,
353 resource,
354 )
355 .await
356 }
357 Extension::V0_4_0(ext) => {
358 ext.call_language_server_workspace_configuration(
359 store,
360 &language_server_id.0,
361 resource,
362 )
363 .await
364 }
365 Extension::V0_3_0(ext) => {
366 ext.call_language_server_workspace_configuration(
367 store,
368 &language_server_id.0,
369 resource,
370 )
371 .await
372 }
373 Extension::V0_2_0(ext) => {
374 ext.call_language_server_workspace_configuration(
375 store,
376 &language_server_id.0,
377 resource,
378 )
379 .await
380 }
381 Extension::V0_1_0(ext) => {
382 ext.call_language_server_workspace_configuration(
383 store,
384 &language_server_id.0,
385 resource,
386 )
387 .await
388 }
389 Extension::V0_0_6(ext) => {
390 ext.call_language_server_workspace_configuration(
391 store,
392 &language_server_id.0,
393 resource,
394 )
395 .await
396 }
397 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
398 }
399 }
400
401 pub async fn call_language_server_additional_initialization_options(
402 &self,
403 store: &mut Store<WasmState>,
404 language_server_id: &LanguageServerName,
405 target_language_server_id: &LanguageServerName,
406 resource: Resource<Arc<dyn WorktreeDelegate>>,
407 ) -> Result<Result<Option<String>, String>> {
408 match self {
409 Extension::V0_5_0(ext) => {
410 ext.call_language_server_additional_initialization_options(
411 store,
412 &language_server_id.0,
413 &target_language_server_id.0,
414 resource,
415 )
416 .await
417 }
418 Extension::V0_4_0(ext) => {
419 ext.call_language_server_additional_initialization_options(
420 store,
421 &language_server_id.0,
422 &target_language_server_id.0,
423 resource,
424 )
425 .await
426 }
427 Extension::V0_3_0(_)
428 | Extension::V0_2_0(_)
429 | Extension::V0_1_0(_)
430 | Extension::V0_0_6(_)
431 | Extension::V0_0_4(_)
432 | Extension::V0_0_1(_) => Ok(Ok(None)),
433 }
434 }
435
436 pub async fn call_language_server_additional_workspace_configuration(
437 &self,
438 store: &mut Store<WasmState>,
439 language_server_id: &LanguageServerName,
440 target_language_server_id: &LanguageServerName,
441 resource: Resource<Arc<dyn WorktreeDelegate>>,
442 ) -> Result<Result<Option<String>, String>> {
443 match self {
444 Extension::V0_5_0(ext) => {
445 ext.call_language_server_additional_workspace_configuration(
446 store,
447 &language_server_id.0,
448 &target_language_server_id.0,
449 resource,
450 )
451 .await
452 }
453 Extension::V0_4_0(ext) => {
454 ext.call_language_server_additional_workspace_configuration(
455 store,
456 &language_server_id.0,
457 &target_language_server_id.0,
458 resource,
459 )
460 .await
461 }
462 Extension::V0_3_0(_)
463 | Extension::V0_2_0(_)
464 | Extension::V0_1_0(_)
465 | Extension::V0_0_6(_)
466 | Extension::V0_0_4(_)
467 | Extension::V0_0_1(_) => Ok(Ok(None)),
468 }
469 }
470
471 pub async fn call_labels_for_completions(
472 &self,
473 store: &mut Store<WasmState>,
474 language_server_id: &LanguageServerName,
475 completions: Vec<latest::Completion>,
476 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
477 match self {
478 Extension::V0_5_0(ext) => {
479 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
480 .await
481 }
482 Extension::V0_4_0(ext) => Ok(ext
483 .call_labels_for_completions(
484 store,
485 &language_server_id.0,
486 &completions.into_iter().collect::<Vec<_>>(),
487 )
488 .await?
489 .map(|labels| {
490 labels
491 .into_iter()
492 .map(|label| label.map(Into::into))
493 .collect()
494 })),
495 Extension::V0_3_0(ext) => Ok(ext
496 .call_labels_for_completions(
497 store,
498 &language_server_id.0,
499 &completions.into_iter().collect::<Vec<_>>(),
500 )
501 .await?
502 .map(|labels| {
503 labels
504 .into_iter()
505 .map(|label| label.map(Into::into))
506 .collect()
507 })),
508 Extension::V0_2_0(ext) => Ok(ext
509 .call_labels_for_completions(
510 store,
511 &language_server_id.0,
512 &completions.into_iter().collect::<Vec<_>>(),
513 )
514 .await?
515 .map(|labels| {
516 labels
517 .into_iter()
518 .map(|label| label.map(Into::into))
519 .collect()
520 })),
521 Extension::V0_1_0(ext) => Ok(ext
522 .call_labels_for_completions(
523 store,
524 &language_server_id.0,
525 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
526 )
527 .await?
528 .map(|labels| {
529 labels
530 .into_iter()
531 .map(|label| label.map(Into::into))
532 .collect()
533 })),
534 Extension::V0_0_6(ext) => Ok(ext
535 .call_labels_for_completions(
536 store,
537 &language_server_id.0,
538 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
539 )
540 .await?
541 .map(|labels| {
542 labels
543 .into_iter()
544 .map(|label| label.map(Into::into))
545 .collect()
546 })),
547 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
548 }
549 }
550
551 pub async fn call_labels_for_symbols(
552 &self,
553 store: &mut Store<WasmState>,
554 language_server_id: &LanguageServerName,
555 symbols: Vec<latest::Symbol>,
556 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
557 match self {
558 Extension::V0_5_0(ext) => {
559 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
560 .await
561 }
562 Extension::V0_4_0(ext) => Ok(ext
563 .call_labels_for_symbols(
564 store,
565 &language_server_id.0,
566 &symbols.into_iter().collect::<Vec<_>>(),
567 )
568 .await?
569 .map(|labels| {
570 labels
571 .into_iter()
572 .map(|label| label.map(Into::into))
573 .collect()
574 })),
575 Extension::V0_3_0(ext) => Ok(ext
576 .call_labels_for_symbols(
577 store,
578 &language_server_id.0,
579 &symbols.into_iter().collect::<Vec<_>>(),
580 )
581 .await?
582 .map(|labels| {
583 labels
584 .into_iter()
585 .map(|label| label.map(Into::into))
586 .collect()
587 })),
588 Extension::V0_2_0(ext) => Ok(ext
589 .call_labels_for_symbols(
590 store,
591 &language_server_id.0,
592 &symbols.into_iter().collect::<Vec<_>>(),
593 )
594 .await?
595 .map(|labels| {
596 labels
597 .into_iter()
598 .map(|label| label.map(Into::into))
599 .collect()
600 })),
601 Extension::V0_1_0(ext) => Ok(ext
602 .call_labels_for_symbols(
603 store,
604 &language_server_id.0,
605 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
606 )
607 .await?
608 .map(|labels| {
609 labels
610 .into_iter()
611 .map(|label| label.map(Into::into))
612 .collect()
613 })),
614 Extension::V0_0_6(ext) => Ok(ext
615 .call_labels_for_symbols(
616 store,
617 &language_server_id.0,
618 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
619 )
620 .await?
621 .map(|labels| {
622 labels
623 .into_iter()
624 .map(|label| label.map(Into::into))
625 .collect()
626 })),
627 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
628 }
629 }
630
631 pub async fn call_complete_slash_command_argument(
632 &self,
633 store: &mut Store<WasmState>,
634 command: &SlashCommand,
635 arguments: &[String],
636 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
637 match self {
638 Extension::V0_5_0(ext) => {
639 ext.call_complete_slash_command_argument(store, command, arguments)
640 .await
641 }
642 Extension::V0_4_0(ext) => {
643 ext.call_complete_slash_command_argument(store, command, arguments)
644 .await
645 }
646 Extension::V0_3_0(ext) => {
647 ext.call_complete_slash_command_argument(store, command, arguments)
648 .await
649 }
650 Extension::V0_2_0(ext) => {
651 ext.call_complete_slash_command_argument(store, command, arguments)
652 .await
653 }
654 Extension::V0_1_0(ext) => {
655 ext.call_complete_slash_command_argument(store, command, arguments)
656 .await
657 }
658 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
659 Ok(Ok(Vec::new()))
660 }
661 }
662 }
663
664 pub async fn call_run_slash_command(
665 &self,
666 store: &mut Store<WasmState>,
667 command: &SlashCommand,
668 arguments: &[String],
669 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
670 ) -> Result<Result<SlashCommandOutput, String>> {
671 match self {
672 Extension::V0_5_0(ext) => {
673 ext.call_run_slash_command(store, command, arguments, resource)
674 .await
675 }
676 Extension::V0_4_0(ext) => {
677 ext.call_run_slash_command(store, command, arguments, resource)
678 .await
679 }
680 Extension::V0_3_0(ext) => {
681 ext.call_run_slash_command(store, command, arguments, resource)
682 .await
683 }
684 Extension::V0_2_0(ext) => {
685 ext.call_run_slash_command(store, command, arguments, resource)
686 .await
687 }
688 Extension::V0_1_0(ext) => {
689 ext.call_run_slash_command(store, command, arguments, resource)
690 .await
691 }
692 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
693 Err(anyhow!("`run_slash_command` not available prior to v0.1.0"))
694 }
695 }
696 }
697
698 pub async fn call_context_server_command(
699 &self,
700 store: &mut Store<WasmState>,
701 context_server_id: Arc<str>,
702 project: Resource<ExtensionProject>,
703 ) -> Result<Result<Command, String>> {
704 match self {
705 Extension::V0_5_0(ext) => {
706 ext.call_context_server_command(store, &context_server_id, project)
707 .await
708 }
709 Extension::V0_4_0(ext) => {
710 ext.call_context_server_command(store, &context_server_id, project)
711 .await
712 }
713 Extension::V0_3_0(ext) => {
714 ext.call_context_server_command(store, &context_server_id, project)
715 .await
716 }
717 Extension::V0_2_0(ext) => Ok(ext
718 .call_context_server_command(store, &context_server_id, project)
719 .await?
720 .map(Into::into)),
721 Extension::V0_0_1(_)
722 | Extension::V0_0_4(_)
723 | Extension::V0_0_6(_)
724 | Extension::V0_1_0(_) => Err(anyhow!(
725 "`context_server_command` not available prior to v0.2.0"
726 )),
727 }
728 }
729
730 pub async fn call_context_server_configuration(
731 &self,
732 store: &mut Store<WasmState>,
733 context_server_id: Arc<str>,
734 project: Resource<ExtensionProject>,
735 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
736 match self {
737 Extension::V0_5_0(ext) => {
738 ext.call_context_server_configuration(store, &context_server_id, project)
739 .await
740 }
741 Extension::V0_0_1(_)
742 | Extension::V0_0_4(_)
743 | Extension::V0_0_6(_)
744 | Extension::V0_1_0(_)
745 | Extension::V0_2_0(_)
746 | Extension::V0_3_0(_)
747 | Extension::V0_4_0(_) => Err(anyhow!(
748 "`context_server_configuration` not available prior to v0.5.0"
749 )),
750 }
751 }
752
753 pub async fn call_suggest_docs_packages(
754 &self,
755 store: &mut Store<WasmState>,
756 provider: &str,
757 ) -> Result<Result<Vec<String>, String>> {
758 match self {
759 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
760 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
761 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
762 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
763 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
764 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => Err(anyhow!(
765 "`suggest_docs_packages` not available prior to v0.1.0"
766 )),
767 }
768 }
769
770 pub async fn call_index_docs(
771 &self,
772 store: &mut Store<WasmState>,
773 provider: &str,
774 package_name: &str,
775 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
776 ) -> Result<Result<(), String>> {
777 match self {
778 Extension::V0_5_0(ext) => {
779 ext.call_index_docs(store, provider, package_name, kv_store)
780 .await
781 }
782 Extension::V0_4_0(ext) => {
783 ext.call_index_docs(store, provider, package_name, kv_store)
784 .await
785 }
786 Extension::V0_3_0(ext) => {
787 ext.call_index_docs(store, provider, package_name, kv_store)
788 .await
789 }
790 Extension::V0_2_0(ext) => {
791 ext.call_index_docs(store, provider, package_name, kv_store)
792 .await
793 }
794 Extension::V0_1_0(ext) => {
795 ext.call_index_docs(store, provider, package_name, kv_store)
796 .await
797 }
798 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
799 Err(anyhow!("`index_docs` not available prior to v0.1.0"))
800 }
801 }
802 }
803}
804
805trait ToWasmtimeResult<T> {
806 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
807}
808
809impl<T> ToWasmtimeResult<T> for Result<T> {
810 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
811 Ok(self.map_err(|error| error.to_string()))
812 }
813}