1use std::cell::OnceCell;
2use std::cell::{Cell, Ref, RefCell};
3use std::cmp::Ordering;
4use std::collections::{BTreeMap, BTreeSet};
5use std::fmt;
6use std::hash;
7use std::path::{Path, PathBuf};
8use std::rc::Rc;
9use std::time::{Duration, Instant};
10
11use crate::util::data_structures::{HashMap, HashSet};
12use anyhow::Context as _;
13use cargo_util_schemas::manifest::{FeatureDefinition, Hints, RustVersion};
14use futures::FutureExt;
15use futures::TryStreamExt;
16use futures::stream::FuturesUnordered;
17use http::Request;
18use semver::Version;
19use serde::Serialize;
20use tracing::debug;
21
22use crate::compiler::{CompileKind, RustcTargetData};
23use crate::resolver::features::ForceAllTargets;
24use crate::resolver::{HasDevUnits, Resolve};
25use crate::sources::source::{MaybePackage, SourceMap};
26use crate::util::HumanBytes;
27use crate::util::cache_lock::{CacheLock, CacheLockMode};
28use crate::util::errors::{CargoResult, HttpNotSuccessful};
29use crate::util::interning::InternedString;
30use crate::util::network::retry::{Retry, RetryResult};
31use crate::util::{self, GlobalContext, Progress, ProgressStyle, internal};
32use crate::workspace::dependency::DepKind;
33use crate::workspace::{
34 CliUnstable, Dependency, Feature, Features, Manifest, PackageId, PackageIdSpec,
35 SerializedDependency, SourceId, Target,
36};
37use crate::workspace::{Summary, Workspace};
38
39#[derive(Clone)]
43pub struct Package {
44 inner: Rc<PackageInner>,
45}
46
47#[derive(Clone)]
48struct PackageInner {
50 manifest: Manifest,
52 manifest_path: PathBuf,
54}
55
56impl Ord for Package {
57 fn cmp(&self, other: &Package) -> Ordering {
58 self.package_id().cmp(&other.package_id())
59 }
60}
61
62impl PartialOrd for Package {
63 fn partial_cmp(&self, other: &Package) -> Option<Ordering> {
64 Some(self.cmp(other))
65 }
66}
67
68#[derive(Serialize)]
70pub struct SerializedPackage {
71 name: InternedString,
72 version: Version,
73 id: PackageIdSpec,
74 license: Option<String>,
75 license_file: Option<String>,
76 description: Option<String>,
77 source: SourceId,
78 dependencies: Vec<SerializedDependency>,
79 targets: Vec<Target>,
80 features: BTreeMap<InternedString, Vec<InternedString>>,
81 #[serde(skip_serializing_if = "Option::is_none")]
82 features_v2: Option<BTreeMap<InternedString, SerializedFeature>>,
83 manifest_path: PathBuf,
84 metadata: Option<toml::Value>,
85 publish: Option<Vec<String>>,
86 authors: Vec<String>,
87 categories: Vec<String>,
88 keywords: Vec<String>,
89 readme: Option<String>,
90 repository: Option<String>,
91 homepage: Option<String>,
92 documentation: Option<String>,
93 edition: String,
94 links: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 metabuild: Option<Vec<String>>,
97 default_run: Option<String>,
98 rust_version: Option<RustVersion>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 hints: Option<Hints>,
101}
102
103#[derive(Serialize)]
104struct SerializedFeature {
105 enables: Vec<InternedString>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 doc: Option<String>,
108}
109
110impl Package {
111 pub fn new(manifest: Manifest, manifest_path: &Path) -> Package {
113 Package {
114 inner: Rc::new(PackageInner {
115 manifest,
116 manifest_path: manifest_path.to_path_buf(),
117 }),
118 }
119 }
120
121 pub fn dependencies(&self) -> &[Dependency] {
123 self.manifest().dependencies()
124 }
125 pub fn manifest(&self) -> &Manifest {
127 &self.inner.manifest
128 }
129 pub fn manifest_mut(&mut self) -> &mut Manifest {
131 &mut Rc::make_mut(&mut self.inner).manifest
132 }
133 pub fn manifest_path(&self) -> &Path {
135 &self.inner.manifest_path
136 }
137 pub fn name(&self) -> InternedString {
139 self.package_id().name()
140 }
141 pub fn package_id(&self) -> PackageId {
143 self.manifest().package_id()
144 }
145 pub fn root(&self) -> &Path {
147 self.manifest_path().parent().unwrap()
148 }
149 pub fn summary(&self) -> &Summary {
151 self.manifest().summary()
152 }
153 pub fn targets(&self) -> &[Target] {
155 self.manifest().targets()
156 }
157 pub fn library(&self) -> Option<&Target> {
159 self.targets().iter().find(|t| t.is_lib())
160 }
161 pub fn version(&self) -> &Version {
163 self.package_id().version()
164 }
165 pub fn authors(&self) -> &Vec<String> {
167 &self.manifest().metadata().authors
168 }
169
170 pub fn publish(&self) -> &Option<Vec<String>> {
174 self.manifest().publish()
175 }
176 pub fn proc_macro(&self) -> bool {
178 self.targets().iter().any(|target| target.proc_macro())
179 }
180 pub fn rust_version(&self) -> Option<&RustVersion> {
182 self.manifest().rust_version()
183 }
184
185 pub fn hints(&self) -> Option<&Hints> {
187 self.manifest().hints()
188 }
189
190 pub fn has_custom_build(&self) -> bool {
192 self.targets().iter().any(|t| t.is_custom_build())
193 }
194
195 pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Package {
196 Package {
197 inner: Rc::new(PackageInner {
198 manifest: self.manifest().clone().map_source(to_replace, replace_with),
199 manifest_path: self.manifest_path().to_owned(),
200 }),
201 }
202 }
203
204 pub fn serialized(
205 &self,
206 unstable_flags: &CliUnstable,
207 cargo_features: &Features,
208 ) -> SerializedPackage {
209 let summary = self.manifest().summary();
210 let package_id = summary.package_id();
211 let manmeta = self.manifest().metadata();
212 let targets: Vec<Target> = self
216 .manifest()
217 .targets()
218 .iter()
219 .filter(|t| t.src_path().is_path())
220 .cloned()
221 .collect();
222 let manifest_features = self.manifest().normalized_toml().features();
223 let mut crate_features = BTreeMap::new();
224 let mut features_v2 = cargo_features
225 .is_enabled(Feature::feature_metadata())
226 .then(BTreeMap::new);
227 for (k, v) in summary.features() {
228 let enables: Vec<InternedString> = v.iter().map(|fv| fv.to_string().into()).collect();
229 if let Some(features_v2) = &mut features_v2 {
230 let doc = manifest_features
231 .and_then(|mf| mf.get(k.as_str()))
232 .and_then(|feat_def| match feat_def {
233 FeatureDefinition::Metadata(meta) => meta.doc.clone(),
234 FeatureDefinition::Array(_) => None,
235 });
236 features_v2.insert(
237 *k,
238 SerializedFeature {
239 enables: enables.clone(),
240 doc,
241 },
242 );
243 }
244 crate_features.insert(*k, enables);
245 }
246
247 SerializedPackage {
248 name: package_id.name(),
249 version: package_id.version().clone(),
250 id: package_id.to_spec(),
251 license: manmeta.license.clone(),
252 license_file: manmeta.license_file.clone(),
253 description: manmeta.description.clone(),
254 source: summary.source_id(),
255 dependencies: summary
256 .dependencies()
257 .iter()
258 .map(|dep| dep.serialized(unstable_flags, cargo_features))
259 .collect(),
260 targets,
261 features: crate_features,
262 features_v2,
263 manifest_path: self.manifest_path().to_path_buf(),
264 metadata: self.manifest().custom_metadata().cloned(),
265 authors: manmeta.authors.clone(),
266 categories: manmeta.categories.clone(),
267 keywords: manmeta.keywords.clone(),
268 readme: manmeta.readme.clone(),
269 repository: manmeta.repository.clone(),
270 homepage: manmeta.homepage.clone(),
271 documentation: manmeta.documentation.clone(),
272 edition: self.manifest().edition().to_string(),
273 links: self.manifest().links().map(|s| s.to_owned()),
274 metabuild: self.manifest().metabuild().cloned(),
275 publish: self.publish().as_ref().cloned(),
276 default_run: self.manifest().default_run().map(|s| s.to_owned()),
277 rust_version: self.rust_version().cloned(),
278 hints: self.hints().cloned(),
279 }
280 }
281}
282
283impl fmt::Display for Package {
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 write!(f, "{}", self.summary().package_id())
286 }
287}
288
289impl fmt::Debug for Package {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 f.debug_struct("Package")
292 .field("id", &self.summary().package_id())
293 .field("..", &"..")
294 .finish()
295 }
296}
297
298impl PartialEq for Package {
299 fn eq(&self, other: &Package) -> bool {
300 self.package_id() == other.package_id()
301 }
302}
303
304impl Eq for Package {}
305
306impl hash::Hash for Package {
307 fn hash<H: hash::Hasher>(&self, into: &mut H) {
308 self.package_id().hash(into)
309 }
310}
311
312pub struct PackageSet<'gctx> {
317 packages: HashMap<PackageId, OnceCell<Package>>,
318 sources: RefCell<SourceMap<'gctx>>,
319 gctx: &'gctx GlobalContext,
320}
321
322pub struct Downloads<'a, 'gctx> {
324 set: &'a PackageSet<'gctx>,
325 progress: RefCell<Progress<'gctx>>,
327 first: Cell<bool>,
329 largest: Cell<Option<(u64, InternedString)>>,
331 downloads_finished: Cell<u64>,
333 downloaded_bytes: Cell<u64>,
335 pending: Cell<u64>,
337 start: Instant,
339 _lock: CacheLock<'gctx>,
341}
342
343impl<'a, 'gctx> Downloads<'a, 'gctx> {
344 pub async fn download(
345 set: &'a PackageSet<'gctx>,
346 ids: impl IntoIterator<Item = PackageId>,
347 ) -> CargoResult<Vec<&'a Package>> {
348 let progress = RefCell::new(Progress::with_style(
349 "Downloading",
350 ProgressStyle::Ratio,
351 set.gctx,
352 ));
353 let dl = Downloads {
354 set,
355 progress,
356 first: Cell::new(true),
357 largest: Cell::new(None),
358 downloads_finished: Cell::new(0),
359 downloaded_bytes: Cell::new(0),
360 pending: Cell::new(0),
361 start: Instant::now(),
362 _lock: set
363 .gctx
364 .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?,
365 };
366 dl.run(ids).await
367 }
368
369 async fn run(&self, ids: impl IntoIterator<Item = PackageId>) -> CargoResult<Vec<&'a Package>> {
370 let mut futures: FuturesUnordered<_> =
371 ids.into_iter().map(|id| self.get_package(id)).collect();
372
373 let mut out = Vec::new();
377 loop {
378 futures::select! {
379 pkg = futures.try_next() => {
380 match pkg? {
381 Some(pkg) => out.push(pkg),
382 None => break,
383 }
384 },
385 _ = futures_timer::Delay::new(Duration::from_millis(200)).fuse() => {
386 self.tick(WhyTick::DownloadUpdate)?;
387 },
388 }
389 }
390 self.print_summary()?;
391 self.set
392 .gctx
393 .deferred_global_last_use()?
394 .save_no_error(self.set.gctx);
395 Ok(out)
396 }
397
398 async fn get_package(&self, id: PackageId) -> CargoResult<&'a Package> {
401 let slot = self
402 .set
403 .packages
404 .get(&id)
405 .ok_or_else(|| internal(format!("couldn't find `{}` in package set", id)))?;
406 if let Some(pkg) = slot.get() {
407 return CargoResult::Ok(pkg);
408 }
409 let source = self
410 .set
411 .sources
412 .borrow()
413 .get(id.source_id())
414 .ok_or_else(|| internal(format!("couldn't find source for `{}`", id)))?
415 .clone();
416 let pkg = match source
417 .download(id)
418 .await
419 .context("unable to get packages from source")
420 .with_context(|| format!("failed to download `{}`", id))?
421 {
422 MaybePackage::Ready(package) => CargoResult::Ok(package),
423 MaybePackage::Download {
424 url,
425 descriptor,
426 authorization,
427 } => {
428 let mut r = Retry::new(self.set.gctx)?;
429 let contents = loop {
430 self.tick(WhyTick::DownloadStarted)?;
431 self.pending.update(|v| v + 1);
432 let response = self
433 .fetch(&url, authorization.as_deref(), &descriptor, &id)
434 .await;
435 self.pending.update(|v| v - 1);
436 match r.r#try(|| response) {
437 RetryResult::Success(result) => break result,
438 RetryResult::Err(error) => {
439 debug!(target: "network", "final failure for {url}");
440 return Err(error);
441 }
442 RetryResult::Retry(delay_ms) => {
443 debug!(target: "network", "download retry {url} for {delay_ms}ms");
444 futures_timer::Delay::new(Duration::from_millis(delay_ms)).await;
445 }
446 }
447 };
448 self.downloads_finished.update(|v| v + 1);
449 self.downloaded_bytes.update(|v| v + contents.len() as u64);
450
451 let kib_400 = 1024 * 400;
457 if contents.len() < kib_400 {
458 self.tick(WhyTick::DownloadFinished)?;
459 } else {
460 self.tick(WhyTick::Extracting(&id.name()))?;
461 }
462
463 Ok(source.finish_download(id, contents).await?)
464 }
465 }?;
466
467 assert!(slot.set(pkg).is_ok());
468 Ok(slot.get().unwrap())
469 }
470
471 async fn fetch(
473 &self,
474 url: &str,
475 authorization: Option<&str>,
476 descriptor: &str,
477 id: &PackageId,
478 ) -> CargoResult<Vec<u8>> {
479 let mut request = if let Some(file_url) = url.strip_prefix("file:///") {
482 Request::get(format!("file://localhost/{file_url}"))
483 } else {
484 Request::get(url)
485 };
486 if let Some(authorization) = authorization {
487 request = request.header(http::header::AUTHORIZATION, authorization);
488 }
489 let client = self
490 .set
491 .gctx
492 .http_async()
493 .with_context(|| format!("failed to download `{}`", id))?;
494
495 if self.first.get() && !self.progress.borrow().is_enabled() {
499 self.first.set(false);
500 self.set.gctx.shell().status("Downloading", "crates ...")?;
501 }
502
503 let response = client
504 .request(request.body(Vec::new())?)
505 .await
506 .with_context(|| format!("failed to download from `{}`", url))?;
507
508 let previous_largest = self.largest.get().map(|(v, _)| v).unwrap_or_default();
509 let len = response.body().len() as u64;
510 if len > previous_largest {
511 self.largest.set(Some((len, id.name())));
512 }
513
514 if response.status() != http::StatusCode::OK {
515 return Err(HttpNotSuccessful::new_from_response(response, &url))
516 .with_context(|| format!("failed to download from `{}`", url))?;
517 }
518 self.set.gctx.shell().status("Downloaded", descriptor)?;
523
524 Ok(response.into_body())
525 }
526
527 fn tick(&self, why: WhyTick<'_>) -> CargoResult<()> {
528 let mut progress = self.progress.borrow_mut();
529
530 if let WhyTick::DownloadUpdate = why {
531 if !progress.update_allowed() {
532 return Ok(());
533 }
534 }
535
536 let pending = self.pending.get();
537 let mut msg = if pending == 1 {
538 format!("{} crate", pending)
539 } else {
540 format!("{} crates", pending)
541 };
542 match why {
543 WhyTick::Extracting(krate) => {
544 msg.push_str(&format!(", extracting {} ...", krate));
545 }
546 _ => {
547 let remaining = self
548 .set
549 .gctx
550 .http_async()
551 .map(|c| c.bytes_pending())
552 .unwrap_or_default();
553 if remaining > 0 {
554 msg.push_str(&format!(
555 ", remaining bytes: {:.1}",
556 HumanBytes(remaining as u64)
557 ));
558 }
559 }
560 }
561 progress.print_now(&msg)
562 }
563
564 fn print_summary(&self) -> CargoResult<()> {
565 if !self.progress.borrow().is_enabled() {
568 return Ok(());
569 }
570 let downloads_finished = self.downloads_finished.get();
571
572 if downloads_finished == 0 {
574 return Ok(());
575 }
576
577 let crate_string = if downloads_finished == 1 {
579 "crate"
580 } else {
581 "crates"
582 };
583 let mut status = format!(
584 "{downloads_finished} {crate_string} ({:.1}) in {}",
585 HumanBytes(self.downloaded_bytes.get()),
586 util::elapsed(self.start.elapsed())
587 );
588 if let Some(largest) = self.largest.get() {
592 let mib_1 = 1024 * 1024;
593 if largest.0 > mib_1 && downloads_finished > 1 {
594 status.push_str(&format!(
595 " (largest was `{}` at {:.1})",
596 largest.1,
597 HumanBytes(largest.0),
598 ));
599 }
600 }
601
602 self.progress.borrow_mut().clear();
604 self.set.gctx.shell().status("Downloaded", status)?;
605 Ok(())
606 }
607}
608
609impl<'gctx> PackageSet<'gctx> {
610 pub fn new(
611 package_ids: &[PackageId],
612 sources: SourceMap<'gctx>,
613 gctx: &'gctx GlobalContext,
614 ) -> CargoResult<PackageSet<'gctx>> {
615 gctx.http_config()?;
616
617 Ok(PackageSet {
618 packages: package_ids
619 .iter()
620 .map(|&id| (id, OnceCell::new()))
621 .collect(),
622 sources: RefCell::new(sources),
623 gctx,
624 })
625 }
626
627 pub fn package_ids(&self) -> impl Iterator<Item = PackageId> + '_ {
628 self.packages.keys().cloned()
629 }
630
631 pub fn packages(&self) -> impl Iterator<Item = &Package> {
632 self.packages.values().filter_map(|p| p.get())
633 }
634
635 pub fn get_one(&self, id: PackageId) -> CargoResult<&Package> {
636 if let Some(pkg) = self.packages.get(&id).and_then(|slot| slot.get()) {
637 return Ok(pkg);
638 }
639 Ok(self.get_many(Some(id))?.remove(0))
640 }
641
642 pub fn get_many(&self, ids: impl IntoIterator<Item = PackageId>) -> CargoResult<Vec<&Package>> {
643 return crate::util::block_on(Downloads::download(self, ids));
644 }
645
646 #[tracing::instrument(skip_all)]
648 pub fn download_accessible(
649 &self,
650 resolve: &Resolve,
651 root_ids: &[PackageId],
652 has_dev_units: HasDevUnits,
653 requested_kinds: &[CompileKind],
654 target_data: &RustcTargetData<'gctx>,
655 force_all_targets: ForceAllTargets,
656 ) -> CargoResult<()> {
657 fn collect_used_deps(
658 used: &mut BTreeSet<(PackageId, CompileKind)>,
659 resolve: &Resolve,
660 pkg_id: PackageId,
661 has_dev_units: HasDevUnits,
662 requested_kind: CompileKind,
663 target_data: &RustcTargetData<'_>,
664 force_all_targets: ForceAllTargets,
665 ) -> CargoResult<()> {
666 if !used.insert((pkg_id, requested_kind)) {
667 return Ok(());
668 }
669 let requested_kinds = &[requested_kind];
670 let filtered_deps = PackageSet::filter_deps(
671 pkg_id,
672 resolve,
673 has_dev_units,
674 requested_kinds,
675 target_data,
676 force_all_targets,
677 );
678 for (pkg_id, deps) in filtered_deps {
679 collect_used_deps(
680 used,
681 resolve,
682 pkg_id,
683 has_dev_units,
684 requested_kind,
685 target_data,
686 force_all_targets,
687 )?;
688 let artifact_kinds = deps.iter().filter_map(|dep| {
689 Some(
690 dep.artifact()?
691 .target()?
692 .to_resolved_compile_kind(*requested_kinds.iter().next().unwrap()),
693 )
694 });
695 for artifact_kind in artifact_kinds {
696 collect_used_deps(
697 used,
698 resolve,
699 pkg_id,
700 has_dev_units,
701 artifact_kind,
702 target_data,
703 force_all_targets,
704 )?;
705 }
706 }
707 Ok(())
708 }
709
710 let mut to_download = BTreeSet::new();
714
715 for id in root_ids {
716 for requested_kind in requested_kinds {
717 collect_used_deps(
718 &mut to_download,
719 resolve,
720 *id,
721 has_dev_units,
722 *requested_kind,
723 target_data,
724 force_all_targets,
725 )?;
726 }
727 }
728 let to_download = to_download
729 .into_iter()
730 .map(|(p, _)| p)
731 .collect::<BTreeSet<_>>();
732 self.get_many(to_download.into_iter())?;
733 Ok(())
734 }
735
736 pub(crate) fn warn_no_lib_packages_and_artifact_libs_overlapping_deps(
739 &self,
740 ws: &Workspace<'gctx>,
741 resolve: &Resolve,
742 root_ids: &[PackageId],
743 has_dev_units: HasDevUnits,
744 requested_kinds: &[CompileKind],
745 target_data: &RustcTargetData<'_>,
746 force_all_targets: ForceAllTargets,
747 ) -> CargoResult<()> {
748 let no_lib_pkgs: BTreeMap<PackageId, Vec<(&Package, &HashSet<Dependency>)>> = root_ids
749 .iter()
750 .map(|&root_id| {
751 let dep_pkgs_to_deps: Vec<_> = PackageSet::filter_deps(
752 root_id,
753 resolve,
754 has_dev_units,
755 requested_kinds,
756 target_data,
757 force_all_targets,
758 )
759 .collect();
760
761 let dep_pkgs_and_deps = dep_pkgs_to_deps
762 .into_iter()
763 .filter(|(_id, deps)| deps.iter().any(|dep| dep.maybe_lib()))
764 .filter_map(|(dep_package_id, deps)| {
765 self.get_one(dep_package_id).ok().and_then(|dep_pkg| {
766 (!dep_pkg.targets().iter().any(|t| t.is_lib())).then(|| (dep_pkg, deps))
767 })
768 })
769 .collect();
770 (root_id, dep_pkgs_and_deps)
771 })
772 .collect();
773
774 for (pkg_id, dep_pkgs) in no_lib_pkgs {
775 for (_dep_pkg_without_lib_target, deps) in dep_pkgs {
776 for dep in deps.iter().filter(|dep| {
777 dep.artifact()
778 .map(|artifact| artifact.is_lib())
779 .unwrap_or(true)
780 }) {
781 ws.gctx().shell().warn(&format!(
782 "{} ignoring invalid dependency `{}` which is missing a lib target",
783 pkg_id,
784 dep.name_in_toml(),
785 ))?;
786 }
787 }
788 }
789 Ok(())
790 }
791
792 pub fn filter_deps<'a>(
793 pkg_id: PackageId,
794 resolve: &'a Resolve,
795 has_dev_units: HasDevUnits,
796 requested_kinds: &'a [CompileKind],
797 target_data: &'a RustcTargetData<'_>,
798 force_all_targets: ForceAllTargets,
799 ) -> impl Iterator<Item = (PackageId, &'a HashSet<Dependency>)> + 'a {
800 resolve
801 .deps(pkg_id)
802 .filter(move |&(_id, deps)| {
803 deps.iter().any(|dep| {
804 if dep.kind() == DepKind::Development && has_dev_units == HasDevUnits::No {
805 return false;
806 }
807 if force_all_targets == ForceAllTargets::No {
808 let activated = requested_kinds
809 .iter()
810 .chain(Some(&CompileKind::Host))
811 .any(|kind| target_data.dep_platform_activated(dep, *kind));
812 if !activated {
813 return false;
814 }
815 }
816 true
817 })
818 })
819 .into_iter()
820 }
821
822 pub fn sources(&self) -> Ref<'_, SourceMap<'gctx>> {
823 self.sources.borrow()
824 }
825
826 pub fn add_set(&mut self, set: PackageSet<'gctx>) {
828 for (pkg_id, p_cell) in set.packages {
829 self.packages.entry(pkg_id).or_insert(p_cell);
830 }
831 let mut sources = self.sources.borrow_mut();
832 let other_sources = set.sources.into_inner();
833 sources.add_source_map(other_sources);
834 }
835}
836
837#[derive(Copy, Clone)]
838enum WhyTick<'a> {
839 DownloadStarted,
840 DownloadUpdate,
841 DownloadFinished,
842 Extracting(&'a str),
843}