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